2017-05-16 22:09:12 +02:00
|
|
|
import neovim
|
|
|
|
import fileinput
|
2017-05-17 21:52:30 +02:00
|
|
|
import pathlib
|
2017-05-16 22:09:12 +02:00
|
|
|
import subprocess
|
2017-05-17 21:52:30 +02:00
|
|
|
import sys
|
|
|
|
import traceback
|
2017-05-16 22:09:12 +02:00
|
|
|
|
|
|
|
|
|
|
|
@neovim.plugin
|
|
|
|
class NeotagsPlugin(object):
|
|
|
|
|
|
|
|
def __init__(self, nvim):
|
|
|
|
self.nvim = nvim
|
2017-05-17 22:55:09 +02:00
|
|
|
# Perhaps debugging settings?
|
2017-05-19 15:39:22 +02:00
|
|
|
# Like autotags, configure regex compared to filename to ignore, e.g.
|
|
|
|
# fugitive buffers, git commits, etc.
|
2017-05-17 22:55:09 +02:00
|
|
|
self.options = {
|
|
|
|
'tags_filename': 'tags',
|
|
|
|
'ctags_cmd': 'ctags',
|
|
|
|
'logging': False,
|
|
|
|
}
|
2017-05-16 22:09:12 +02:00
|
|
|
|
2017-05-17 22:33:16 +02:00
|
|
|
def update_settings(self):
|
2017-05-17 22:55:09 +02:00
|
|
|
for option, default in self.options.items():
|
|
|
|
try:
|
|
|
|
variable = 'neotags_%s' % option
|
|
|
|
self.options[option] = self.nvim.vars[variable]
|
|
|
|
except neovim.api.nvim.NvimError:
|
|
|
|
self.options[option] = default
|
|
|
|
|
2017-05-16 22:37:51 +02:00
|
|
|
# Check whether 'FileWritePost' is necessary
|
|
|
|
@neovim.autocmd('BufWritePost', pattern='*', eval='expand("<afile>:p")')
|
2017-05-16 22:09:12 +02:00
|
|
|
def update_tags_for_file(self, filename):
|
2017-05-17 22:33:16 +02:00
|
|
|
self.update_settings()
|
|
|
|
|
2017-05-17 22:55:09 +02:00
|
|
|
self.debug('Triggered for "%s"' % filename)
|
2017-05-17 21:52:30 +02:00
|
|
|
|
2017-05-16 22:09:12 +02:00
|
|
|
pwd = self.nvim.funcs.execute('pwd').strip()
|
2017-05-17 21:52:30 +02:00
|
|
|
relative_filename = filename.replace(pwd, '').lstrip('\/')
|
2017-05-16 22:09:12 +02:00
|
|
|
|
|
|
|
try:
|
2017-05-17 22:55:09 +02:00
|
|
|
tags_file = self.get_tags_file(filename)
|
|
|
|
except:
|
|
|
|
self.error(
|
|
|
|
'Could not determine tags file to update for "%s"' % (
|
|
|
|
filename
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
|
|
|
try:
|
|
|
|
self.debug('Start updating tags for "%s"' % filename)
|
2017-05-17 21:52:30 +02:00
|
|
|
self.strip_existing_tags(tags_file, relative_filename)
|
|
|
|
self.generate_tags(tags_file, relative_filename)
|
2017-05-17 22:55:09 +02:00
|
|
|
self.debug('Tags updated for "%s"' % filename)
|
2017-05-17 21:52:30 +02:00
|
|
|
except:
|
2017-05-17 22:55:09 +02:00
|
|
|
self.error(
|
2017-05-17 21:52:30 +02:00
|
|
|
'Failed to update tags for "%s", reason: %s' % (
|
|
|
|
filename, traceback.format_exc()
|
|
|
|
)
|
|
|
|
)
|
2017-05-16 22:09:12 +02:00
|
|
|
|
2017-05-17 21:52:30 +02:00
|
|
|
def strip_existing_tags(self, tags_f, filename):
|
2017-05-17 21:18:25 +02:00
|
|
|
with fileinput.input(files=tags_f, inplace=True, backup='.bak') as f:
|
2017-05-16 22:37:51 +02:00
|
|
|
for line in f:
|
2017-05-17 21:52:30 +02:00
|
|
|
if filename not in line:
|
2017-05-16 22:37:51 +02:00
|
|
|
sys.stdout.write(line)
|
2017-05-16 22:09:12 +02:00
|
|
|
|
2017-05-17 21:52:30 +02:00
|
|
|
def generate_tags(self, tags_file, filename):
|
2017-08-07 08:47:58 +02:00
|
|
|
subprocess.call([
|
2017-05-17 22:55:09 +02:00
|
|
|
self.options['ctags_cmd'],
|
2017-05-16 22:09:12 +02:00
|
|
|
'-f',
|
2017-05-17 21:52:30 +02:00
|
|
|
tags_file,
|
2017-05-16 22:09:12 +02:00
|
|
|
'-a',
|
2017-05-17 21:52:30 +02:00
|
|
|
"%s" % filename
|
2017-05-16 22:09:12 +02:00
|
|
|
])
|
|
|
|
|
2017-05-17 21:52:30 +02:00
|
|
|
def get_tags_file(self, filename):
|
|
|
|
path = pathlib.Path(filename)
|
2017-05-17 22:55:09 +02:00
|
|
|
possible_file = path.with_name(self.options['tags_filename'])
|
2017-05-17 21:18:11 +02:00
|
|
|
|
2017-05-17 22:55:09 +02:00
|
|
|
self.debug('Search tags file: "%s"' % possible_file)
|
2017-05-17 22:33:16 +02:00
|
|
|
if possible_file.is_file():
|
|
|
|
return str(possible_file)
|
2017-05-17 21:18:11 +02:00
|
|
|
|
|
|
|
for folder in path.parents:
|
2017-05-17 22:55:09 +02:00
|
|
|
possible_file = folder.with_name(self.options['tags_filename'])
|
|
|
|
self.debug('Search tags file: "%s"' % possible_file)
|
2017-05-17 22:33:16 +02:00
|
|
|
if possible_file.is_file():
|
|
|
|
return str(possible_file)
|
2017-05-16 22:09:12 +02:00
|
|
|
|
|
|
|
raise ValueError('No tags file found in parent folders of given file')
|
|
|
|
|
2017-05-17 22:55:09 +02:00
|
|
|
def debug(self, message):
|
|
|
|
if self.options['logging']:
|
2017-05-17 22:33:16 +02:00
|
|
|
self.nvim.out_write('neotags > ' + message + "\n")
|
2017-05-17 22:55:09 +02:00
|
|
|
|
|
|
|
def error(self, message):
|
|
|
|
if self.options['logging']:
|
|
|
|
self.nvim.err_write('neotags > ' + message + "\n")
|