Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Commit

Permalink
add auto completions to typescript / javascript
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesbirtles committed May 5, 2019
1 parent 35c0981 commit fc0a237
Show file tree
Hide file tree
Showing 9 changed files with 746 additions and 685 deletions.
674 changes: 0 additions & 674 deletions package-lock.json

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"prettier": "1.17.0",
"sinon": "^4.5.0",
"source-map": "^0.7.3",
"svelte": "3.1.0",
"svelte": "3.2.0",
"typescript": "3.4.5",
"vscode-css-languageservice": "3.0.13",
"vscode-emmet-helper": "1.2.15",
Expand Down
6 changes: 5 additions & 1 deletion src/api/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ export namespace HoverProvider {
}

export interface CompletionsProvider {
getCompletions(document: Document, position: Position): Resolvable<CompletionItem[]>;
getCompletions(
document: Document,
position: Position,
triggerCharacter?: string,
): Resolvable<CompletionItem[]>;
}

export namespace CompletionsProvider {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/documents/DocumentManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export class DocumentManager extends PluginHost {
async getCompletions(
textDocument: TextDocumentIdentifier,
position: Position,
triggerCharacter?: string,
): Promise<CompletionItem[]> {
const document = this.documents.get(textDocument.uri);
if (!document) {
Expand All @@ -123,7 +124,7 @@ export class DocumentManager extends PluginHost {
return flatten(
await this.execute<CompletionItem[]>(
'getCompletions',
[document, position],
[document, position, triggerCharacter],
ExecuteMode.Collect,
),
);
Expand Down
45 changes: 42 additions & 3 deletions src/plugins/TypeScriptPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ import {
Host,
DocumentSymbolsProvider,
SymbolInformation,
SymbolKind,
CompletionsProvider,
CompletionItem,
} from '../api';
import {
convertRange,
getScriptKindFromAttributes,
symbolKindFromString,
scriptElementKindToCompletionItemKind,
getCommitCharactersForScriptElement,
} from './typescript/utils';
import { getLanguageServiceForDocument, CreateDocument } from './typescript/service';

Expand All @@ -34,7 +37,8 @@ export class TypeScriptPlugin
HoverProvider,
FormattingProvider,
OnRegister,
DocumentSymbolsProvider {
DocumentSymbolsProvider,
CompletionsProvider {
public static matchFragment(fragment: Fragment) {
return fragment.details.attributes.tag == 'script';
}
Expand All @@ -58,7 +62,7 @@ export class TypeScriptPlugin
languageId: '',
text: content,
uri,
version: 1,
version: 0,
});
host.lockDocument(uri);
return document;
Expand Down Expand Up @@ -177,6 +181,41 @@ export class TypeScriptPlugin
}
}
}

getCompletions(
document: Document,
position: Position,
triggerCharacter?: string,
): CompletionItem[] {
if (!this.host.getConfig<boolean>('typescript.completions.enable')) {
return [];
}

const lang = getLanguageServiceForDocument(document, this.createDocument);
const completions = lang.getCompletionsAtPosition(
document.getFilePath()!,
document.offsetAt(position),
{
includeCompletionsForModuleExports: true,
triggerCharacter: triggerCharacter as any,
},
);
console.log(completions);

if (!completions) {
return [];
}

return completions!.entries.map(comp => {
return <CompletionItem>{
label: comp.name,
kind: scriptElementKindToCompletionItemKind(comp.kind),
sortText: comp.sortText,
commitCharacters: getCommitCharactersForScriptElement(comp.kind),
preselect: comp.isRecommended,
};
});
}
}

function getParserFromAttributes(attrs: Record<string, string>): prettier.BuiltInParserName {
Expand Down
81 changes: 80 additions & 1 deletion src/plugins/typescript/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ts from 'typescript';
import { Document, Range, SymbolKind } from '../../api';
import { Document, Range, SymbolKind, CompletionItemKind } from '../../api';

export function getScriptKindFromFileName(fileName: string): ts.ScriptKind {
const ext = fileName.substr(fileName.lastIndexOf('.'));
Expand Down Expand Up @@ -95,3 +95,82 @@ export function symbolKindFromString(kind: string): SymbolKind {
return SymbolKind.Variable;
}
}

export function scriptElementKindToCompletionItemKind(
kind: ts.ScriptElementKind,
): CompletionItemKind {
switch (kind) {
case ts.ScriptElementKind.primitiveType:
case ts.ScriptElementKind.keyword:
return CompletionItemKind.Keyword;
case ts.ScriptElementKind.constElement:
return CompletionItemKind.Constant;
case ts.ScriptElementKind.letElement:
case ts.ScriptElementKind.variableElement:
case ts.ScriptElementKind.localVariableElement:
case ts.ScriptElementKind.alias:
return CompletionItemKind.Variable;
case ts.ScriptElementKind.memberVariableElement:
case ts.ScriptElementKind.memberGetAccessorElement:
case ts.ScriptElementKind.memberSetAccessorElement:
return CompletionItemKind.Field;
case ts.ScriptElementKind.functionElement:
return CompletionItemKind.Function;
case ts.ScriptElementKind.memberFunctionElement:
case ts.ScriptElementKind.constructSignatureElement:
case ts.ScriptElementKind.callSignatureElement:
case ts.ScriptElementKind.indexSignatureElement:
return CompletionItemKind.Method;
case ts.ScriptElementKind.enumElement:
return CompletionItemKind.Enum;
case ts.ScriptElementKind.moduleElement:
case ts.ScriptElementKind.externalModuleName:
return CompletionItemKind.Module;
case ts.ScriptElementKind.classElement:
case ts.ScriptElementKind.typeElement:
return CompletionItemKind.Class;
case ts.ScriptElementKind.interfaceElement:
return CompletionItemKind.Interface;
case ts.ScriptElementKind.warning:
case ts.ScriptElementKind.scriptElement:
return CompletionItemKind.File;
case ts.ScriptElementKind.directory:
return CompletionItemKind.Folder;
case ts.ScriptElementKind.string:
return CompletionItemKind.Constant;
}
return CompletionItemKind.Property;
}

export function getCommitCharactersForScriptElement(
kind: ts.ScriptElementKind,
): string[] | undefined {
const commitCharacters: string[] = [];
switch (kind) {
case ts.ScriptElementKind.memberGetAccessorElement:
case ts.ScriptElementKind.memberSetAccessorElement:
case ts.ScriptElementKind.constructSignatureElement:
case ts.ScriptElementKind.callSignatureElement:
case ts.ScriptElementKind.indexSignatureElement:
case ts.ScriptElementKind.enumElement:
case ts.ScriptElementKind.interfaceElement:
commitCharacters.push('.');
break;

case ts.ScriptElementKind.moduleElement:
case ts.ScriptElementKind.alias:
case ts.ScriptElementKind.constElement:
case ts.ScriptElementKind.letElement:
case ts.ScriptElementKind.variableElement:
case ts.ScriptElementKind.localVariableElement:
case ts.ScriptElementKind.memberVariableElement:
case ts.ScriptElementKind.classElement:
case ts.ScriptElementKind.functionElement:
case ts.ScriptElementKind.memberFunctionElement:
commitCharacters.push('.', ',');
commitCharacters.push('(');
break;
}

return commitCharacters.length === 0 ? undefined : commitCharacters;
}
10 changes: 8 additions & 2 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export function startServer() {
},
hoverProvider: manager.supports('doHover'),
completionProvider: {
triggerCharacters: ['<'],
triggerCharacters: ['.', '"', "'", '`', '/', '@', '<'],
},
documentFormattingProvider: true,
colorProvider: true,
Expand All @@ -68,7 +68,13 @@ export function startServer() {
manager.updateDocument(evt.textDocument, evt.contentChanges),
);
connection.onHover(evt => manager.doHover(evt.textDocument, evt.position));
connection.onCompletion(evt => manager.getCompletions(evt.textDocument, evt.position));
connection.onCompletion(evt =>
manager.getCompletions(
evt.textDocument,
evt.position,
evt.context && evt.context.triggerCharacter,
),
);
connection.onDocumentFormatting(evt => manager.formatDocument(evt.textDocument));
connection.onRequest(TagCloseRequest.type, evt =>
manager.doTagComplete(evt.textDocument, evt.position),
Expand Down
4 changes: 2 additions & 2 deletions test/lib/documents/DocumentManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ describe('Document Manager', () => {
const document = manager.openDocument(textDocument);

const pos = Position.create(0, 0);
await manager.getCompletions(textDocument, pos);
await manager.getCompletions(textDocument, pos, '.');

sinon.assert.calledOnce(plugin.getCompletions);
sinon.assert.calledWithExactly(plugin.getCompletions, document, pos);
sinon.assert.calledWithExactly(plugin.getCompletions, document, pos, '.');
});
});
Loading

0 comments on commit fc0a237

Please sign in to comment.