Sublime Forum

I want all my snippets to open in an "autocomplete" list after typing custom code (3 brackets - [[[ )

#1

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?

0 Likes

#2

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 :wink:

1 Like

Snippet's dropdown for LaTeX
Sublime-snippet tabtrigger is behaving differently than sublime-completions trigger
#3

@kingkeith

 
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 )

0 Likes

#4

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 :frowning:

1 Like

#5

 
Hope this doesn’t turn out to be one of the bugs that sits in the queue for years… :unamused:

It would be super useful to have mixed snippets & completions without any issues.

0 Likes

#6

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.

1 Like

#7

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 :wink:

1 Like

#8

 
Would it work if OP included [[[ in tabTrigger but omitted it from content ?

0 Likes

#9

unfortunately not :frowning: 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>
0 Likes

#10

 
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
0 Likes

#11

Here’s a general idea on how I would approach it (after little thinking).

  1. Provide all completions in a on_query_completions callback.
  2. See if the three characters before the location parameter (which is a list, so best to check all locations in that) equal [[[.
  3. 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 locations.

0 Likes