From b5b8970c67c183a111a03cfdde93d15c75317092 Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Thu, 10 May 2018 22:01:14 -0700 Subject: [PATCH 01/13] WIP: Initial Logic to fix #1005 --- src/goSuggest.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/goSuggest.ts b/src/goSuggest.ts index d67039d12..9ba974ccd 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -53,7 +53,11 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { let autocompleteUnimportedPackages = config['autocompleteUnimportedPackages'] === true && !lineText.match(/^(\s)*(import|package)(\s)+/); if (lineText.match(/^\s*\/\//)) { - return resolve([]); + let nextLine = document.lineAt(position.line + 1).text; + let part0 = nextLine.split(" "); + if (!part0[1].match(/^[A-Z]/)) { + return resolve([]); + } } let inString = isPositionInString(document, position); From a0785467a059de326ca485a66c139398a6b91f7b Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Sat, 12 May 2018 15:08:30 -0700 Subject: [PATCH 02/13] Cleaning Up Logic for fixing #1005 and added test --- src/goSuggest.ts | 8 +++- .../completions/exportedMemberDocs.go | 22 +++++++++++ test/go.test.ts | 38 ++++++++++++++++--- 3 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 test/fixtures/completions/exportedMemberDocs.go diff --git a/src/goSuggest.ts b/src/goSuggest.ts index 9ba974ccd..2251f6e57 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -54,8 +54,12 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { if (lineText.match(/^\s*\/\//)) { let nextLine = document.lineAt(position.line + 1).text; - let part0 = nextLine.split(" "); - if (!part0[1].match(/^[A-Z]/)) { + let memberName = nextLine.replace(/\s+/g, ' ').trim().split(" "); + if (!nextLine.startsWith("\t")) { + // check for exported qmembers declared in block + memberName.shift() + } + if (!memberName[0].match(/^[A-Z]/)) { return resolve([]); } } diff --git a/test/fixtures/completions/exportedMemberDocs.go b/test/fixtures/completions/exportedMemberDocs.go new file mode 100644 index 000000000..e9e79e7f4 --- /dev/null +++ b/test/fixtures/completions/exportedMemberDocs.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" +) + +const ( + // + HelloStatus = 0 + // + GreetingStatus = 1 +) + +// +func SayHello() { + fmt.Println("Says hello!") +} + +// HelloParams +type HelloParams struct { + language string +} diff --git a/test/go.test.ts b/test/go.test.ts index 2a8be4767..9cc587ec6 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -65,6 +65,7 @@ suite('Go Extension Tests', () => { fs.copySync(path.join(fixtureSourcePath, 'linterTest', 'linter_2.go'), path.join(testPath, 'linterTest', 'linter_2.go')); 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', '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')); @@ -277,9 +278,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++; } } @@ -403,8 +404,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++; } } @@ -793,6 +794,33 @@ 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(7, 8), ['HelloStatus']], + [new vscode.Position(9, 8), ['GreetingStatus']], + [new vscode.Position(13, 4), ['SayHello']], + [new vscode.Position(18, 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); + for (let entry of expected) { + assert.equal(labels.indexOf(entry) > -1, true, `missing expected item in completion list: ${entry} Actual: ${labels}`); + } + }) + ); + 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'], From 0f484b7f6ae26e48e76fe02e20e405f3b972a78c Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Sat, 12 May 2018 15:11:53 -0700 Subject: [PATCH 03/13] Cleaning Up Logic for fixing #1005 and added test --- test/fixtures/completions/exportedMemberDocs.go | 5 +++++ test/go.test.ts | 1 + 2 files changed, 6 insertions(+) diff --git a/test/fixtures/completions/exportedMemberDocs.go b/test/fixtures/completions/exportedMemberDocs.go index e9e79e7f4..536f42b79 100644 --- a/test/fixtures/completions/exportedMemberDocs.go +++ b/test/fixtures/completions/exportedMemberDocs.go @@ -20,3 +20,8 @@ func SayHello() { type HelloParams struct { language string } + +type ( + // + Point struct{ x, y float64 } +) diff --git a/test/go.test.ts b/test/go.test.ts index 9cc587ec6..2a15759f7 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -801,6 +801,7 @@ It returns the number of bytes written and any write error encountered. [new vscode.Position(9, 8), ['GreetingStatus']], [new vscode.Position(13, 4), ['SayHello']], [new vscode.Position(18, 5), ['HelloParams']], + [new vscode.Position(25, 8), ['Point']] ]; let uri = vscode.Uri.file(path.join(fixturePath, 'completions', 'exportedMemberDocs.go')); From d12fb52ca35859d076763a49ac5fe7ec6ac4aa5d Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Sat, 12 May 2018 15:22:18 -0700 Subject: [PATCH 04/13] Cleaning Up Logic for fixing #1005 and added test --- src/goSuggest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goSuggest.ts b/src/goSuggest.ts index 2251f6e57..fc15717eb 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -56,7 +56,7 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { let nextLine = document.lineAt(position.line + 1).text; let memberName = nextLine.replace(/\s+/g, ' ').trim().split(" "); if (!nextLine.startsWith("\t")) { - // check for exported qmembers declared in block + // check for exported members declared in block memberName.shift() } if (!memberName[0].match(/^[A-Z]/)) { From ed40bcdb2473bb414824e720bb273b419922fad7 Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Sat, 12 May 2018 15:37:26 -0700 Subject: [PATCH 05/13] Linting according to tslint --- src/goSuggest.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/goSuggest.ts b/src/goSuggest.ts index fc15717eb..758efa929 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -54,10 +54,10 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { if (lineText.match(/^\s*\/\//)) { let nextLine = document.lineAt(position.line + 1).text; - let memberName = nextLine.replace(/\s+/g, ' ').trim().split(" "); - if (!nextLine.startsWith("\t")) { + let memberName = nextLine.replace(/\s+/g, ' ').trim().split(' '); + if (!nextLine.startsWith('\t')) { // check for exported members declared in block - memberName.shift() + memberName.shift(); } if (!memberName[0].match(/^[A-Z]/)) { return resolve([]); From 02aa6217f81e6f58f66c701d4c2db2bde5792c08 Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Sat, 12 May 2018 20:22:40 -0700 Subject: [PATCH 06/13] Added check for last line per review comments --- src/goSuggest.ts | 17 +++++++++++------ test/fixtures/completions/exportedMemberDocs.go | 5 ++++- test/go.test.ts | 11 ++++++----- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/goSuggest.ts b/src/goSuggest.ts index 758efa929..bee9cd91d 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -53,13 +53,18 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { let autocompleteUnimportedPackages = config['autocompleteUnimportedPackages'] === true && !lineText.match(/^(\s)*(import|package)(\s)+/); if (lineText.match(/^\s*\/\//)) { - let nextLine = document.lineAt(position.line + 1).text; - let memberName = nextLine.replace(/\s+/g, ' ').trim().split(' '); - if (!nextLine.startsWith('\t')) { - // check for exported members declared in block - memberName.shift(); + if (position.line + 1 < document.lineCount) { + let nextLine = document.lineAt(position.line + 1).text; + let memberName = nextLine.replace(/\s+/g, ' ').trim().split(' '); + if ((!nextLine.startsWith('\t'))) { + // check for exported members declared in block + memberName.shift(); + } + if (!memberName[0].match(/^[A-Z]/)) { + return resolve([]); + } } - if (!memberName[0].match(/^[A-Z]/)) { + else { return resolve([]); } } diff --git a/test/fixtures/completions/exportedMemberDocs.go b/test/fixtures/completions/exportedMemberDocs.go index 536f42b79..ad7f1c723 100644 --- a/test/fixtures/completions/exportedMemberDocs.go +++ b/test/fixtures/completions/exportedMemberDocs.go @@ -4,6 +4,9 @@ import ( "fmt" ) +// +var Language = "english" + const ( // HelloStatus = 0 @@ -22,6 +25,6 @@ type HelloParams struct { } type ( - // + // Point struct{ x, y float64 } ) diff --git a/test/go.test.ts b/test/go.test.ts index 2a15759f7..c043dfa09 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -797,11 +797,12 @@ It returns the number of bytes written and any write error encountered. test('Test Completion on Comments for Exported Members', (done) => { let provider = new GoCompletionItemProvider(); let testCases: [vscode.Position, string[]][] = [ - [new vscode.Position(7, 8), ['HelloStatus']], - [new vscode.Position(9, 8), ['GreetingStatus']], - [new vscode.Position(13, 4), ['SayHello']], - [new vscode.Position(18, 5), ['HelloParams']], - [new vscode.Position(25, 8), ['Point']] + [new vscode.Position(6, 3), ['Language']], + [new vscode.Position(10, 8), ['HelloStatus']], + [new vscode.Position(12, 8), ['GreetingStatus']], + [new vscode.Position(16, 4), ['SayHello']], + [new vscode.Position(21, 5), ['HelloParams']], + [new vscode.Position(28, 8), ['Point']], ]; let uri = vscode.Uri.file(path.join(fixturePath, 'completions', 'exportedMemberDocs.go')); From 4bc5615788ffbc79f32139423fbebed50db7eae0 Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Sun, 13 May 2018 15:43:07 -0700 Subject: [PATCH 07/13] Merging from upstream --- src/goSuggest.ts | 4 +- .../completions/exportedMemberDocs.go | 7 ++ test/go.test.ts | 85 ++++++++++--------- 3 files changed, 53 insertions(+), 43 deletions(-) diff --git a/src/goSuggest.ts b/src/goSuggest.ts index e1b3ae8f6..06fb48274 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -170,7 +170,7 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { ); } if ((config['useCodeSnippetsOnFunctionSuggest'] || config['useCodeSnippetsOnFunctionSuggestWithoutType']) - && (suggest.class === 'func' || suggest.class === 'var' && suggest.type.startsWith('func('))) { + && (suggest.class === 'func' || suggest.class === 'var' && suggest.type.startsWith('func('))) { let params = parameters(suggest.type.substring(4)); let paramSnippets = []; for (let i = 0; i < params.length; i++) { @@ -345,4 +345,4 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { return matchingPackages[0]; } } -} +} \ No newline at end of file diff --git a/test/fixtures/completions/exportedMemberDocs.go b/test/fixtures/completions/exportedMemberDocs.go index ad7f1c723..dc3d70848 100644 --- a/test/fixtures/completions/exportedMemberDocs.go +++ b/test/fixtures/completions/exportedMemberDocs.go @@ -7,6 +7,13 @@ import ( // var Language = "english" +var ( + // + Greeting = "Hello" + // + GreetingText = "Hello World!" +) + const ( // HelloStatus = 0 diff --git a/test/go.test.ts b/test/go.test.ts index 451a19d7e..6d6b5742f 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -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')); @@ -776,50 +777,50 @@ 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((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((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((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((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((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((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((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((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'); - let item2 = items.find(x => x.label === 'HandlerFuncWithArgNames'); - assert.equal(!item1.insertText, true); - assert.equal(!item2.insertText, true); - }); + 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'); + let item2 = items.find(x => x.label === 'HandlerFuncWithArgNames'); + assert.equal(!item1.insertText, true); + assert.equal(!item2.insertText, true); + }); - let withFunctionAsTypeSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(14, 0), null, Object.create(baseConfig, {'useCodeSnippetsOnFunctionSuggest': { value: true }})).then(items => { - let item1 = items.find(x => x.label === 'HandlerFunc'); - let item2 = items.find(x => x.label === 'HandlerFuncWithArgNames'); - assert.equal((item1.insertText).value, 'HandlerFunc(func(${1:arg1} http.ResponseWriter, ${2:arg2} *http.Request) {\n\t$3\n})'); - assert.equal((item2.insertText).value, 'HandlerFuncWithArgNames(func(${1:w} http.ResponseWriter, ${2:r} *http.Request) {\n\t$3\n})'); - }); + let withFunctionAsTypeSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(14, 0), null, Object.create(baseConfig, { 'useCodeSnippetsOnFunctionSuggest': { value: true } })).then(items => { + let item1 = items.find(x => x.label === 'HandlerFunc'); + let item2 = items.find(x => x.label === 'HandlerFuncWithArgNames'); + assert.equal((item1.insertText).value, 'HandlerFunc(func(${1:arg1} http.ResponseWriter, ${2:arg2} *http.Request) {\n\t$3\n})'); + assert.equal((item2.insertText).value, 'HandlerFuncWithArgNames(func(${1:w} http.ResponseWriter, ${2:r} *http.Request) {\n\t$3\n})'); + }); return Promise.all([ noFunctionSnippet, withFunctionSnippet, withFunctionSnippetNotype, @@ -863,11 +864,13 @@ It returns the number of bytes written and any write error encountered. let provider = new GoCompletionItemProvider(); let testCases: [vscode.Position, string[]][] = [ [new vscode.Position(6, 3), ['Language']], - [new vscode.Position(10, 8), ['HelloStatus']], - [new vscode.Position(12, 8), ['GreetingStatus']], - [new vscode.Position(16, 4), ['SayHello']], - [new vscode.Position(21, 5), ['HelloParams']], - [new vscode.Position(28, 8), ['Point']], + [new vscode.Position(10, 8), ['Greeting']], + [new vscode.Position(12, 8), ['GreetingText']], + [new vscode.Position(17, 8), ['HelloStatus']], + [new vscode.Position(19, 8), ['GreetingStatus']], + [new vscode.Position(23, 4), ['SayHello']], + [new vscode.Position(28, 5), ['HelloParams']], + [new vscode.Position(34, 8), ['Point']], ]; let uri = vscode.Uri.file(path.join(fixturePath, 'completions', 'exportedMemberDocs.go')); From b5ebe2c0ec76883cb2aaa3ae98eb9cfbc57405cc Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Sun, 13 May 2018 18:28:53 -0700 Subject: [PATCH 08/13] WIP: Testing autocompletion on comments after refactoring code according to comments --- src/goSuggest.ts | 18 +++++++++++++++++- .../fixtures/completions/exportedMemberDocs.go | 4 ++-- test/go.test.ts | 3 ++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/goSuggest.ts b/src/goSuggest.ts index 06fb48274..147f6feb6 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -55,7 +55,23 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { // prevent completion when typing in a line comment const commentIndex = lineText.indexOf('//'); if (commentIndex >= 0 && position.character > commentIndex) { - return resolve([]); + if (!lineText.trim().startsWith('//')) { + return resolve([]); + } + // triggering completions in comments on exported members + if (position.line + 1 < document.lineCount) { + let nextLine = document.lineAt(position.line + 1).text.trim(); + let memberType = nextLine.match(/(const|func|type|var)\s*(\w+)/); + if (memberType && memberType.length === 3) { + if (!memberType[2].match(/^[A-Z]/)) { + return resolve([]); + } + let suggestionItem = new vscode.CompletionItem(memberType[2]); + suggestionItem.kind = vscodeKindFromGoCodeClass(memberType[1]); + return resolve([suggestionItem]); + } + } + } let inString = isPositionInString(document, position); diff --git a/test/fixtures/completions/exportedMemberDocs.go b/test/fixtures/completions/exportedMemberDocs.go index dc3d70848..0e61b09c5 100644 --- a/test/fixtures/completions/exportedMemberDocs.go +++ b/test/fixtures/completions/exportedMemberDocs.go @@ -5,12 +5,12 @@ import ( ) // -var Language = "english" +var Language = "english" // should not invoke completion since this is line comment var ( // Greeting = "Hello" - // + // GreetingText = "Hello World!" ) diff --git a/test/go.test.ts b/test/go.test.ts index 6d6b5742f..b47d25714 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -864,7 +864,8 @@ It returns the number of bytes written and any write error encountered. let provider = new GoCompletionItemProvider(); let testCases: [vscode.Position, string[]][] = [ [new vscode.Position(6, 3), ['Language']], - [new vscode.Position(10, 8), ['Greeting']], + [new vscode.Position(7, 29), []], + [new vscode.Position(10, 9), ['Greeting']], [new vscode.Position(12, 8), ['GreetingText']], [new vscode.Position(17, 8), ['HelloStatus']], [new vscode.Position(19, 8), ['GreetingStatus']], From ac730dfdeb9e1ae175b07c86d17893e8a9863b83 Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Sun, 13 May 2018 18:37:29 -0700 Subject: [PATCH 09/13] WIP: Testing autocompletion on comments after refactoring code according to comments --- src/goSuggest.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/goSuggest.ts b/src/goSuggest.ts index 147f6feb6..8f5cf9fc1 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -71,7 +71,6 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { return resolve([suggestionItem]); } } - } let inString = isPositionInString(document, position); From 39765425bf999b91b05a52536fe32acc18f4d6ac Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Sun, 13 May 2018 19:01:56 -0700 Subject: [PATCH 10/13] Reverting Lint Issues --- test/go.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/go.test.ts b/test/go.test.ts index b47d25714..0370c3f14 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -777,45 +777,45 @@ 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 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 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((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 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((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 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 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((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 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((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 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'); let item2 = items.find(x => x.label === 'HandlerFuncWithArgNames'); assert.equal(!item1.insertText, true); assert.equal(!item2.insertText, true); }); - let withFunctionAsTypeSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(14, 0), null, Object.create(baseConfig, { 'useCodeSnippetsOnFunctionSuggest': { value: true } })).then(items => { + let withFunctionAsTypeSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(14, 0), null, Object.create(baseConfig, {'useCodeSnippetsOnFunctionSuggest': { value: true }})).then(items => { let item1 = items.find(x => x.label === 'HandlerFunc'); let item2 = items.find(x => x.label === 'HandlerFuncWithArgNames'); assert.equal((item1.insertText).value, 'HandlerFunc(func(${1:arg1} http.ResponseWriter, ${2:arg2} *http.Request) {\n\t$3\n})'); From 41bd17d542cfaefba3ee8ed84e2f21a785d96eed Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Mon, 14 May 2018 14:40:07 -0700 Subject: [PATCH 11/13] Made changes to code according to review comments and refactored tests to include test cases --- src/goSuggest.ts | 31 +++++++------- .../completions/exportedMemberDocs.go | 24 ++--------- test/go.test.ts | 41 ++++++++++--------- 3 files changed, 40 insertions(+), 56 deletions(-) diff --git a/src/goSuggest.ts b/src/goSuggest.ts index 8f5cf9fc1..6c323ea5c 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -52,25 +52,24 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { let lineTillCurrentPosition = lineText.substr(0, position.character); let autocompleteUnimportedPackages = config['autocompleteUnimportedPackages'] === true && !lineText.match(/^(\s)*(import|package)(\s)+/); + // triggering completions in comments on exported members + if (lineText.trim().startsWith('//') && (position.line + 1 < document.lineCount) && (lineTillCurrentPosition.match(/\/\/\s+/))) { + let nextLine = document.lineAt(position.line + 1).text.trim(); + let memberType = nextLine.match(/(const|func|type|var)\s+(\w+)/); + if (memberType && memberType.length === 3) { + if (!memberType[2].match(/^[A-Z]/)) { + return resolve([]); + } + let suggestionItem = new vscode.CompletionItem(memberType[2]); + suggestionItem.kind = vscodeKindFromGoCodeClass(memberType[1]); + return resolve([suggestionItem]); + } + return resolve([]); + } // prevent completion when typing in a line comment const commentIndex = lineText.indexOf('//'); if (commentIndex >= 0 && position.character > commentIndex) { - if (!lineText.trim().startsWith('//')) { - return resolve([]); - } - // triggering completions in comments on exported members - if (position.line + 1 < document.lineCount) { - let nextLine = document.lineAt(position.line + 1).text.trim(); - let memberType = nextLine.match(/(const|func|type|var)\s*(\w+)/); - if (memberType && memberType.length === 3) { - if (!memberType[2].match(/^[A-Z]/)) { - return resolve([]); - } - let suggestionItem = new vscode.CompletionItem(memberType[2]); - suggestionItem.kind = vscodeKindFromGoCodeClass(memberType[1]); - return resolve([suggestionItem]); - } - } + return resolve([]); } let inString = isPositionInString(document, position); diff --git a/test/fixtures/completions/exportedMemberDocs.go b/test/fixtures/completions/exportedMemberDocs.go index 0e61b09c5..3f8560dd4 100644 --- a/test/fixtures/completions/exportedMemberDocs.go +++ b/test/fixtures/completions/exportedMemberDocs.go @@ -4,24 +4,13 @@ import ( "fmt" ) -// +// L var Language = "english" // should not invoke completion since this is line comment -var ( - // - Greeting = "Hello" - // - GreetingText = "Hello World!" -) - -const ( - // - HelloStatus = 0 - // - GreetingStatus = 1 -) +// G +const GreetingText = "Hello" -// +// S func SayHello() { fmt.Println("Says hello!") } @@ -30,8 +19,3 @@ func SayHello() { type HelloParams struct { language string } - -type ( - // - Point struct{ x, y float64 } -) diff --git a/test/go.test.ts b/test/go.test.ts index 0370c3f14..de1d4695e 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -777,45 +777,45 @@ 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 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 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((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 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((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 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 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((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 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((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 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'); let item2 = items.find(x => x.label === 'HandlerFuncWithArgNames'); assert.equal(!item1.insertText, true); assert.equal(!item2.insertText, true); }); - let withFunctionAsTypeSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(14, 0), null, Object.create(baseConfig, {'useCodeSnippetsOnFunctionSuggest': { value: true }})).then(items => { + let withFunctionAsTypeSnippet = provider.provideCompletionItemsInternal(editor.document, new vscode.Position(14, 0), null, Object.create(baseConfig, { 'useCodeSnippetsOnFunctionSuggest': { value: true } })).then(items => { let item1 = items.find(x => x.label === 'HandlerFunc'); let item2 = items.find(x => x.label === 'HandlerFuncWithArgNames'); assert.equal((item1.insertText).value, 'HandlerFunc(func(${1:arg1} http.ResponseWriter, ${2:arg2} *http.Request) {\n\t$3\n})'); @@ -863,15 +863,14 @@ It returns the number of bytes written and any write error encountered. test('Test Completion on Comments for Exported Members', (done) => { let provider = new GoCompletionItemProvider(); let testCases: [vscode.Position, string[]][] = [ - [new vscode.Position(6, 3), ['Language']], - [new vscode.Position(7, 29), []], - [new vscode.Position(10, 9), ['Greeting']], - [new vscode.Position(12, 8), ['GreetingText']], - [new vscode.Position(17, 8), ['HelloStatus']], - [new vscode.Position(19, 8), ['GreetingStatus']], - [new vscode.Position(23, 4), ['SayHello']], - [new vscode.Position(28, 5), ['HelloParams']], - [new vscode.Position(34, 8), ['Point']], + [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')); @@ -880,9 +879,11 @@ It returns the number of bytes written and any write error encountered. let promises = testCases.map(([position, expected]) => provider.provideCompletionItems(editor.document, position, null).then(items => { let labels = items.map(x => x.label); - for (let entry of expected) { - assert.equal(labels.indexOf(entry) > -1, true, `missing expected item in completion list: ${entry} Actual: ${labels}`); - } + 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')); From a7b8307907b7d4b47915bb74cc1e71687d820a6e Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Mon, 14 May 2018 18:32:53 -0700 Subject: [PATCH 12/13] Refactoring --- src/goSuggest.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/goSuggest.ts b/src/goSuggest.ts index a207016de..189741af7 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -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(); @@ -53,20 +56,17 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { let autocompleteUnimportedPackages = config['autocompleteUnimportedPackages'] === true && !lineText.match(/^(\s)*(import|package)(\s)+/); // triggering completions in comments on exported members - if (lineText.trim().startsWith('//') && (position.line + 1 < document.lineCount) && (lineTillCurrentPosition.match(/\/\/\s+/))) { + if (lineCommentRegex.test(lineTillCurrentPosition) && position.line + 1 < document.lineCount) { let nextLine = document.lineAt(position.line + 1).text.trim(); - let memberType = nextLine.match(/(const|func|type|var)\s+(\w+)/); + let memberType = nextLine.match(exportedMemberRegex); if (memberType && memberType.length === 3) { - if (!memberType[2].match(/^[A-Z]/)) { - return resolve([]); - } let suggestionItem = new vscode.CompletionItem(memberType[2]); suggestionItem.kind = vscodeKindFromGoCodeClass(memberType[1]); return resolve([suggestionItem]); } return resolve([]); } - // prevent completion when typing in a line comment + // 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([]); From 0c625e28b8c2c5c03375e8c12e18b9a2f9f05f80 Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Mon, 14 May 2018 18:38:11 -0700 Subject: [PATCH 13/13] Pass suggestion item kind to constructor --- src/goSuggest.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/goSuggest.ts b/src/goSuggest.ts index 189741af7..b8aa4f7c6 100644 --- a/src/goSuggest.ts +++ b/src/goSuggest.ts @@ -59,12 +59,11 @@ export class GoCompletionItemProvider implements vscode.CompletionItemProvider { 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) { - let suggestionItem = new vscode.CompletionItem(memberType[2]); - suggestionItem.kind = vscodeKindFromGoCodeClass(memberType[1]); - return resolve([suggestionItem]); + suggestionItem = new vscode.CompletionItem(memberType[2], vscodeKindFromGoCodeClass(memberType[1])); } - return resolve([]); + 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('//');