VSCode_LaTeX/src/completionItemProvider.ts

290 lines
14 KiB
TypeScript

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<vscode.CompletionItem>();
this.math_symbols = new Array<vscode.CompletionItem>();
this.package_symbols = new Array<vscode.CompletionItem>();
this.environment_symbols = new Array<vscode.CompletionItem>();
this.tikz_symbols = new Array<vscode.CompletionItem>();
// 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<vscode.CompletionItem>();
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<vscode.CompletionItem>();
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<vscode.CompletionItem>();
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 [];
}
}