skip to Main Content

I am attempting to add Completion snippets to an extension I’m writing based on the completions sample ( https://github.com/microsoft/vscode-extension-samples/tree/main/completions-sample ). I would like to have it branch complete. In my extension, SET is a keyword that then has possible params. Each param then has further params.

Ex: SET FOO|BAR|BAS where SET FOO can be ON|OFF, SET BAR is 1|2|3, and SET BAS is RED|BLUE.

I’ve tried to do it with

            const SetCompletion = new vscode.CompletionItem('SET');
            SetCompletion.insertText = new vscode.SnippetString('SET ${1|FOO,BAR,BAS|};');

And then Follow on with

            const SetFooCompletion = new vscode.CompletionItem('FOO');
            SetFooCompletion.insertText = new vscode.SnippetString('FOO ${1|ON,OFF|};');

            const SetBarCompletion = new vscode.CompletionItem('BAR');
            SetBarCompletion.insertText = new vscode.SnippetString('BAR ${1|1,2,3|};');

            const SetBasCompletion = new vscode.CompletionItem('BAS');
            SetBasCompletion.insertText = new vscode.SnippetString('BAS ${1|RED,BLUE|};');

And this sort of works if I retrigger completion after the first item is inserted. I think there might be a better way. In my real world code, there are about 15 SET things that I can call on, and each one has different types of params. Some are ON|OFF, some are numbers, some strings. In the above snippets, SET BAR ON is invalid, since BAR is an integer and only FOO is ON|OFF so I don’t want to provide all possible parameters to all SET statements. They should be specific to the SET command that resolves in the first completion.

Is this possible?

Edit: Fixed typos in sample code

2

Answers


  1. The following code works.

    const linePrefix = document.lineAt(position).text.substr(0, position.character);
    if (linePrefix.endsWith('SET')) {
      const setCompletion = new vscode.CompletionItem('SET', vscode.CompletionItemKind.Snippet);
      setCompletion.insertText = new vscode.SnippetString('SET ${1|FOO,BAR,BAS|};');
      const setFooCompletion = new vscode.CompletionItem('SET FOO', vscode.CompletionItemKind.Snippet);
      setFooCompletion.insertText = new vscode.SnippetString('SET FOO ${1|ON,OFF|};');
      const setBarCompletion = new vscode.CompletionItem('SET BAR', vscode.CompletionItemKind.Snippet);
      setBarCompletion.insertText = new vscode.SnippetString('SET BAR ${1|1,2,3|};');
      const setBasCompletion = new vscode.CompletionItem('SET BAS', vscode.CompletionItemKind.Snippet);
      setBasCompletion.insertText = new vscode.SnippetString('SET BAS ${1|RED,BLUE|};');
      return [setCompletion, setFooCompletion, setBarCompletion, setBasCompletion];
    }
    

    If you use new vscode.CompletionItem('FOO'); it does not work. Looks like the label must match the last word of the line.

    Also the line

    blablaSET
    

    does not give completion items. The SET must be a separate word. The completion items are created but are not shown.


    Or you can try:

    const linePrefix = document.lineAt(position).text.substr(0, position.character);
    if (linePrefix.endsWith('SET')) {
      const setCompletion = new vscode.CompletionItem('SET', vscode.CompletionItemKind.Snippet);
      setCompletion.insertText = new vscode.SnippetString('SET ${1|FOO,BAR,BAS|}$0;');
      return [setCompletion];
    }
    if (linePrefix.endsWith('SET FOO')) {
      const setFooCompletion = new vscode.CompletionItem('FOO', vscode.CompletionItemKind.Snippet);
      setFooCompletion.insertText = new vscode.SnippetString('FOO ${1|ON,OFF|}');
      return [setFooCompletion];
    }
    if (linePrefix.endsWith('SET BAR')) {
      const setBarCompletion = new vscode.CompletionItem('BAR', vscode.CompletionItemKind.Snippet);
      setBarCompletion.insertText = new vscode.SnippetString('BAR ${1|1,2,3|}');
      return [setBarCompletion];
    }
    if (linePrefix.endsWith('SET BAS')) {
      const setBasCompletion = new vscode.CompletionItem('BAS', vscode.CompletionItemKind.Snippet);
      setBasCompletion.insertText = new vscode.SnippetString('BAS ${1|RED,BLUE|}');
      return [setBasCompletion];
    }
    

    You have to trigger the CompletionItems with Ctrl+Space after selecting one of the SET options. Look carefully when you leave the snippet (or double snippet) when using TAB (multiple times)

    Login or Signup to reply.
  2. I took a long look at this trying to figure out what is going on and concluded that because your first snippet is a choice snippet that you will not be able to do it as simply as you would like.

    Normally, if you used this

    const SetCompletion  = new vscode.CompletionItem('SET');
    SetCompletion .insertText = new vscode.SnippetString('SET ${1|FOO,BAR,BAS|};');
    
    SetCompletion.command = { command: 'editor.action.triggerSuggest', title: 'Re-trigger completions...' };
    

    that command property would help you avoid having to manually re-trigger the suggestions for FOO/BAR/BAS. But it doesn’t work. I am convinced that the command runs after the snippet is inserted but before it is completed.

    You can see this if you use other commands like

    SetCompletion.command = { command: 'leaveSnippet', title: '...' };
    

    In this case, you won’t even get the choice presented because the leaveSnippet command has already run!

    So it seems the simplest is this:

    const SetFooCompletion = new vscode.CompletionItem('SET FOO');
    SetFooCompletion.insertText = new vscode.SnippetString('SET FOO ${1|ON,OFF|};');
    
    const SetBarCompletion = new vscode.CompletionItem('SET BAR');
    SetBarCompletion.insertText = new vscode.SnippetString('SET BAR ${1|1,2,3|};');
    
    const SetBasCompletion = new vscode.CompletionItem('SET BAS');
    SetBasCompletion.insertText = new vscode.SnippetString('SET BAS ${1|RED,BLUE|};');
    

    You would have to make a bunch of SET xxx CompletionItems but there would be no manually triggering of suggestions to complete.

    choice completions demo


    As an interesting aside (and more proof that the command is running before the snippet choice and thus of no use is code like this:

    const SetCompletion = new vscode.CompletionItem('SET');
    SetCompletion.insertText = new vscode.SnippetString('${TM_FILENAME_BASE/(.*)/${1:/upcase}/}');
    
    SetCompletion.command = { command: 'folder-operations.setCompletionCommand', title: 'Re-trigger completions...' };
    

    With the command defined as

    const setCompletionHandler = vscode.commands.registerCommand('folder-operations.setCompletionCommand', async () => {
      await vscode.commands.executeCommand('editor.action.triggerSuggest');
      await vscode.commands.executeCommand('acceptSelectedSuggestion');
    });
    context.subscriptions.push(setCompletionHandler);
    

    If you run that in a FOO.<some extension> or BAR.<ext> or BAS.<ext> it will work as expected. The snippet fileNameBase is resolved before the command is run – the command just selects the top choice.

    snippet choice completions with a working command

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search