Add command to fetch import on current line (#1222)

* Add command to fetch import on current line

This will allow users to easily fetch a dependency without having to
take their attention away from the code they're editing.

Microsoft/vscode-go#1189

* Rename goGetImports to goGetImport

The plugin only fetches one import so having the file name plural is
misleading to anybody reading the code.

Microsoft/vscode-go#1189

* Refactor getImportPath

This consolidates the functionality found in two commands into one place
so that if it ever needs to be changed or removed it can be done more
easily.

* Fix lint issues

* Make command title and description more intuitive

Microsoft/vscode-go#1189

* Make name `goGetPackage` consistent

Anybody else who comes along later and reads this is gonna have an
easier time if they only have to keep one name in their head vs. having
to keep two (goGetImport and goGetPackage).

Microsoft/vscode-go#1189

* Exit early if there's no import path to get

If there's no import path to pass to `go get` then there's no point in
spinning up a child process and waiting for it to finish to error out.

This also fixes a bug in `getImportPath` that would cause it to return
invalid input paths for things like comments and function definitions.

Microsoft/vscode-go#1189

* Fallback to selectedText for browsePackage feature

* Offload check for package to go get

`go get` won't download a package if it's already in `$GOPATH/src`.
There's no point in checking for the package to exist and then
downloading with `-u` because `go get -u` and `go get` are effectively
the same when a package hasn't been downloaded yet.

Microsoft/vscode-go#1189

* Use output pane for go get output

`go get -v` gives users more information on what's going on with the
command. This way a user can tell if the package was even downloaded,
because by default `go get` won't output anything.

`go get -v` will output nothing if the package isn't downloaded because
it already exists. To get around this, an information message is shown
saying that the package wasn't downloaded. This keeps the user informed
because they will be expecting feedback from the command.

In the event of an error (like if there's no internet connection), the
error gets shown to the output pane so the user knows what happened.

Microsoft/vscode-go#1189

* Cleanup
This commit is contained in:
Hugo 2017-09-27 22:05:05 -04:00 коммит произвёл Ramya Rao
Родитель e2175a303e
Коммит 2e2e3cda2b
6 изменённых файлов: 83 добавлений и 17 удалений

Просмотреть файл

@ -169,6 +169,11 @@
"command": "go.browse.packages",
"title": "Go: Browse Packages",
"description": "Browse packages and Go files inside the packages."
},
{
"command": "go.get.package",
"title": "Go: Get Package",
"description": "Run `go get -v` on the package on the current line."
}
],
"debuggers": [

Просмотреть файл

@ -10,6 +10,7 @@ import cp = require('child_process');
import { getGoRuntimePath } from './goPath';
import path = require('path');
import { getAllPackages } from './goPackages';
import { getImportPath } from './util';
export function browsePackages() {
let selectedText = '';
@ -23,7 +24,7 @@ export function browsePackages() {
// if selection is empty, then get the whole line the cursor is currently on.
selectedText = editor.document.lineAt(selection.active.line).text;
}
selectedText = getImportPath(selectedText);
selectedText = getImportPath(selectedText) || selectedText.trim();
}
showPackageFiles(selectedText, true);
@ -85,19 +86,3 @@ function showPackageList() {
});
});
}
function getImportPath(text: string): string {
// Catch cases like `import alias "importpath"` and `import "importpath"`
let singleLineImportMatches = text.match(/^\s*import\s+([a-z,A-Z,_,\.]\w*\s+)?\"([^\"]+)\"/);
if (singleLineImportMatches) {
return singleLineImportMatches[2];
}
// Catch cases like `alias "importpath"` and "importpath"
let groupImportMatches = text.match(/^\s*([a-z,A-Z,_,\.]\w*\s+)?\"([^\"]+)\"/);
if (groupImportMatches) {
return groupImportMatches[2];
}
return text.trim();
}

38
src/goGetPackage.ts Normal file
Просмотреть файл

@ -0,0 +1,38 @@
'use strict';
import vscode = require('vscode');
import cp = require('child_process');
import { getGoRuntimePath } from './goPath';
import { getImportPath } from './util';
import { outputChannel } from './goStatus';
export function goGetPackage() {
const editor = vscode.window.activeTextEditor;
const selection = editor.selection;
const selectedText = editor.document.lineAt(selection.active.line).text;
const importPath = getImportPath(selectedText);
if (importPath === '') {
vscode.window.showErrorMessage('No import path to get');
return;
}
const goRuntimePath = getGoRuntimePath();
if (!goRuntimePath) {
return vscode.window.showErrorMessage('Could not locate Go binaries. Make sure you have Go installed');
}
cp.execFile(goRuntimePath, ['get', '-v', importPath], (err, stdout, stderr) => {
// go get -v uses stderr to write output regardless of success or failure
if (stderr !== '') {
outputChannel.show();
outputChannel.clear();
outputChannel.appendLine(stderr);
return;
}
// go get -v doesn't write anything when the package already exists
vscode.window.showInformationMessage(`Package already exists: ${importPath}`);
});
};

Просмотреть файл

@ -37,6 +37,7 @@ import { parseLiveFile } from './goLiveErrors';
import { GoReferencesCodeLensProvider } from './goReferencesCodelens';
import { implCursor } from './goImpl';
import { browsePackages } from './goBrowsePackage';
import { goGetPackage } from './goGetPackage';
export let errorDiagnosticCollection: vscode.DiagnosticCollection;
let warningDiagnosticCollection: vscode.DiagnosticCollection;
@ -283,6 +284,8 @@ export function activate(ctx: vscode.ExtensionContext): void {
});
}));
ctx.subscriptions.push(vscode.commands.registerCommand('go.get.package', goGetPackage));
vscode.languages.setLanguageConfiguration(GO_MODE.language, {
indentationRules: {
decreaseIndentPattern: /^\s*(\bcase\b.*:|\bdefault\b:|}[),]?|\)[,]?)$/,

Просмотреть файл

@ -409,3 +409,22 @@ export function resolvePath(inputPath: string, workspaceRoot?: string): string {
return resolveHomeDir(inputPath);
}
/**
* Returns the import path in a passed in string.
* @param text The string to search for an import path
*/
export function getImportPath(text: string): string {
// Catch cases like `import alias "importpath"` and `import "importpath"`
let singleLineImportMatches = text.match(/^\s*import\s+([a-z,A-Z,_,\.]\w*\s+)?\"([^\"]+)\"/);
if (singleLineImportMatches) {
return singleLineImportMatches[2];
}
// Catch cases like `alias "importpath"` and "importpath"
let groupImportMatches = text.match(/^\s*([a-z,A-Z,_,\.]\w*\s+)?\"([^\"]+)\"/);
if (groupImportMatches) {
return groupImportMatches[2];
}
return '';
}

Просмотреть файл

@ -22,6 +22,7 @@ import { documentSymbols } from '../src/goOutline';
import { listPackages } from '../src/goImport';
import { generateTestCurrentFile, generateTestCurrentPackage, generateTestCurrentFunction } from '../src/goGenerateTests';
import { getAllPackages } from '../src/goPackages';
import { getImportPath } from '../src/util';
suite('Go Extension Tests', () => {
let gopath = process.env['GOPATH'];
@ -738,4 +739,19 @@ It returns the number of bytes written and any write error encountered.
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'],
['import "net/http"', 'net/http'],
['"github.com/sirupsen/logrus"', 'github.com/sirupsen/logrus'],
['', ''],
['func foo(bar int) (int, error) {', ''],
['// This is a comment, complete with punctuation.', '']
];
testCases.forEach(run => {
assert.equal(run[1], getImportPath(run[0]));
});
});
});