2

I'm creating a vscode extension that requires some custom completion for json files. Is it possible to not show the trigger character when using autocompletions.

Here is what I mean :

Let's say the trigger character is '.' In your json file you type '.' which suggests you a list of items that I defined in the code. When i press tab or enter, the normal behavior would be to display .item (item being the selected item when i pressed enter) Is it possible to only have 'item' and remove the trigger character '.' ?

Here is my code so far :

context.subscriptions.push(languages.registerCompletionItemProvider (
            { language: 'json', scheme: 'file' },
            // 'json',
            {
                provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken, context: CompletionContext) {
        
                let myitem = (text:string) => {
                    let item = new CompletionItem(text, CompletionItemKind.Text);
                    item.range = new Range(position, position);
                    return item;
                };

                const linePrefix = document.lineAt(position).text.substring(0, position.character);
                if (linePrefix.match(/name/g)) {
                    return [
                        myitem('log'),
                        myitem('warn'),
                        myitem('error'),
                        ];
                } else {
                    return undefined;
                }
            }
            },
            '?' // trigger
        ));
Witaek
  • 33
  • 4
  • See https://stackoverflow.com/a/66407855/836330 - although a modified version of that isn't working for me yet, – Mark Jul 07 '22 at 18:20

1 Answers1

2

In general the trigger characters would be removed automatically but I believe because your trigger character ? is a non-word character (at least in json files) that vscode returns undefined when trying to get the wordRangeAtPosition(position) and so does not replace the trigger character.

So you will have to take matters into your hands. One way is to get the wordRangeAtPosition() using a custom regex that includes ?. And then use that range in the CompletionItem.range.

After playing around unsuccessfully trying to set the range to a value that would include and thus replace that ? like the link in my comment above, I found success with a different method. Thanks to https://github.com/microsoft/vscode/issues/75237

Try adding this to your CompletionItems:

let myitem = (text) => {
    let item = new vscode.CompletionItem(text, vscode.CompletionItemKind.Text);
    // item.range = new vscode.Range(position, position);

    const rangeToRemove = new vscode.Range(position.line, position.character-1, position.line, position.character);
    item.additionalTextEdits = [vscode.TextEdit.delete(rangeToRemove)];

    return item;
};

In my testing with the code above you do not need the following line since you will be using the default:

item.range = new Range(position, position);

{I showed the non-typescript version with vscode. added to the calls for general use.]

Mark
  • 143,421
  • 24
  • 428
  • 436
  • Thanks ! Addind the two lines to my `CompletionItems` seems to do the work just fine. However, if I delete the item.range line as you suggest, it doesn't work anymore. – Witaek Jul 08 '22 at 07:46
  • 1
    I tried it again and I do not need the `item.range` line. I edited the answer to show what I am using to create `myItem`. – Mark Jul 08 '22 at 21:26