forked from microsoft/vscode-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgoSignature.ts
executable file
·90 lines (83 loc) · 3.18 KB
/
goSignature.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import cp = require('child_process');
import path = require('path');
import { getBinPath } from './goPath';
import { languages, window, commands, SignatureHelpProvider, SignatureHelp, SignatureInformation, ParameterInformation, TextDocument, Position, Range, CancellationToken } from 'vscode';
import { definitionLocation } from './goDeclaration';
import { parameters } from './util';
export class GoSignatureHelpProvider implements SignatureHelpProvider {
public provideSignatureHelp(document: TextDocument, position: Position, token: CancellationToken): Promise<SignatureHelp> {
let theCall = this.walkBackwardsToBeginningOfCall(document, position);
if (theCall == null) {
return Promise.resolve(null);
}
let callerPos = this.previousTokenPosition(document, theCall.openParen);
return definitionLocation(document, callerPos).then(res => {
if (!res) {
// The definition was not found
return null;
}
if (res.line === callerPos.line) {
// This must be a function definition
return null;
}
let result = new SignatureHelp();
let decl = res.info.decl.substring(5); // 'func '
let cutIndex = decl.indexOf(res.info.name + '('); // Find 'functionname(' to remove anything before it
if (cutIndex !== -1) {
cutIndex += res.info.name.length; // no need to +1 for the (
} else {
cutIndex = res.info.name.length; // try to do our best
}
let sig = decl.substring(cutIndex); // Remove the func name
let si = new SignatureInformation(decl, res.info.doc);
si.parameters = parameters(sig).map(paramText =>
new ParameterInformation(paramText)
);
result.signatures = [si];
result.activeSignature = 0;
result.activeParameter = Math.min(theCall.commas.length, si.parameters.length - 1);
return result;
});
}
protected previousTokenPosition(document: TextDocument, position: Position): Position {
while (position.character > 0) {
let word = document.getWordRangeAtPosition(position);
if (word) {
return word.start;
}
position = position.translate(0, -1);
}
return null;
}
protected walkBackwardsToBeginningOfCall(document: TextDocument, position: Position): { openParen: Position, commas: Position[] } {
let currentLine = document.lineAt(position.line).text.substring(0, position.character);
let parenBalance = 0;
let commas = [];
for (let char = position.character; char >= 0; char--) {
switch (currentLine[char]) {
case '(':
parenBalance--;
if (parenBalance < 0) {
return {
openParen: new Position(position.line, char),
commas: commas
};
}
break;
case ')':
parenBalance++;
break;
case ',':
if (parenBalance === 0) {
commas.push(new Position(position.line, char));
}
}
}
return null;
}
}