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

Commit

Permalink
Triggering autocompletion in comments if the next item is an exported…
Browse files Browse the repository at this point in the history
… member #1005 (#1675)

* WIP: Initial Logic to fix #1005

* Cleaning Up Logic for fixing #1005 and added test

* Cleaning Up Logic for fixing #1005 and added test

* Cleaning Up Logic for fixing #1005 and added test

* Linting according to tslint

* Added check for last line per review comments

* Merging from upstream

* WIP: Testing autocompletion on comments after refactoring code according to comments

* WIP: Testing autocompletion on comments after refactoring code according to comments

* Reverting Lint Issues

* Made changes to code according to review comments and refactored tests to include test cases

* Refactoring

* Pass suggestion item kind to constructor
  • Loading branch information
Shreyas Karnik authored and ramya-rao-a committed May 15, 2018
1 parent 8bb08f6 commit 82481fe
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 31 deletions.
17 changes: 15 additions & 2 deletions src/goSuggest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ interface GoCodeSuggestion {
type: string;
}

const lineCommentRegex = /^\s*\/\/\s+/;
const exportedMemberRegex = /(const|func|type|var)\s+([A-Z]\w*)/;

export class GoCompletionItemProvider implements vscode.CompletionItemProvider {

private pkgsList = new Map<string, string>();
Expand All @@ -52,7 +55,17 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider {
let lineTillCurrentPosition = lineText.substr(0, position.character);
let autocompleteUnimportedPackages = config['autocompleteUnimportedPackages'] === true && !lineText.match(/^(\s)*(import|package)(\s)+/);

// prevent completion when typing in a line comment
// triggering completions in comments on exported members
if (lineCommentRegex.test(lineTillCurrentPosition) && position.line + 1 < document.lineCount) {
let nextLine = document.lineAt(position.line + 1).text.trim();
let memberType = nextLine.match(exportedMemberRegex);
let suggestionItem: vscode.CompletionItem;
if (memberType && memberType.length === 3) {
suggestionItem = new vscode.CompletionItem(memberType[2], vscodeKindFromGoCodeClass(memberType[1]));
}
return resolve(suggestionItem ? [suggestionItem] : []);
}
// prevent completion when typing in a line comment that doesnt start from the beginning of the line
const commentIndex = lineText.indexOf('//');
if (commentIndex >= 0 && position.character > commentIndex) {
return resolve([]);
Expand Down Expand Up @@ -345,4 +358,4 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider {
return matchingPackages[0];
}
}
}
}
21 changes: 21 additions & 0 deletions test/fixtures/completions/exportedMemberDocs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

import (
"fmt"
)

// L
var Language = "english" // should not invoke completion since this is line comment

// G
const GreetingText = "Hello"

// S
func SayHello() {
fmt.Println("Says hello!")
}

// HelloParams
type HelloParams struct {
language string
}
92 changes: 63 additions & 29 deletions test/go.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ suite('Go Extension Tests', () => {
fs.copySync(path.join(fixtureSourcePath, 'buildTags', 'hello.go'), path.join(fixturePath, 'buildTags', 'hello.go'));
fs.copySync(path.join(fixtureSourcePath, 'completions', 'unimportedPkgs.go'), path.join(fixturePath, 'completions', 'unimportedPkgs.go'));
fs.copySync(path.join(fixtureSourcePath, 'completions', 'snippets.go'), path.join(fixturePath, 'completions', 'snippets.go'));
fs.copySync(path.join(fixtureSourcePath, 'completions', 'exportedMemberDocs.go'), path.join(fixturePath, 'completions', 'exportedMemberDocs.go'));
fs.copySync(path.join(fixtureSourcePath, 'importTest', 'noimports.go'), path.join(fixturePath, 'importTest', 'noimports.go'));
fs.copySync(path.join(fixtureSourcePath, 'importTest', 'groupImports.go'), path.join(fixturePath, 'importTest', 'groupImports.go'));
fs.copySync(path.join(fixtureSourcePath, 'importTest', 'singleImports.go'), path.join(fixturePath, 'importTest', 'singleImports.go'));
Expand Down Expand Up @@ -278,9 +279,9 @@ It returns the number of bytes written and any write error encountered.
for (let i in expected) {
for (let j in sortedDiagnostics) {
if (expected[i].line
&& (expected[i].line === sortedDiagnostics[j].line)
&& (expected[i].severity === sortedDiagnostics[j].severity)
&& (expected[i].msg === sortedDiagnostics[j].msg)) {
&& (expected[i].line === sortedDiagnostics[j].line)
&& (expected[i].severity === sortedDiagnostics[j].severity)
&& (expected[i].msg === sortedDiagnostics[j].msg)) {
matchCount++;
}
}
Expand Down Expand Up @@ -404,8 +405,8 @@ It returns the number of bytes written and any write error encountered.
for (let i in expected) {
for (let j in sortedDiagnostics) {
if ((expected[i].line === sortedDiagnostics[j].line)
&& (expected[i].severity === sortedDiagnostics[j].severity)
&& (expected[i].msg === sortedDiagnostics[j].msg)) {
&& (expected[i].severity === sortedDiagnostics[j].severity)
&& (expected[i].msg === sortedDiagnostics[j].msg)) {
matchCount++;
}
}
Expand Down Expand Up @@ -776,36 +777,36 @@ It returns the number of bytes written and any write error encountered.
vscode.workspace.openTextDocument(uri).then((textDocument) => {
return vscode.window.showTextDocument(textDocument).then(editor => {

let noFunctionSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(9, 6), null, Object.create(baseConfig, {'useCodeSnippetsOnFunctionSuggest': { value: false }})).then(items => {
let item = items.find(x => x.label === 'Print');
assert.equal(!item.insertText, true);
});
let noFunctionSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(9, 6), null, Object.create(baseConfig, { 'useCodeSnippetsOnFunctionSuggest': { value: false } })).then(items => {
let item = items.find(x => x.label === 'Print');
assert.equal(!item.insertText, true);
});

let withFunctionSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(9, 6), null, Object.create(baseConfig, {'useCodeSnippetsOnFunctionSuggest': { value: true }})).then(items => {
let item = items.find(x => x.label === 'Print');
assert.equal((<vscode.SnippetString>item.insertText).value, 'Print(${1:a ...interface{\\}})');
let withFunctionSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(9, 6), null, Object.create(baseConfig, { 'useCodeSnippetsOnFunctionSuggest': { value: true } })).then(items => {
let item = items.find(x => x.label === 'Print');
assert.equal((<vscode.SnippetString>item.insertText).value, 'Print(${1:a ...interface{\\}})');

});
});

let withFunctionSnippetNotype = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(9, 6), null, Object.create(baseConfig, {'useCodeSnippetsOnFunctionSuggestWithoutType': { value: true }})).then(items => {
let item = items.find(x => x.label === 'Print');
assert.equal((<vscode.SnippetString>item.insertText).value, 'Print(${1:a})');
});
let withFunctionSnippetNotype = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(9, 6), null, Object.create(baseConfig, { 'useCodeSnippetsOnFunctionSuggestWithoutType': { value: true } })).then(items => {
let item = items.find(x => x.label === 'Print');
assert.equal((<vscode.SnippetString>item.insertText).value, 'Print(${1:a})');
});

let noFunctionAsVarSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(11, 3), null, Object.create(baseConfig, {'useCodeSnippetsOnFunctionSuggest': { value: false }})).then(items => {
let item = items.find(x => x.label === 'funcAsVariable');
assert.equal(!item.insertText, true);
});
let noFunctionAsVarSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(11, 3), null, Object.create(baseConfig, { 'useCodeSnippetsOnFunctionSuggest': { value: false } })).then(items => {
let item = items.find(x => x.label === 'funcAsVariable');
assert.equal(!item.insertText, true);
});

let withFunctionAsVarSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(11, 3), null, Object.create(baseConfig, {'useCodeSnippetsOnFunctionSuggest': { value: true }})).then(items => {
let item = items.find(x => x.label === 'funcAsVariable');
assert.equal((<vscode.SnippetString>item.insertText).value, 'funcAsVariable(${1:k string})');
});
let withFunctionAsVarSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(11, 3), null, Object.create(baseConfig, { 'useCodeSnippetsOnFunctionSuggest': { value: true } })).then(items => {
let item = items.find(x => x.label === 'funcAsVariable');
assert.equal((<vscode.SnippetString>item.insertText).value, 'funcAsVariable(${1:k string})');
});

let withFunctionAsVarSnippetNoType = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(11, 3), null, Object.create(baseConfig, {'useCodeSnippetsOnFunctionSuggestWithoutType': { value: true }})).then(items => {
let item = items.find(x => x.label === 'funcAsVariable');
assert.equal((<vscode.SnippetString>item.insertText).value, 'funcAsVariable(${1:k})');
});
let withFunctionAsVarSnippetNoType = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(11, 3), null, Object.create(baseConfig, { 'useCodeSnippetsOnFunctionSuggestWithoutType': { value: true } })).then(items => {
let item = items.find(x => x.label === 'funcAsVariable');
assert.equal((<vscode.SnippetString>item.insertText).value, 'funcAsVariable(${1:k})');
});

let noFunctionAsTypeSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(14, 0), null, Object.create(baseConfig, {'useCodeSnippetsOnFunctionSuggest': { value: false }})).then(items => {
let item1 = items.find(x => x.label === 'HandlerFunc');
Expand Down Expand Up @@ -863,6 +864,39 @@ It returns the number of bytes written and any write error encountered.
}).then(() => done(), done);
});

test('Test Completion on Comments for Exported Members', (done) => {
let provider = new GoCompletionItemProvider();
let testCases: [vscode.Position, string[]][] = [
[new vscode.Position(6, 4), ['Language']],
[new vscode.Position(9, 4), ['GreetingText']],
// checking for comment completions with begining of comment without space
[new vscode.Position(12, 2), []],
// cursor between /$/ this should not trigger any completion
[new vscode.Position(12, 1), []],
[new vscode.Position(12, 4), ['SayHello']],
[new vscode.Position(17, 5), ['HelloParams']],
];
let uri = vscode.Uri.file(path.join(fixturePath, 'completions', 'exportedMemberDocs.go'));

vscode.workspace.openTextDocument(uri).then((textDocument) => {
return vscode.window.showTextDocument(textDocument).then(editor => {
let promises = testCases.map(([position, expected]) =>
provider.provideCompletionItems(editor.document, position, null).then(items => {
let labels = items.map(x => x.label);
assert.equal(expected.length, labels.length, `expected number of completions: ${expected.length} Actual: ${labels.length} at position(${position.line},${position.character}) ${labels}`);
expected.forEach((entry, index) => {
assert.equal(entry, labels[index], `mismatch in comment completion list Expected: ${entry} Actual: ${labels[index]}`);
});

})
);
return Promise.all(promises).then(() => vscode.commands.executeCommand('workbench.action.closeActiveEditor'));
});
}, (err) => {
assert.ok(false, `error in OpenTextDocument ${err}`);
}).then(() => done(), done);
});

test('getImportPath()', () => {
let testCases: [string, string][] = [
['import "github.com/sirupsen/logrus"', 'github.com/sirupsen/logrus'],
Expand Down

0 comments on commit 82481fe

Please sign in to comment.