I have proprietary / custom code that I’d like to set up as snippets, but I’d also like them to autocomplete. All of them start with three brackets ( [[[ ) so I was thinking, after I type those in and begin typing sublime could search through all my custom snippets. The snippets would appear just as the autocompletion items do. Not sure where to start. I tried to poke my way through creating a html_completions.py file, but got lost. Should I set up some kind of macro?
I want all my snippets to open in an "autocomplete" list after typing custom code (3 brackets - [[[ )
Here is a generic solution that will work with your [[[
tab trigger prefix to show auto completions:
(It is Python code, to be saved as a plugin with a .py
extension in your Packages/User
folder)
import sublime, sublime_plugin
from xml.etree import ElementTree
class AutoCompleteSnippetTriggersListener(sublime_plugin.EventListener):
def on_query_completions(self, view, prefix, locations):
snippets = sublime.find_resources('*.sublime-snippet')
completions = []
word_separators = view.settings().get('word_separators')
for snippet_path in snippets:
snippet_content = sublime.load_resource(snippet_path)
xml_doc = ElementTree.fromstring(snippet_content)
trigger = xml_doc.find('tabTrigger')
if trigger is None or trigger.text is None:
continue
triggerText = trigger.text
separator_prefix = ''
while len(triggerText) > 0 and triggerText[0] in word_separators:
separator_prefix += triggerText[0]
triggerText = triggerText[1:]
if not triggerText.startswith(prefix):
continue
if len(separator_prefix) > 0:
prefix_match = True
for location in locations:
if location - len(separator_prefix) < 0:
prefix_match = False
break
if view.substr(sublime.Region(location - len(separator_prefix) - len(prefix), location)) != separator_prefix + prefix:
prefix_match = False
break
if not prefix_match:
continue
scope = xml_doc.find('scope')
if scope is not None and scope.text is not None:
scope_match = False
for location in locations:
if view.match_selector(location, scope.text):
scope_match = True
break
if not scope_match:
continue
completions.append((trigger.text + '\tSnippet', xml_doc.find('content').text))
#if len(completions) > 1: # only show completions if there are more than one, otherwise ST will automatically insert the snippet as it is the only completion, and maybe we want it to only work on the exact tab trigger
return completions
#else:
# return None
homework task: if you wanted, you could modify it to only suggest snippets from the User folder, and/or to only suggest snippets beginning with [[[
. or, create a keybinding for [[[
that will display only your relevant snippets
Snippet's dropdown for LaTeX
Sublime-snippet tabtrigger is behaving differently than sublime-completions trigger
Is this code affected by those AutoComplete bugs you sent me before?
Completion triggers with characters not in [a-zA-Z0-9_-] prevent buffer completions
on_query_completions fails to return custom completions when some characters are used
( For context: I’m also working on an AutoComplete plugin, and when I tried to include snippets it would disable all of the regular document completions )
unfortunately, yes - if any of the snippets include a tabTrigger
with “special” (i.e. unsupported/bug-causing) characters, then entries from custom completion files will not be shown
Hope this doesn’t turn out to be one of the bugs that sits in the queue for years…
It would be super useful to have mixed snippets & completions without any issues.
I experimented with working around it by not including the word separator characters that appear at the beginning of the tabTrigger (i.e. completions.append((trigger.text[len(separator_prefix):] + '\tSnippet', xml_doc.find('content').text))
) but then if you type [[[
(from the OP example), press ctrl+space, and choose the relevant snippet, the [[[
will still appear in the document - i.e. that part will not get replaced with the snippet.
I have the idea (well, hope, really) that once the Default Packages have been improved, more work will go into looking at some of the core issues. Therefore, I have been trying to help improve the default packages to speed things along
unfortunately not https://github.com/SublimeTextIssues/Core/issues/156
here is a test sublime-snippet file in case you want to experiment:
<snippet>
<content><![CDATA[
Hello, ${1:this} is a ${2:snippet}.
]]></content>
<!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
<tabTrigger>[[[hello</tabTrigger>
<!-- Optional: Set a scope to limit where the snippet will trigger -->
<!-- <scope>source.python</scope> -->
</snippet>
It’s not working for me.
From OP:
Based on that - Im expecting to type [[[h
at which point the AutoComplete would kick in, but I’m not currently getting any results.
Edit:
It was caused by a plugin snippet:
snippet_path == Packages/AutoHotkey/AHK-TrayIcon.sublime-snippet
Traceback (most recent call last):
File "C:\Program Files\Sublime Text 3\sublime_plugin.py", line 377, in on_query_completions
res = callback.on_query_completions(v, prefix, locations)
File "C:\Users\Fico\AppData\Roaming\Sublime Text 3\Packages\_DEV_Test\TEST.py", line 16, in on_query_completions
xml_doc = ElementTree.fromstring(snippet_content)
File "./xml/etree/ElementTree.py", line 1356, in XML
File "<string>", line None
xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 3, column 19
Fixed With:
try:
xml_doc = ElementTree.fromstring(snippet_content)
except ElementTree.ParseError:
continue
Here’s a general idea on how I would approach it (after little thinking).
- Provide all completions in a
on_query_completions
callback. - See if the three characters before the
location
parameter (which is a list, so best to check all locations in that) equal[[[
. - If they do not, prepend
[[[
to all your completions’ contents.
This may or may not be what you wanted.
Alternatively, you could set [
as a auto_complete_trigger
character (see default preferences) and prevent completions from within your plugin if one or two [
are preceding the location
s.