From 033ec22938d4a82c6c93d59d90623e3458fb4635 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Fri, 11 Aug 2023 11:33:13 +0200 Subject: [PATCH 01/15] Fix Rebuild CTags command being disabled Fixes #341 This commit converts `RebuildTags` into a `WindowCommand` so it keeps working when used in sidebar context menu. This change is required as ST4147+ restricts `TextCommand` usage to fix https://github.com/sublimehq/sublime_text/issues/5781. --- ctagsplugin.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ctagsplugin.py b/ctagsplugin.py index c414881..8e4786a 100644 --- a/ctagsplugin.py +++ b/ctagsplugin.py @@ -207,6 +207,8 @@ def find_tags_relative_to(path, tag_file): def read_opts(view): # the first one is useful to change opts only on a specific project # (by adding ctags.opts to a project settings file) + if not view: + return setting('opts') return view.settings().get('ctags.opts') or setting('opts') def get_alternate_tags_paths(view, tags_file): @@ -812,7 +814,7 @@ def sorted_tags(): # Rebuild CTags commands -class RebuildTags(sublime_plugin.TextCommand): +class RebuildTags(sublime_plugin.WindowCommand): """ Provider for the ``rebuild_tags`` command. @@ -820,13 +822,15 @@ class RebuildTags(sublime_plugin.TextCommand): relevant settings from the settings file. """ - def run(self, edit, **args): + def run(self, **args): """Handler for ``rebuild_tags`` command""" paths = [] + view = self.window.active_view(); + command = setting('command') recursive = setting('recursive') - opts = read_opts(self.view) + opts = read_opts(view) tag_file = setting('tag_file') if 'dirs' in args and args['dirs']: @@ -837,12 +841,10 @@ def run(self, edit, **args): # build ctags and ignore recursive flag - we clearly only want # to build them for a file self.build_ctags(paths, command, tag_file, False, opts) - elif (self.view.file_name() is None and - len(self.view.window().folders()) <= 0): + elif view is None or view.file_name() is None and len(self.window.folders()) <= 0: status_message('Cannot build CTags: No file or folder open.') - return else: - show_build_panel(self.view) + show_build_panel(view) @threaded(msg='Already running CTags!') def build_ctags(self, paths, command, tag_file, recursive, opts): From 738280707fdad4562b147d1c47aa7edcd7974b33 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Fri, 11 Aug 2023 11:48:15 +0200 Subject: [PATCH 02/15] Refactor RebuildTags run() method 1. introduce explicit method argument names 2. merge dirs and files to one paths list 3. read settings only, if ctag command is being invoked 4. `recursive` is always passed to command using merged paths --- ctagsplugin.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/ctagsplugin.py b/ctagsplugin.py index 8e4786a..b27ed0d 100644 --- a/ctagsplugin.py +++ b/ctagsplugin.py @@ -822,27 +822,28 @@ class RebuildTags(sublime_plugin.WindowCommand): relevant settings from the settings file. """ - def run(self, **args): + def run(self, dirs=None, files=None): """Handler for ``rebuild_tags`` command""" - paths = [] - view = self.window.active_view(); - command = setting('command') - recursive = setting('recursive') - opts = read_opts(view) - tag_file = setting('tag_file') - - if 'dirs' in args and args['dirs']: - paths.extend(args['dirs']) - self.build_ctags(paths, command, tag_file, recursive, opts) - elif 'files' in args and args['files']: - paths.extend(args['files']) - # build ctags and ignore recursive flag - we clearly only want - # to build them for a file - self.build_ctags(paths, command, tag_file, False, opts) + paths = [] + if dirs: + paths += dirs + if files: + paths += files + + if paths: + self.build_ctags( + paths, + command=setting('command'), + tag_file=setting('tag_file'), + recursive=setting('recursive'), + opts=read_opts(view) + ) + elif view is None or view.file_name() is None and len(self.window.folders()) <= 0: status_message('Cannot build CTags: No file or folder open.') + else: show_build_panel(view) From a951ca3c9ceb3d16a53e558be47857152e81413e Mon Sep 17 00:00:00 2001 From: deathaxe Date: Fri, 11 Aug 2023 12:07:11 +0200 Subject: [PATCH 03/15] Opt-in to ST4's python 3.8 plugin host --- .python-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .python-version diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..98fccd6 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.8 \ No newline at end of file From d8878a83112dc9ef6e59d9803dad72776c2ea9fb Mon Sep 17 00:00:00 2001 From: deathaxe Date: Thu, 17 Aug 2023 19:30:28 +0200 Subject: [PATCH 04/15] Run unittests via Github Actions --- .github/workflows/ci.yaml | 20 ++++++++++++++++++++ .travis.yml | 12 ------------ README.rst | 3 +-- 3 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/ci.yaml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..4413565 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,20 @@ +name: CI +on: [push, pull_request] + +jobs: + tests: + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: 3.8 + - name: Install Universal CTags + run: sudo apt-get install universal-ctags + - name: Install PyTest + run: pip install pytest + - name: Run PyTest + run: pytest . + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a10e80b..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -# After changing this file, check it on: -# http://lint.travis-ci.org/ -language: python -python: - - "2.6" # sublime text 2 - - "3.3" # sublime text 3 -before_install: - - sudo apt-get install exuberant-ctags - - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi -script: - - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then python -m unittest2.__main__ discover; fi - - if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then python -m unittest discover; fi diff --git a/README.rst b/README.rst index 2b575b4..ff1c3b3 100644 --- a/README.rst +++ b/README.rst @@ -2,8 +2,7 @@ CTags ===== -.. image:: https://travis-ci.org/SublimeText/CTags.svg?branch=development - :target: https://travis-ci.org/SublimeText/CTags +.. image:: https://github.com/SublimeText/CTags/actions/workflows/ci.yaml/badge.svg About ===== From 91d5d02e9ca723f6e42a4d5fa81090fbe9ea688d Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 12 Aug 2023 10:50:33 +0200 Subject: [PATCH 05/15] Fix unittest for c files --- ctags.py | 2 +- test_ctags.py | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ctags.py b/ctags.py index 66ca1e1..084d796 100644 --- a/ctags.py +++ b/ctags.py @@ -345,7 +345,7 @@ def resort_ctags(tag_file): For each key in the sorted dictionary For each line in the list indicated by the key Split the line on tab character - Remove the prepending ``.\`` from the ``file_name`` part of + Remove the prepending ``.`` from the ``file_name`` part of the tag Join the line again and write the ``sorted_by_file`` file diff --git a/test_ctags.py b/test_ctags.py index c472cc3..0331abc 100644 --- a/test_ctags.py +++ b/test_ctags.py @@ -453,13 +453,16 @@ def test_parse_tag_lines__c(self): 'symbol': 'bar', 'filename': filename, 'ex_command': 'void bar()', - 'tag_path': (filename, 'bar'), + 'tag_path': (filename, 'typename', 'void', 'bar'), 'type': 'f', - 'fields': None}], + 'fields': 'typeref:typename:void', + 'field_keys': ['typeref'], + 'typeref': 'typename:void', + }], 'foo': [{ 'symbol': 'foo', 'filename': filename, - 'ex_command': '1', + 'ex_command': '#define foo', 'tag_path': (filename, 'foo'), 'type': 'd', 'fields': 'file:', @@ -468,7 +471,7 @@ def test_parse_tag_lines__c(self): 'foobar': [{ 'symbol': 'foobar', 'filename': filename, - 'ex_command': '2', + 'ex_command': '#define foobar', 'tag_path': (filename, 'foobar'), 'type': 'd', 'fields': 'file:', From b7015eb697a36c51d41082b237076ca413ebe98e Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 6 Jan 2024 17:46:28 +0100 Subject: [PATCH 06/15] Fix goto definition for macros (#345) Fixes #336 Returned `ex_command` patterns don't necessarily represent a full line pattern. They rather represent the beginning of the line. --- ctagsplugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctagsplugin.py b/ctagsplugin.py index b27ed0d..1dfa427 100644 --- a/ctagsplugin.py +++ b/ctagsplugin.py @@ -332,7 +332,7 @@ def follow_tag_path(view, tag_path, pattern): # find the ex_command pattern pattern_region = find_source( - view, '^' + escape_regex(pattern) + '$', start_at, flags=0) + view, r'^' + escape_regex(pattern), start_at, flags=0) if setting('debug'): # leave a visual trail for easy debugging regions = regions + ([pattern_region] if pattern_region else []) From 153ab87a27a37a60f0916715c2ffd31f52a665c9 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 6 Jan 2024 17:46:55 +0100 Subject: [PATCH 07/15] Fix show_symbols for relative sub directories (#346) This commit updates ShowSymbols command in order to... 1. convert path of source file relative to its .tags file to unix format by replacing `\\` by `/`. That's required as paths use the former on Windows, while path in .tags file are always given in unix format. 2. creates a common cache key `__all__` for running command with `type=multi`, instead of using active view's relative path. This enables multiple views to share the same cache object for "all symbols". --- ctagsplugin.py | 32 +++++++++++++++++++------------- test_ctagsplugin.py | 10 ++++------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/ctagsplugin.py b/ctagsplugin.py index 1dfa427..3cd0ebe 100644 --- a/ctagsplugin.py +++ b/ctagsplugin.py @@ -426,7 +426,7 @@ def compile_lists(sorter): # File collection helper functions -def get_rel_path_to_source(path, tag_file, multiple=True): +def get_rel_path_to_source(path, tag_file): """ Get relative path from tag_file to source file. @@ -436,14 +436,11 @@ def get_rel_path_to_source(path, tag_file, multiple=True): :returns: list containing relative path from tag_file to source file """ - if multiple: - return [] - tag_dir = os.path.dirname(tag_file) # get tag directory - common_prefix = os.path.commonprefix([tag_dir, path]) + common_prefix = os.path.commonprefix((tag_dir, path)) relative_path = os.path.relpath(path, common_prefix) - return [relative_path] + return relative_path def get_current_file_suffix(path): @@ -753,18 +750,27 @@ def run(self, view, args, tags_file): if not tags_file: return - multi = args.get('type') == 'multi' - lang = args.get('type') == 'lang' - - if view.file_name(): - files = get_rel_path_to_source( - view.file_name(), tags_file, multi) + symbol_type = args.get('type') + multi = symbol_type == 'multi' + lang = symbol_type == 'lang' if lang: + # filter and cache by file suffix suffix = get_current_file_suffix(view.file_name()) key = suffix + elif multi: + # request all symbols of given tags file + key = "__all__" + files = [] else: - key = ','.join(files) + # request symbols of current view's file + key = view.file_name() + if not key: + return + key = get_rel_path_to_source(key, tags_file) + key = key.replace('\\', '/') + + files = [key] tags_file = tags_file + '_sorted_by_file' base_path = get_common_ancestor_folder( diff --git a/test_ctagsplugin.py b/test_ctagsplugin.py index 394b458..602cc5e 100644 --- a/test_ctagsplugin.py +++ b/test_ctagsplugin.py @@ -205,24 +205,22 @@ def test_get_rel_path_to_source__source_file_in_sibling_directory(self): temp = '/c/users/temporary_file' tag_file = '/c/users/tags' - result = ctagsplugin.get_rel_path_to_source( - temp, tag_file, multiple=False) + result = ctagsplugin.get_rel_path_to_source(temp, tag_file) relative_path = 'temporary_file' - self.assertEqual([relative_path], result) + self.assertEqual(relative_path, result) def test_get_rel_path_to_source__source_file_in_child_directory(self): temp = '/c/users/folder/temporary_file' tag_file = '/c/users/tags' - result = ctagsplugin.get_rel_path_to_source( - temp, tag_file, multiple=False) + result = ctagsplugin.get_rel_path_to_source(temp, tag_file) # handle [windows, unix] paths relative_paths = ['folder\\temporary_file', 'folder/temporary_file'] - self.assertIn(result[0], relative_paths) + self.assertIn(result, relative_paths) if __name__ == '__main__': unittest.main() From 9468e67cefb988adf63d5671f0e361871362527a Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 6 Jan 2024 17:47:21 +0100 Subject: [PATCH 08/15] Fix file encoding exception (#347) This commit opens .tags files with utf-8 encoding to avoid file encoding exceptions such as the following, which was raised while looking up symbols in linux kernel sources. ``` loading symbols from file Traceback (most recent call last): File "\Lib\python38\sublime_plugin.py", line 1697, in run_ return self.run(edit, **args) File "\Data\Packages\CTags\plugins\cmds.py", line 587, in command result = func(self, self.view, args, tags_file) File "\Data\Packages\CTags\plugins\cmds.py", line 789, in run tags = get_tags() File "\Data\Packages\CTags\plugins\cmds.py", line 778, in get_tags return tagfile.get_tags_dict( File "\Data\Packages\CTags\plugins\ctags.py", line 567, in get_tags_dict filters = kw.get('filters', []) File "\Data\Packages\CTags\plugins\ctags.py", line 86, in parse_tag_lines for line in lines: File "\Data\Packages\CTags\plugins\ctags.py", line 518, in search while self.mapped.tell() < self.mapped.size(): File "./python3.8/codecs.py", line 714, in __next__ File "./python3.8/codecs.py", line 645, in __next__ File "./python3.8/codecs.py", line 558, in readline File "./python3.8/codecs.py", line 504, in read UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 135: ordinal not in range(128) ``` .tags files are stored using utf-8 and thus must be opened with that encoding. --- ctags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctags.py b/ctags.py index 084d796..fdff8b2 100644 --- a/ctags.py +++ b/ctags.py @@ -476,7 +476,7 @@ def open(self): """ Open file. """ - self.file_o = codecs.open(self.path, 'r+b', encoding='ascii') + self.file_o = codecs.open(self.path, 'r+b', encoding='utf-8') self.mapped = mmap.mmap(self.file_o.fileno(), 0, access=mmap.ACCESS_READ) From f029530671255f5e1ed367125b380687ee014583 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 6 Jan 2024 17:55:30 +0100 Subject: [PATCH 09/15] Fix IndexError caused by invalid tags (#348) `TagFile` class' __getitem__() method returns `Tag` objects for invalid tags with only one column or even for empty lines. This causes index errors, when trying to access non-existing columns (not enough \t present in a line). --- ctags.py | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/ctags.py b/ctags.py index fdff8b2..e506bf5 100644 --- a/ctags.py +++ b/ctags.py @@ -393,16 +393,26 @@ def __init__(self, line, column=0): self.column = column def __lt__(self, other): - return self.line.split('\t')[self.column] < other + try: + return self.key < other + except IndexError: + return False def __gt__(self, other): - return self.line.split('\t')[self.column] > other + try: + return self.key > other + except IndexError: + return False def __getitem__(self, index): - return self.line.split('\t')[index] + return self.line.split('\t', self.column + 1)[index] def __len__(self): - return len(self.line.split('\t')) + return self.line.count('\t') + 1 + + @property + def key(self): + return self[self.column] class TagFile(object): """ @@ -443,6 +453,8 @@ def __getitem__(self, index): result = self.mapped.readline() # get a complete line result = result.strip() + if not result: + raise IndexError("Invalid tag at index %d." % index) return Tag(result, self.column) @@ -500,7 +512,8 @@ def search(self, exact_match=True, *tags): if not tags: while self.mapped.tell() < self.mapped.size(): result = Tag(self.mapped.readline().strip(), self.column) - yield(result) + if result.line: + yield result return for key in tags: @@ -508,12 +521,12 @@ def search(self, exact_match=True, *tags): if exact_match: result = self[left_index] while result.line and result[result.column] == key: - yield(result) + yield result result = Tag(self.mapped.readline().strip(), self.column) else: result = self[left_index] while result.line and result[result.column].startswith(key): - yield(result) + yield result result = Tag(self.mapped.readline().strip(), self.column) def search_by_suffix(self, suffix): @@ -529,10 +542,9 @@ def search_by_suffix(self, suffix): :returns: matching tags """ for line in self.file_o: - if line.split('\t')[self.column].endswith(suffix): - yield Tag(line) - else: - continue + tag = Tag(line, self.column) + if tag.key.endswith(suffix): + yield tag def tag_class(self): """ From ac0364bd81dfc4fa8aac8dd231532fbfdb1f9cb4 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 6 Jan 2024 17:56:10 +0100 Subject: [PATCH 10/15] Improve auto completions (#350) * Improve auto completions 1. Load .tags file relative to active view, the same way as for GotoSymbol 2. Directly iterate through .tags file without using awk. 3. Restrict auto completions to .tag files with 100MB of size or less. 4. Drop a lot of type conversions between lists and sets. 5. Don't return completions for metadata `!_TAG_...` lines. 6. Cache completions per tag_file. Doing so globally may have unwanted side effects when multiple projects/windows are open. 7. Drop extracting and merging with ST completions, as merging all sources is already performed by ST. No need to do it here. * Fix typo --- ctagsplugin.py | 69 ++++++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/ctagsplugin.py b/ctagsplugin.py index 3cd0ebe..44e3407 100644 --- a/ctagsplugin.py +++ b/ctagsplugin.py @@ -908,66 +908,51 @@ def tags_built(tag_file): tags_built(result) - GetAllCTagsList.ctags_list = [] # clear the cached ctags list + if tag_file in ctags_completions: + del ctags_completions[tag_file] # clear the cached ctags list # Autocomplete commands -class GetAllCTagsList(): - """ - Cache all the ctags list. - """ - ctags_list = [] - - def __init__(self, list): - self.ctags_list = list +ctags_completions = {} class CTagsAutoComplete(sublime_plugin.EventListener): def on_query_completions(self, view, prefix, locations): - if setting('autocomplete'): - prefix = prefix.strip().lower() - tags_path = view.window().folders()[0] + '/' + setting('tag_file') + if not setting('autocomplete'): + return None - sub_results = [v.extract_completions(prefix) - for v in sublime.active_window().views()] - sub_results = [(item, item) for sublist in sub_results - for item in sublist] # flatten + prefix = prefix.lower() - if GetAllCTagsList.ctags_list: - results = [sublist for sublist in GetAllCTagsList.ctags_list - if sublist[0].lower().startswith(prefix)] - results = sorted(set(results).union(set(sub_results))) + tags_path = find_tags_relative_to( + view.file_name(), setting('tag_file')) - return results - else: - tags = [] + if not tags_path: + return None - # check if a project is open and the tags file exists - if not (view.window().folders() and os.path.exists(tags_path)): - return tags + if not os.path.exists(tags_path): + return None - if sublime.platform() == "windows": - prefix = "" - else: - prefix = "\\" + if os.path.getsize(tags_path) > 100 * 1024 * 1024: + return None + + if tags_path not in ctags_completions: + tags = set() - f = os.popen( - "awk \"{ print " + prefix + "$1 }\" \"" + tags_path + "\"") + with open(tags_path, "r", encoding="utf-8") as fobj: + for line in fobj: + line = line.strip() + if not line or line.startswith("!_TAG"): + continue + cols = line.split("\t", 1) + tags.add(cols[0]) - for i in f.readlines(): - tags.append([i.strip()]) + ctags_completions[tags_path] = tags - tags = [(item, item) for sublist in tags - for item in sublist] # flatten - tags = sorted(set(tags)) # make unique - GetAllCTagsList.ctags_list = tags - results = [sublist for sublist in GetAllCTagsList.ctags_list - if sublist[0].lower().startswith(prefix)] - results = sorted(set(results).union(set(sub_results))) + return [tag for tag in ctags_completions[tags_path] + if tag.lower().startswith(prefix)] - return results # Test CTags commands From 1fbe1c504814db86519bdf46aa9f6079b796f512 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 6 Jan 2024 18:28:18 +0100 Subject: [PATCH 11/15] Improve sorting .tag files (#349) * Improve sorting .tag files Fixes #278 Fixes #329 This commit refactors .tags file post-processing. 1. All metadata lines, beginning with `!_TAG`, are sorted and moved to the top of the output file. 2. Invalid lines are silently dropped. A line is valid, at least contains one `\t`. 3. symbols are stored in a list of tuples rather than a dict, to improve iteration and sorting performance during output phase. It has the form of: [ filename, ( symbol_name, filename, ... ) ] Symbols are sorted by filename, followed by symbol_name. Note: This is an alternative #279, but without printing warnings and with an additional optimizations to avoid splitting lines twice. * Keep only sorted .tags files As those may be large, it's probably useful to not have two of them. --- ctags.py | 38 +++++++++++++++++++++++++++++--------- ctagsplugin.py | 1 - 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/ctags.py b/ctags.py index e506bf5..027f60e 100644 --- a/ctags.py +++ b/ctags.py @@ -341,7 +341,7 @@ def resort_ctags(tag_file): If not exists, create an empty array and store in the dictionary with the file name as key Save the line to this list - Create a new ``[tagfile]_sorted_by_file`` file + Create a new ``tagfile`` file For each key in the sorted dictionary For each line in the list indicated by the key Split the line on tab character @@ -353,19 +353,39 @@ def resort_ctags(tag_file): :returns: None """ - keys = {} + meta = [] + symbols = [] + tmp_file = tag_file + '.tmp' with codecs.open(tag_file, encoding='utf-8', errors='replace') as file_: for line in file_: - keys.setdefault(line.split('\t')[FILENAME], []).append(line) + if line.startswith('!_TAG'): + meta.append(line) + continue - with codecs.open(tag_file+'_sorted_by_file', 'w', encoding='utf-8', + # read all valid symbol tags, which contain at least + # symbol name and containing file and build a list of tuples + split = line.split('\t') + if len(split) > FILENAME: + symbols.append((split[FILENAME], split)) + + # sort inplace to save some RAM with large .tags files + meta.sort() + symbols.sort() + + with codecs.open(tmp_file, 'w', encoding='utf-8', errors='replace') as file_: - for k in sorted(keys): - for line in keys[k]: - split = line.split('\t') - split[FILENAME] = split[FILENAME].lstrip('.\\') - file_.write('\t'.join(split)) + + # write sourted metadata + file_.writelines(meta) + + # followed by sorted list of symbols + for _, split in symbols: + split[FILENAME] = split[FILENAME].lstrip('.\\') + file_.write('\t'.join(split)) + + os.remove(tag_file) + os.rename(tmp_file, tag_file) # # Models diff --git a/ctagsplugin.py b/ctagsplugin.py index 44e3407..58db37e 100644 --- a/ctagsplugin.py +++ b/ctagsplugin.py @@ -772,7 +772,6 @@ def run(self, view, args, tags_file): files = [key] - tags_file = tags_file + '_sorted_by_file' base_path = get_common_ancestor_folder( view.file_name(), view.window().folders()) From bea804d33ca958bf0edb4c2e8468b4c2bc1a4ff0 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 6 Jan 2024 18:45:36 +0100 Subject: [PATCH 12/15] README: Fix links Fixes #352 --- README.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index ff1c3b3..5bdf688 100644 --- a/README.rst +++ b/README.rst @@ -7,10 +7,10 @@ CTags About ===== -This `Sublime Text 2/3`_ package provides support for working with tags +This `Sublime Text`_ package provides support for working with tags generated by `Exuberant CTags`_ -.. _Sublime Text 2/3: http://sublimetext.com/ +.. _Sublime Text: http://sublimetext.com/ .. _Exuberant CTags: http://ctags.sourceforge.net/ The ctags command is searched for on the system PATH. It works by doing a @@ -24,11 +24,9 @@ See this `forum thread`_ for a bit of historical background on the Sublime Text Installation ============ -The easiest way to install this plugin, is to use the `Package Control`_ -plugin, by `Will Bond`_ +The easiest way to install this plugin, is to use the `Package Control`_ . -.. _Package Control: http://wbond.net/sublime_packages/package_control/ -.. _Will Bond: http://wbond.net/ +.. _Package Control: http://packagecontrol.io/ Alternatively, the plugin can be installed manually using one of the following methods. From c30202b6e34d464dbf6b2e7fa1724d32dd99ecd8 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 6 Jan 2024 18:47:43 +0100 Subject: [PATCH 13/15] README: Fix path value Fixes #330 --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 5bdf688..ee9f35e 100644 --- a/README.rst +++ b/README.rst @@ -156,7 +156,7 @@ can be edited like any other ``.sublime-settings`` file or:: - "command" : "C:\Users\\Downloads\CTags\ctag.exe" + "command" : "C:\\Users\\\\Downloads\\CTags\\ctag.exe" The rest of the options are fairly self explanatory. From e20f02773f01155ddcefff8c943e7fc824fe47af Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 6 Jan 2024 18:53:12 +0100 Subject: [PATCH 14/15] Remove invalid "context" keys --- Default.sublime-commands | 16 ---------------- Main.sublime-menu | 23 +++-------------------- 2 files changed, 3 insertions(+), 36 deletions(-) diff --git a/Default.sublime-commands b/Default.sublime-commands index a7bb43d..9da3ad8 100644 --- a/Default.sublime-commands +++ b/Default.sublime-commands @@ -6,14 +6,6 @@ { "caption": "CTags: Show Symbols (file)", "command": "show_symbols", - "context": [ - { - "key": "selector", - "match_all": true, - "operand": "source -source.css", - "operator": "equal" - } - ] }, { "caption": "CTags: Show Symbols (all)", @@ -21,13 +13,5 @@ "args": { "type": "multi" }, - "context": [ - { - "key": "selector", - "match_all": true, - "operand": "source -source.css", - "operator": "equal" - } - ] } ] diff --git a/Main.sublime-menu b/Main.sublime-menu index e977bc4..1c83cb9 100644 --- a/Main.sublime-menu +++ b/Main.sublime-menu @@ -22,39 +22,22 @@ "command": "rebuild_tags" }, { + "caption": "Show Symbols (file)", "command": "show_symbols", - "context": [ - { - "key": "selector", - "match_all": true, - "operand": "source -source.css", - "operator": "equal" - } - ] }, { + "caption": "Show Symbols (all)", + "command": "show_symbols", //"arg_comment": "TODO", "args": { "type": "multi" }, - "caption": "Show Symbols (all)", - "command": "show_symbols", - "context": [ - { - "key": "selector", - "match_all": true, - "operand": "source -source.css", - "operator": "equal" - } - ] } ] } ] }, { - "caption": "Preferences", - "mnemonic": "n", "id": "preferences", "children": [ From babb1a90c7e813b335fbc4097fd30254411509e6 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Sat, 6 Jan 2024 19:02:11 +0100 Subject: [PATCH 15/15] Auto-migrate existing .tags_sorted_file to .tags Needed to migrate existing sorted .tags files to new name as it is changed by PR #349. --- ctagsplugin.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ctagsplugin.py b/ctagsplugin.py index 58db37e..18c73c3 100644 --- a/ctagsplugin.py +++ b/ctagsplugin.py @@ -772,6 +772,17 @@ def run(self, view, args, tags_file): files = [key] + # Note: Help migrating existing tags files to new file name. + # Needed, because this plugin now sorts .tags file in-place, + # while former versions used to create a dedicated file. + sorted_tags_file = tags_file + '_sorted_by_file' + if os.path.isfile(sorted_tags_file): + try: + os.remove(tags_file) + os.rename(sorted_tags_file, tags_file) + except OSError: + pass + base_path = get_common_ancestor_folder( view.file_name(), view.window().folders())