diff --git a/src/completion.ts b/src/completion.ts index 12a58bb..df7313e 100644 --- a/src/completion.ts +++ b/src/completion.ts @@ -7,64 +7,31 @@ import * as vscode from 'vscode'; +/** + * Texinfo language completion item provider. + */ export class CompletionItemProvider implements vscode.CompletionItemProvider { - private readonly completionItems: vscode.CompletionItem[] = [ - { - label: 'header', - kind: vscode.CompletionItemKind.Snippet, - detail: 'Start/end of header', - sortText: 'c1', - filterText: 'c', - insertText: 'c %**', - }, - { - label: '@setfilename', - kind: vscode.CompletionItemKind.Function, - detail: 'Set output file name', - sortText: 'setfilename', - filterText: 'setfilename', - insertText: 'setfilename ', - }, - { - label: '@settitle', - kind: vscode.CompletionItemKind.Function, - detail: 'Set document title', - sortText: 'settitle', - filterText: 'settitle', - insertText: 'settitle ', - }, - { - label: '@copying', - kind: vscode.CompletionItemKind.Function, - detail: 'declare copying permissions', - sortText: 'copying1', - filterText: 'copying', - insertText: 'copying', - }, - { - label: 'copying', - kind: vscode.CompletionItemKind.Snippet, - detail: 'declare copying permissions', - sortText: 'copying0', - filterText: 'copying', - insertText: new vscode.SnippetString('copying\n$1\n@end copying\n'), - }, - { - label: '@copyright', - kind: vscode.CompletionItemKind.Function, - detail: 'The \'©\' symbol', - sortText: 'copyright', - filterText: 'copyright', - insertText: 'copyright{} ' - }, + private readonly completionItems = [ + command('c', 'Line comment'), + snippet('header', 'c', 'Declare header block', 1, + '@c %**start of header\n\n@c %**end of header', + 'c %**${1:start of header}\n$2\n@c %**${3:end of header}'), + command('setfilename', 'Set output file name'), + command('settitle', 'Set document title'), + command('copying', 'Declare copying permissions', { sortOrder: 1 }), + blockSnippet('copying', 'Declare copying permissions'), + command('copyright', 'The \'©\' symbol', { hasEmptyArguments: true }), + command('insertcopying', 'Include permissions text'), + command('titlepage', 'Declare title page', { sortOrder: 1 }), + blockSnippet('titlepage', 'Declare title page'), ]; provideCompletionItems( document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, - context: vscode.CompletionContext + context: vscode.CompletionContext, ) { if (context.triggerKind === vscode.CompletionTriggerKind.Invoke) { const wordRange = document.getWordRangeAtPosition(position); @@ -73,12 +40,10 @@ export class CompletionItemProvider implements vscode.CompletionItemProvider { } position = wordRange.start; if (document.getText(new vscode.Range(position.translate(0, -1), position)) !== '@') { - // Current word is not a command. return undefined; } } if (position.character === 1) { - // Start of line. return this.completionItems; } if (document.getText(new vscode.Range(position.translate(0, -2), position.translate(0, -1))) === '@') { @@ -89,3 +54,72 @@ export class CompletionItemProvider implements vscode.CompletionItemProvider { } } } + +/** + * Build the completion item for a Texinfo command. + * + * @param name The command name. + * @param detail The command description. + * @param extraArgs Extra arguments. + */ +function command(name: string, detail: string, extraArgs?: { + /** + * Sort order for this completion item when names collide. + */ + sortOrder?: number, + /** + * Whether this command takes no arguments and braces are required. + */ + hasEmptyArguments?: boolean, +}): vscode.CompletionItem { + return { + label: '@' + name, + kind: vscode.CompletionItemKind.Function, + detail: detail, + sortText: name + extraArgs?.sortOrder?.toString() ?? '', + filterText: name, + insertText: name + extraArgs?.hasEmptyArguments ? '{}' : '', + } +} + +function blockSnippet(name: string, detail: string): vscode.CompletionItem { + return snippet(name, name, detail, 0, `@${name}\n\n@end ${name}`, `${name}\n$1\n@end ${name}`); +} + +/** + * Build the completion item for a generic snippet. + * + * @param label The string showing up in the completion list. + * @param keyword The word typed by the user. + * @param detail The snippet description. + * @param sortOrder Sort order for this completion item when names collide. + * @param documentation The Markdown documentation for this snippet. + * @param insertText The text to replace current word when the item is selected. + */ +function snippet( + label: string, + keyword: string, + detail: string, + sortOrder: number, + documentation: string, + insertText: string, +): vscode.CompletionItem { + return { + label: label, + kind: vscode.CompletionItemKind.Snippet, + detail: detail + ' (snippet)', + documentation: snippetDocumentation(documentation), + sortText: keyword + sortOrder.toString(), + filterText: keyword, + insertText: new vscode.SnippetString(insertText), + } +} + +/** + * Wraps Texinfo snippet code into a Markdown code block for documentation. + * + * @param snippet The snippet code + */ +function snippetDocumentation(snippet: string) { + return new vscode.MarkdownString(`\`\`\`texinfo\n${snippet}\n\`\`\``); +} diff --git a/tsconfig.json b/tsconfig.json index 0e511c5..1de245a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,10 @@ { "compilerOptions": { "module": "commonjs", - "target": "es6", + "target": "ES2019", "outDir": "out", "lib": [ - "es6" + "ES2019" ], "sourceMap": true, "rootDir": "src",