Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Don't count signature position changes inside string literals #1738

Merged
merged 9 commits into from
Feb 20, 2019
78 changes: 38 additions & 40 deletions src/goSignature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,27 @@
import vscode = require('vscode');
import { SignatureHelpProvider, SignatureHelp, SignatureInformation, ParameterInformation, TextDocument, Position, CancellationToken, WorkspaceConfiguration } from 'vscode';
import { definitionLocation } from './goDeclaration';
import { getParametersAndReturnType } from './util';
import { getParametersAndReturnType, isPositionInString } from './util';

export class GoSignatureHelpProvider implements SignatureHelpProvider {
private goConfig: WorkspaceConfiguration = null;

constructor(goConfig?: WorkspaceConfiguration) {
this.goConfig = goConfig;
constructor(private goConfig?: WorkspaceConfiguration) {
}

public provideSignatureHelp(document: TextDocument, position: Position, token: CancellationToken): Promise<SignatureHelp> {
if (!this.goConfig) {
this.goConfig = vscode.workspace.getConfiguration('go', document.uri);
}
public async provideSignatureHelp(document: TextDocument, position: Position, token: CancellationToken): Promise<SignatureHelp> {
let goConfig = this.goConfig || vscode.workspace.getConfiguration('go', document.uri);

let theCall = this.walkBackwardsToBeginningOfCall(document, position);
const theCall = this.walkBackwardsToBeginningOfCall(document, position);
if (theCall == null) {
return Promise.resolve(null);
}
let callerPos = this.previousTokenPosition(document, theCall.openParen);
const callerPos = this.previousTokenPosition(document, theCall.openParen);
// Temporary fix to fall back to godoc if guru is the set docsTool
let goConfig = this.goConfig;
if (goConfig['docsTool'] === 'guru') {
goConfig = Object.assign({}, goConfig, { 'docsTool': 'godoc' });
}
return definitionLocation(document, callerPos, goConfig, true, token).then(res => {
try {
const res = await definitionLocation(document, callerPos, goConfig, true, token);
if (!res) {
// The definition was not found
return null;
Expand All @@ -45,37 +41,36 @@ export class GoSignatureHelpProvider implements SignatureHelpProvider {
if (!declarationText) {
return null;
}
let result = new SignatureHelp();
const result = new SignatureHelp();
let sig: string;
let si: SignatureInformation;
if (res.toolUsed === 'godef') {
// declaration is of the form "Add func(a int, b int) int"
let nameEnd = declarationText.indexOf(' ');
let sigStart = nameEnd + 5; // ' func'
let funcName = declarationText.substring(0, nameEnd);
const nameEnd = declarationText.indexOf(' ');
const sigStart = nameEnd + 5; // ' func'
const funcName = declarationText.substring(0, nameEnd);
sig = declarationText.substring(sigStart);
si = new SignatureInformation(funcName + sig, res.doc);
} else if (res.toolUsed === 'gogetdoc') {
}
else if (res.toolUsed === 'gogetdoc') {
// declaration is of the form "func Add(a int, b int) int"
declarationText = declarationText.substring(5);
let funcNameStart = declarationText.indexOf(res.name + '('); // Find 'functionname(' to remove anything before it
const funcNameStart = declarationText.indexOf(res.name + '('); // Find 'functionname(' to remove anything before it
if (funcNameStart > 0) {
declarationText = declarationText.substring(funcNameStart);
}
si = new SignatureInformation(declarationText, res.doc);
sig = declarationText.substring(res.name.length);
}

si.parameters = getParametersAndReturnType(sig).params.map(paramText =>
new ParameterInformation(paramText)
);
si.parameters = getParametersAndReturnType(sig).params.map(paramText => new ParameterInformation(paramText));
result.signatures = [si];
result.activeSignature = 0;
result.activeParameter = Math.min(theCall.commas.length, si.parameters.length - 1);
return result;
}, () => {
}
catch (e) {
return null;
});
}
}

private previousTokenPosition(document: TextDocument, position: Position): Position {
Expand All @@ -89,42 +84,45 @@ export class GoSignatureHelpProvider implements SignatureHelpProvider {
return null;
}

private walkBackwardsToBeginningOfCall(document: TextDocument, position: Position): { openParen: Position, commas: Position[] } {
/**
* Goes through the function params' lines and gets the number of commas and the start position of the call.
*/
private walkBackwardsToBeginningOfCall(document: TextDocument, position: Position): { openParen: Position, commas: Position[] } | null {
let parenBalance = 0;
let commas = [];
let maxLookupLines = 30;
const commas = [];

for (let line = position.line; line >= 0 && maxLookupLines >= 0; line--, maxLookupLines--) {
let currentLine = document.lineAt(line).text;
let characterPosition = document.lineAt(line).text.length - 1;
for (let lineNr = position.line; lineNr >= 0 && maxLookupLines >= 0; lineNr-- , maxLookupLines--) {

if (line === position.line) {
characterPosition = position.character;
currentLine = currentLine.substring(0, position.character);
}
const line = document.lineAt(lineNr);
// if its current line, get the text until the position given, otherwise get the full line.
const [currentLine, characterPosition] = lineNr === position.line
? [line.text.substring(0, position.character), position.character]
: [line.text, line.text.length - 1];

for (let char = characterPosition; char >= 0; char--) {
for (let char = characterPosition - 1; char >= 0; char--) {
switch (currentLine[char]) {
case '(':
parenBalance--;
if (parenBalance < 0) {
return {
openParen: new Position(line, char),
commas: commas
openParen: new Position(lineNr, char),
commas
};
}
break;
case ')':
parenBalance++;
break;
case ',':
if (parenBalance === 0) {
commas.push(new Position(line, char));
const commaPos = new Position(lineNr, char);
if ((parenBalance === 0) && !isPositionInString(document, commaPos)) {
commas.push(commaPos);
}
break;
}
}
}
return null;
}

}
}