Sublime Forum

Is there any way to trigger autocompletion on non-word characters?

#1

Suppose I want to write an autocompletion plugin for HTML that, as soon as I type an opening angle bracket “<”, brings up a completion menu of all tag names. That is, I don’t want the menu to be delayed until after I type the first character of the tag name. (Perhaps I want newbies to be able to browse through all tags if they can’t remember the name of the one they want.)

An example of where this would be even more useful would be in a smart completions plugin for python, where after typing a variable name followed by a “.”, it pops up an auto-complete menu listing all known properties of that object.

I can’t see any way to implement this, since the “on_query_completions” event listener only runs after typing a word character. Is there a way to programmatically trigger the completions query at some other time?

1 Like

#2

I’m working a plugin that does most of what you described.

It will allow devs & users to easily create YAML files that define contextual completions.

The initial release will require completions to be predefined, but I do plan on looking into dynamic completions as well.

Demo

2 Likes

#3

Cool, that’s exactly what I’m going for. How does your plugin handle this?

0 Likes

#4

Here’s the most closely related method ( @kingkeith helped me out with this :grin: ) . There’s a lot of other stuff going on throughout the plugin though; like word segment diffing, user setting validation to determine whether or not the functionality is enabled, etc.

Some of the functionality is also coming from a framework I’m developing in parallel, so it would be difficult for me to extract every related section.  I’ll definitely let you know once the plugin & framework are released though, in case you are still working on this & want to check out the code and/or implement it with your plugin.

def update_CompletionTriggers():

	matchFound = False

	for triggerGroup in G.triggerSettings:

		scopeSelector     = triggerGroup[ "selector" ]
		triggerCharacters = triggerGroup[ "characters" ]

		if scopeSelector == G.scopeSelector:

			matchFound = True

			if not G.completionTrigger in triggerCharacters:
				triggerGroup[ "characters" ] = triggerCharacters + G.completionTrigger
				V.view.settings().set ( "auto_complete_triggers", G.triggerSettings )

			break

	if matchFound == False:
		G.triggerSettings.append ( { "selector": G.scopeSelector, "characters": G.completionTrigger } )
		V.view.settings().set ( "auto_complete_triggers", G.triggerSettings )
0 Likes

#5

I’m guessing that this function is triggered by an on_modified or on_selection_modified event, is that right? And then you’re using show_popup_menu to display the list of completions?

0 Likes

#6

 
You need to use the on_query_completions listener.  The completion menu can’t be shown manually, you can only add entries and dictate triggers.

Here’s a basic example I wrote for another thread.

0 Likes

#7

Sorry for the delay, it seems I missed the notification of your response!

But the on_query_completions listener only fires when I type letters or numbers. What I’m trying to understand is how to show completions after typing non-word characters, as you demonstrate in the gif you posted! How do you get on_query_completions to run, say, after typing a period? (Or a bracket, or a space, or something else?)

I already understand how to add entries to the menu based on the scope or other aspects of the context - it’s triggering the completions menu to pop up after non-word characters that I’m trying to figure out.

0 Likes

#8

 
The simple answer:
Update auto_complete_triggers in your user settings file.

 
The format is:

[{"selector": "source.python", "characters": ".("},{"selector": "text.html", "characters": "<."}]

where characters is a string containing a plain-text list of all trigger characters for the associated selector.
 



 
If you want to do it programatically, you have to update the auto_complete_triggers setting before or during on_query_completions.

The implementation I posted above runs during on_query_completions & updates auto_complete_triggers per view, so as not to overwrite the global settings.  It’s essentially a validation loop to either append to the matched selector’s characters or add a new dictionary to the list if the view does not have an entry for the current selector.

This ensures that existing settings are retained & prevents redundancies like:

[{"selector": "source.python", "characters": "."},{"selector": "source.python", "characters": "."}]

or

[{"selector": "source.python", "characters": "........."}]

 

You can use

view.settings().get( "auto_complete_triggers" )

to get the original settings, and then use

view.settings().set( "auto_complete_triggers", updatedTriggers_List )

to update them.

3 Likes

#9

Awesome! Thanks so much, this is exactly what I was looking for!

1 Like

#10

Additionally, you can manually trigger the completions popup with ctrl+space at any position (assuming there is more than one completion to be inserted, iirc). This binding could be different on linux.

0 Likes

#11

Indeed, in Linux the default binding for this action is Alt+/. MacOS shares the same default as Windows.

1 Like