import * as vscode from 'vscode'; import {latex_types} from '../dictionary/symbol_types'; import text_symbols from '../dictionary/text_symbols'; import math_symbols from '../dictionary/math_symbols'; import package_symbols from '../dictionary/package_symbols'; import environment_symbols from '../dictionary/environment_symbols'; import tikz_symbols from '../dictionary/tikz_symbols'; import parameter_dictionary from '../dictionary/parameter_dictionary'; function convertToItemKind(type: latex_types): vscode.CompletionItemKind { if (latex_types.symbol) { return vscode.CompletionItemKind.Variable; } else if (latex_types.function) { return vscode.CompletionItemKind.Function; } else if (latex_types.environment) { return vscode.CompletionItemKind.Interface; } else if (latex_types.package) { return vscode.CompletionItemKind.Module; } else if (latex_types.keyword) { return vscode.CompletionItemKind.Keyword; } else if (latex_types.parameter) { return vscode.CompletionItemKind.Value; } else if (latex_types.snippet) { return vscode.CompletionItemKind.Snippet; } return vscode.CompletionItemKind.Property; } function fillSymbols(symbolsCollection: vscode.CompletionItem[], symbolsDefinition: Object): void { for (var key in symbolsDefinition) { var sym_def = symbolsDefinition[key]; var item = new vscode.CompletionItem(key, convertToItemKind(sym_def.kind)); if (sym_def.detail) { item.detail = sym_def.detail; } if (sym_def.documentation) { item.documentation = sym_def.documentation; } if (sym_def.insertText) { if (sym_def.insertText.indexOf("$") > -1) { item.insertText = new vscode.SnippetString(sym_def.insertText); } else { item.insertText = sym_def.insertText; } } symbolsCollection.push(item); } } export default class Provider implements vscode.CompletionItemProvider { // protected name: string; private text_symbols: vscode.CompletionItem[]; private math_symbols: vscode.CompletionItem[]; private package_symbols: vscode.CompletionItem[]; private environment_symbols: vscode.CompletionItem[]; private tikz_symbols: vscode.CompletionItem[]; private parameter_dictionary: Object; constructor() { // initialize Collections this.text_symbols = new Array(); this.math_symbols = new Array(); this.package_symbols = new Array(); this.environment_symbols = new Array(); this.tikz_symbols = new Array(); // fill the collections from the LaTeX symbols definitions fillSymbols(this.text_symbols, text_symbols); fillSymbols(this.math_symbols, math_symbols); fillSymbols(this.package_symbols, package_symbols); fillSymbols(this.environment_symbols, environment_symbols); fillSymbols(this.tikz_symbols, tikz_symbols); this.parameter_dictionary = parameter_dictionary; } dispose() { } private isInlinemath(line: string, position: vscode.Position): boolean { var count = 0; for (var i = 0; i < line.length; i++) { if (line[i] === "$") { count++; } } return count % 2 ? true : false; } private getEnvironmentType(document: vscode.TextDocument, position: vscode.Position): string { var line = document.lineAt(position); if (line.isEmptyOrWhitespace ? false : this.isInlinemath(line.text.substring(0, position.character), position)) { return "math"; } var environment_references = { "displaymath": "math", "equation": "math", "eqnarray": "math", "align": "math", "align*": "math", "multline": "math", "multline*": "math", "gather": "math", "gather*": "math", "split": "math", "split*": "math", "tikzpicture": "tikz" }; var begin_index = -1; var end_index = -1; var environment; for (var i = position.line; i >= 0; i--) { // iterate over lines from the current line (position) to the top of he document line = document.lineAt(i); // get line with linenumber i (0 based) if (line.isEmptyOrWhitespace) { continue; } // consistency check var line_text = line.text; // get the current line as string while (line_text.length > 6) { // More then "\\end{" and "}" characters are neccessary for a usefull accessment begin_index = line_text.lastIndexOf("\\begin{"); end_index = line_text.lastIndexOf("\\end{"); if (begin_index > end_index) { let environment = line_text.substring(begin_index + 7, line_text.indexOf("}", begin_index + 7)); if (environment_references.hasOwnProperty(environment)) { return environment_references[environment]; } } else if (end_index > begin_index) { let environment = line_text.substring(end_index + 5, line_text.indexOf("}", end_index + 5)); if (environment_references.hasOwnProperty(environment)) { return null; } } else { break; } line_text = line_text.substring(0, begin_index > end_index ? begin_index : end_index); } } return null; } private searchAndCreateParameterSymbols(line_before_pos: string): vscode.CompletionItem[] { for (var key in this.parameter_dictionary) { if (line_before_pos.endsWith(key)) { var completionItems = new Array(); fillSymbols(completionItems, this.parameter_dictionary[key]); return completionItems; } } return []; } /** * @param symbol_label NOT Used * @param position NOT Used */ private searchAndCreateLableSymbols(document: vscode.TextDocument, symbol_label: string, position: vscode.Position): vscode.CompletionItem[] { var completionItems = new Array(); for (var i = 0; i < document.lineCount; i++) { var line = document.lineAt(i); if (line.isEmptyOrWhitespace) { continue; } var line_text = line.text; var index_start = line_text.indexOf("\\label{") + 7; // add 7 to considure the length of "\label{" if (index_start > 6) { // index_start returns > -1 iff substring was found, adding 7 => 6 var index_end = line_text.indexOf("}", index_start); if (index_end > -1) { completionItems.push(new vscode.CompletionItem( line_text.substring(index_start, index_end), // label vscode.CompletionItemKind.Reference // kind )); } } } return completionItems; } private filterSymbols(symbolsCollection: vscode.CompletionItem[], match: string, position: vscode.Position): vscode.CompletionItem[] { var filtert_symbols = new Array(); var range = new vscode.Range(new vscode.Position(position.line, position.character - match.length), position); for (var i = 0; i < symbolsCollection.length; i++) { var item = symbolsCollection[i]; var clonedItem; if (item.label.includes(match)) { clonedItem = new vscode.CompletionItem(item.label, item.kind); if (item.documentation) { clonedItem.documentation = item.documentation; } if (item.insertText) { clonedItem.insertText = item.insertText; } clonedItem.range = range; clonedItem.filterText = match; clonedItem.sortText = item.label.indexOf(match) + item.label; filtert_symbols.push(clonedItem); } } return filtert_symbols; } // private categoriesAndFilterSymbols(document: vscode.TextDocument, line: string, position: vscode.Position): vscode.CompletionItem[] { // var index; // if ((index = line.lastIndexOf("\\")) > -1) { // line = line.substring(index + 1, position.character); // if (line.startsWith("begin{")) { // return this.filterSymbols(this.environment_symbols, line.substring(6, line.length), position); // } else if (line.startsWith("end{")) { // return this.filterSymbols(this.environment_symbols, line.substring(4, line.length), position); // } else { // switch (this.getEnvironmentType(document, position)) { // case "math": // return this.filterSymbols(this.math_symbols, line, position); // case "tikz": // return this.filterSymbols(this.tikz_symbols, line, position); // default: // return this.filterSymbols(this.text_symbols, line, position); // } // } // } // return []; // } provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken) : vscode.CompletionItem[] { var line = document.lineAt(position); if (line.isEmptyOrWhitespace) { return []; } var line_text = line.text; var line_before_pos = line_text.substring(0, position.character).trim(); // if (line_before_pos.endsWith("\\")) { // if (this.isInlinemath(line_before_pos, position)) { // return this.math_symbols; // } else { // switch (this.getEnvironmentType(document, position)) { // case "math": // return this.math_symbols; // case "tikz": // return this.tikz_symbols; // default: // return this.text_symbols; // } // } // } else if (line_before_pos.endsWith("{")) { // if (line_before_pos.endsWith("\\begin{") || line_before_pos.endsWith("\\end{")) { // return this.environment_symbols; // } else if (line_before_pos.endsWith("\\usepackage{")) { // get package names for usepackage function // return this.package_symbols; // } else if (line_before_pos.endsWith("\\ref{") || line_before_pos.endsWith("\\eqref{") || line_before_pos.endsWith("\\pageref{")) { // return searchAndCreateLableSymbols(document); // } // } else if (line_before_pos.endsWith("[")) { // return this.searchAndCreateParameterSymbols(line_before_pos.substring(0, line_before_pos.length - 1)); // } else { // return this.categoriesAndFilterSymbols(document, line_before_pos, position); // } var start_index: number; var end_index: number; var symbol_label: string; if ((start_index = line_before_pos.lastIndexOf("\\") + 1) > 0) { if ((end_index = line_before_pos.indexOf("{", start_index)) > -1) { symbol_label = line_before_pos.substring(start_index, end_index - 1); switch (symbol_label) { case "begin": case "end": return this.filterSymbols(this.environment_symbols, symbol_label, position); case "ref": case "eqref": case "pageref": return this.searchAndCreateLableSymbols(document, symbol_label, position); case "usepackage": return this.filterSymbols(this.package_symbols, symbol_label, position); default: switch (this.getEnvironmentType(document, position)) { case "math": return this.filterSymbols(this.math_symbols, symbol_label, position); case "tikz": return this.filterSymbols(this.tikz_symbols, symbol_label, position); default: return this.filterSymbols(this.text_symbols, symbol_label, position); } } // if (line_before_pos.startsWith("begin{")) { // } else if (line_before_pos.startsWith("end{")) { // return this.filterSymbols(this.environment_symbols, line_before_pos.substring(4, line_before_pos.length), position); // } else if (line_before_pos.endsWith("ref{") || line_before_pos.endsWith("eqref{") || line_before_pos.endsWith("pageref{")) { // } // } else if ((end_index = line_before_pos.indexOf("[")) > -1) { // return []; // } // else { // switch (this.getEnvironmentType(document, position)) { // case "math": // return this.filterSymbols(this.math_symbols, line_before_pos, position); // case "tikz": // return this.filterSymbols(this.tikz_symbols, line_before_pos, position); // default: // return this.filterSymbols(this.text_symbols, line_before_pos, position); // } } } return []; } }