Change:
VSCode Version: Code - Insiders 1.8.0-insider (, 2016-12-07T07:05:09.124Z) OS Version: Darwin x64 16.1.0 Steps to Reproduce: ! Enter !
That's a really annoying bug! Not just in .
The TypeScript extension tells the editor to only delete the 2 preceding characters, not the entire word. That might be a problem with the work definition you are using. !
I have extrapolated about snippets to the following piece of code
I think that Typescript needs to be explicit in this case, and provide a range for the completion items. We currently automatically pick up the range from
do you know if this is tracked on TS's side? I want to make sure I have it tracked in the OneNote table appropriately.
I don't think this is an issue on the TypeScript side. The bug was that we were relying on the default VSCode logic for determining what word to replace, and it breaks words that contain or any other non letter or digit characters. The result TypeScript provides to us is correct as far as I know

Discussion:
'use strict'; <del> import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, WorkspaceConfiguration, TextEdit, Range, SnippetString, workspace } from 'vscode'; </del> <ins> import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, WorkspaceConfiguration, TextEdit, Range, SnippetString, workspace, ProviderResult } from 'vscode'; </ins> import { ITypescriptServiceClient } from '../typescriptService';

document: TextDocument; position: Position; <del> constructor(entry: CompletionEntry) { </del> <ins> constructor(position: Position, document: TextDocument, entry: CompletionEntry) { </ins> super(entry.name); this.sortText = entry.sortText; this.kind = MyCompletionItem.convertKind(entry.kind); <ins> this.position = position; this.document = document; </ins> if (entry.replacementSpan) { let span: protocol.TextSpan = entry.replacementSpan; // The indexing for the range returned by the server uses 1-based indexing. // We convert to 0-based indexing. this.textEdit = TextEdit.replace(new Range(span.start.line - 1, span.start.offset - 1, span.end.line - 1, span.end.offset - 1), entry.name); <ins> } else { const text = document.getText(new Range(position.line, Math.max(0, position.character - entry.name.length), position.line, position.character)); for (let i = entry.name.length; i >= 0; --i) { if ((text as any).endsWith(entry.name.substr(0, i))) { this.range = new Range(position.line, Math.max(0, position.character - i), position.line, position.character); break; } } </ins> } }

if (body) { for (let i = 0; i < body.length; i++) { let element = body[i]; <del> let item = new MyCompletionItem(element); item.document = document; item.position = position; </del> <ins> let item = new MyCompletionItem(position, document, element); </ins> completionItems.push(item); } }

}); } <del> public resolveCompletionItem(item: CompletionItem, token: CancellationToken): any | Thenable<any> { </del> <ins> public resolveCompletionItem(item: CompletionItem, token: CancellationToken): ProviderResult<CompletionItem> { </ins> if (item instanceof MyCompletionItem) { const filepath = this.client.asAbsolutePath(item.document.uri); if (!filepath) {