Skip to content

Commit

Permalink
Fixed go-to and outline
Browse files Browse the repository at this point in the history
  • Loading branch information
Zachary Norman committed Aug 28, 2019
1 parent bbc3a9e commit b084beb
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 45 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Auto complete for variables in-file and all routines that have been discovered f

Fix for incorrect syntax highlighting of the control statement `end`

Enhanced (and fixed) go-to definitions for functions, procedures, and methods (procedure and function)

## 1.5.2 - 2019-08-25

Corrected the way to add syntax for IDL + ENVI tasks, ENVI style sheets, and ENVI modeler files.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ For developers, see [CONTRIBUTING.md](./CONTRIBUTING.md) for notes on getting yo

* Function/procedure/variable completion for user defined routines in workspaces and opened files

* Go-to definition for functions and procedures (not methods)
* Go-to definition for functions, procedures, and methods from user defined routines

* Search for procedure/function definitions through symbols

Expand Down
10 changes: 6 additions & 4 deletions server/src/providers/idl-document-symbol-extractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,10 @@ export class IDLDocumentSymbolExtractor {
}


getSelectedWord(line: string, position: Position): string {
getSelectedWord(line: string, position: Position): [string, boolean] {
// placeholder for the name
let symbolName = "";
let functionFlag = false;

// get the character position - move to the left so that we are in a word
// otherwise we are outside a word as we are on the next character
Expand All @@ -274,13 +275,13 @@ export class IDLDocumentSymbolExtractor {

// check if zero, then just try and return the first character
if (useChar === 0) {
return line.substr(0, 1).trim();
return [line.substr(0, 1).trim(), functionFlag];
}
}

// split by words to extract our symbol that we may have clicked on
// TODO: add logic for objects and methods here, func/pro are good for now
const wordRegEx = /[a-z_][a-z0-9:_$]*/gim;
const wordRegEx = /[a-z_][\.a-z0-9:_$\-\>]*/gim;
let m: RegExpExecArray;
while ((m = wordRegEx.exec(line)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
Expand All @@ -297,6 +298,7 @@ export class IDLDocumentSymbolExtractor {
idx + m[i].length > useChar
) {
symbolName = m[i];
functionFlag = line.substr(idx + m[i].length, 1) === '('
break;
}
}
Expand All @@ -306,7 +308,7 @@ export class IDLDocumentSymbolExtractor {
}
}

return symbolName;
return [symbolName, functionFlag];
}


Expand Down
111 changes: 74 additions & 37 deletions server/src/providers/idl-document-symbol-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ export class IDLDocumentSymbolManager {
extractor: IDLDocumentSymbolExtractor;

// Track constants by file and routines by all files we have opened
constantLookup: { [key: string]: CompletionItem[] } = {};
routineLookup: { [key: string]: CompletionItem } = {};
constantCompletionLookup: { [key: string]: CompletionItem[] } = {};
routineCompletionLookup: { [key: string]: CompletionItem } = {};
routineSymbolLookup: { [key: string]: DocumentSymbol } = {};

constructor(connection: Connection, documents: TextDocuments) {
this.connection = connection;
Expand Down Expand Up @@ -114,16 +115,16 @@ export class IDLDocumentSymbolManager {
let items: CompletionItem[] = [];

// get constants for our file
if (uri in this.constantLookup) {
items = this.constantLookup[uri];
if (uri in this.constantCompletionLookup) {
items = this.constantCompletionLookup[uri];
}

// merge with all of our symbols if we have user routines
if (Object.keys(this.routineLookup).length > 0) {
if (Object.keys(this.routineCompletionLookup).length > 0) {
if (items.length === 0) {
items = Object.values(this.routineLookup);
items = Object.values(this.routineCompletionLookup);
} else {
items = items.concat(Object.values(this.routineLookup));
items = items.concat(Object.values(this.routineCompletionLookup));
}
}

Expand Down Expand Up @@ -163,7 +164,7 @@ export class IDLDocumentSymbolManager {
// return items;
}

getSelectedSymbolName(params: TextDocumentPositionParams): string {
getSelectedSymbolName(params: TextDocumentPositionParams): [string, boolean] {
// read the strings from our text document
const line = this._getStrings(params.textDocument.uri).split("\n")[
params.position.line
Expand All @@ -176,7 +177,20 @@ export class IDLDocumentSymbolManager {
// search for symbols by line
searchByLine(params: TextDocumentPositionParams, limit = true): Definition {
// get the highlighted symbol name
const symbolName = this.getSelectedSymbolName(params);
const res = this.getSelectedSymbolName(params);
let symbolName = res[0].toLowerCase();
const functionFlag = res[1];

// check if we need to clean up the name
switch (true) {
case symbolName.includes('.'):
symbolName = '::' + symbolName.split('.')[1]
break;
case symbolName.includes('->'):
symbolName = '::' + symbolName.split('->')[1]
break;
default:// do nothing
}

// create a placeholder to return
let placeholder: Definition = null;
Expand All @@ -189,8 +203,24 @@ export class IDLDocumentSymbolManager {
if (symbols.length > 0) {
// are we limiting results and being strict, or loosey goosey?
if (limit) {
if (symbols[0].name.toLowerCase() === symbolName.toLowerCase()) {
placeholder = symbols[0].location;
switch (true) {
// function method
case symbolName.includes('::') && symbols[0].name.toLowerCase().endsWith(symbolName + '()') && functionFlag:
placeholder = symbols[0].location;
break;
// procedure method
case symbolName.includes('::') && symbols[0].name.toLowerCase().endsWith(symbolName):
placeholder = symbols[0].location;
break;
// function
case symbols[0].name.toLowerCase() === symbolName + '()' && functionFlag:
placeholder = symbols[0].location;
break;
// procedure
case symbols[0].name.toLowerCase() === symbolName:
placeholder = symbols[0].location;
break;
default: // do nothing
}
} else {
placeholder = symbols[0].location;
Expand All @@ -203,19 +233,22 @@ export class IDLDocumentSymbolManager {
// when we remove a document, clean up the symbol lookup information
private _removeSymbols(uri: string, symbols: DocumentSymbol[]) {
// clear constant lookup
delete this.constantLookup[uri]
delete this.constantCompletionLookup[uri]

// process each symbol
symbols.forEach(symbol => {
// get the key
const key = symbol.name.toLowerCase();

// clean up routine lookup for functions and procedures
if (key in this.routineLookup) {
delete this.routineLookup[key]
if (key in this.routineCompletionLookup) {
delete this.routineCompletionLookup[key]
}
if (key + '(' in this.routineCompletionLookup) {
delete this.routineCompletionLookup[key + '(']
}
if (key + '(' in this.routineLookup) {
delete this.routineLookup[key + '(']
if (key in this.routineSymbolLookup) {
delete this.routineSymbolLookup[key]
}

// make sure we have symbols to clean up
Expand Down Expand Up @@ -344,26 +377,30 @@ export class IDLDocumentSymbolManager {

// process all of the symbols that we found
foundSymbols.forEach(symbol => {
// make our symbol lookup information
const info: ISymbolLookup = {
uri: uri,
symbol: symbol
};

// get the key
const key = symbol.name.toLowerCase();

// save in our lookup table
if (this.symbols[key]) {
this.symbols[key].push(info);
} else {
this.symbols[key] = [info];
this.symbolKeys.push(key);
this.symbolKeysSearch.push(fuzzysort.prepare(key));
}

// build the completion item for our symbol if it is not a constant
if (symbol.kind !== SymbolKind.Variable) {
// make our symbol lookup information
const info: ISymbolLookup = {
uri: uri,
symbol: symbol
};

// get the key
const key = symbol.name.toLowerCase();

// save in our lookup table
if (this.symbols[key]) {
this.symbols[key].push(info);
} else {
this.symbols[key] = [info];
this.symbolKeys.push(key);
this.symbolKeysSearch.push(fuzzysort.prepare(key));
}

// save our routine symbol lookup
this.routineSymbolLookup[key] = symbol;

// save compeltion information
const completionItem: CompletionItem = {
label: symbol.name,
kind: resolveCompletionItemKind(symbol.kind)
Expand All @@ -390,14 +427,14 @@ export class IDLDocumentSymbolManager {
completionItem.insertText = replaceName;
}

// save in our routine lookip
this.routineLookup[symbol.name.toLowerCase()] = completionItem;
// save in our routine lookup
this.routineCompletionLookup[key] = completionItem;
}
});

// save any constants that we may have found, but only if we have one by that name
const constantNames = [];
this.constantLookup[uri] = foundSymbols.filter(symbol => {
this.constantCompletionLookup[uri] = foundSymbols.filter(symbol => {
let flag = false;
if (symbol.kind === SymbolKind.Variable) {
const saveName = symbol.name.toLowerCase();
Expand Down
6 changes: 3 additions & 3 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ connection.onCompletion(
// get the word that we are trying to complete
// do this here just so we dont have to split larger files more than once
// because we need the strings, split, and regex to find our work
const query = symbolProvider.getSelectedSymbolName(_textDocumentPosition)
const query = symbolProvider.getSelectedSymbolName(_textDocumentPosition)[0]

// get docs matches
// const start1: any = new Date();
Expand Down Expand Up @@ -253,7 +253,7 @@ connection.onWorkspaceSymbol(
// handle when we want the definition of a symbol
connection.onDefinition(
(params: TextDocumentPositionParams): Definition => {
const res = symbolProvider.searchByLine(params);
const res = symbolProvider.searchByLine(params, true);
return res;
}
);
Expand All @@ -272,7 +272,7 @@ connection.onDocumentSymbol(
): Promise<SymbolInformation[] | DocumentSymbol[]> => {
return (await symbolProvider.get.documentSymbols(
params.textDocument.uri
)).filter(symbol => { return symbol.kind !== SymbolKind.Constant }).map(symbol => {
)).filter(symbol => { return symbol.kind !== SymbolKind.Variable }).map(symbol => {
return {
name: symbol.displayName,
detail: symbol.detail,
Expand Down

0 comments on commit b084beb

Please sign in to comment.