* add playground command

enables the user to upload the current file or selection to the
go playground using package goplay - solves #1211

* separate tool execution from command logic, add test

* add tests for error case

* ensure better separation between tool calling and extension logic

* handle no active editor, clear output channel, check for tool availability by stat-ing binary location

* move all logic into function body

* Add tests back

* Fixing linting error
This commit is contained in:
Frederik Ring 2017-11-07 01:40:52 +01:00 коммит произвёл Ramya Rao
Родитель 12e9d30c42
Коммит f71af13762
7 изменённых файлов: 179 добавлений и 1 удалений

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

@ -52,6 +52,7 @@ install:
- go get -u -v github.com/acroca/go-symbols
- go get -u -v github.com/alecthomas/gometalinter
- go get -u -v github.com/cweill/gotests/...
- go get -u -v github.com/haya14busa/goplay/cmd/goplay
- GO15VENDOREXPERIMENT=1
- if [[ "$(go version)" =~ "go version go1.5" ]]; then echo skipping gometalinter; else gometalinter --install; fi

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

@ -28,6 +28,7 @@ This extension adds rich language support for the Go language to VS Code, includ
- Show code coverage
- Generate method stubs for interfaces (using `impl`)
- [_partially implemented_] Debugging (using `delve`)
- Upload to the Go Playground (using `goplay`)
### IDE Features
![IDE](https://i.giphy.com/xTiTndDHV3GeIy6aNa.gif)
@ -105,6 +106,7 @@ In addition to integrated editing features, the extension also provides several
* `Go: Add Tags` Adds configured tags to selected struct fields.
* `Go: Remove Tags` Removes configured tags from selected struct fields.
* `Go: Generate Interface Stubs` Generates method stubs for given interface
* `Go: Run on Go Playground` Upload the current selection or file to the Go Playground
You can access all of the above commands from the command pallet (`Cmd+Shift+P` or `Ctrl+Shift+P`).

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

@ -177,6 +177,11 @@
"command": "go.get.package",
"title": "Go: Get Package",
"description": "Run `go get -v` on the package on the current line."
},
{
"command": "go.playground",
"title": "Go: Run on Go Playground",
"description": "Upload the current selection or file to the Go Playground"
}
],
"debuggers": [
@ -720,6 +725,32 @@
"description": "Tags and options configured here will be used by the Remove Tags command to remove tags to struct fields. If promptForTags is true, then user will be prompted for tags and options. By default, all tags and options will be removed.",
"scope": "resource"
},
"go.playground": {
"type": "object",
"properties": {
"openbrowser": {
"type": "boolean",
"default": true,
"description": "Whether to open the created Go Playground in the default browser"
},
"share": {
"type": "boolean",
"default": true,
"description": "Whether to make the created Go Playground shareable"
},
"run": {
"type": "boolean",
"default": true,
"description": "Whether to run the created Go Playground after creation"
},
"description": "The flags configured here will be passed through to command `goplay`"
},
"default": {
"openbrowser": true,
"share": true,
"run": true
}
},
"go.editorContextMenuCommands": {
"type": "object",
"properties": {
@ -777,6 +808,11 @@
"type": "boolean",
"default": true,
"description": "If true, adds command to run test coverage to the editor context menu"
},
"playground": {
"type": "boolean",
"default": true,
"description": "If true, adds command to upload the current file or selection to the Go Playground"
}
},
"default": {
@ -790,7 +826,8 @@
"generateTestForFile": false,
"generateTestForPackage": false,
"addImport": true,
"testCoverage": true
"testCoverage": true,
"playground": true
},
"description": "Experimental Feature: Enable/Disable entries from the context menu in the editor.",
"scope": "resource"

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

@ -26,6 +26,7 @@ const allTools: { [key: string]: string } = {
'guru': 'golang.org/x/tools/cmd/guru',
'gorename': 'golang.org/x/tools/cmd/gorename',
'gomodifytags': 'github.com/fatih/gomodifytags',
'goplay': 'github.com/haya14busa/goplay/cmd/goplay',
'impl': 'github.com/josharian/impl',
'gotype-live': 'github.com/tylerb/gotype-live',
'godef': 'github.com/rogpeppe/godef',
@ -51,6 +52,7 @@ function getTools(goVersion: SemVersion): string[] {
'guru',
'gorename',
'gomodifytags',
'goplay',
'impl'
];

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

@ -40,6 +40,7 @@ import { implCursor } from './goImpl';
import { browsePackages } from './goBrowsePackage';
import { goGetPackage } from './goGetPackage';
import { GoDebugConfigurationProvider } from './goDebugConfiguration';
import { playgroundCommand } from './goPlayground';
export let errorDiagnosticCollection: vscode.DiagnosticCollection;
let warningDiagnosticCollection: vscode.DiagnosticCollection;
@ -279,6 +280,8 @@ export function activate(ctx: vscode.ExtensionContext): void {
ctx.subscriptions.push(vscode.commands.registerCommand('go.get.package', goGetPackage));
ctx.subscriptions.push(vscode.commands.registerCommand('go.playground', playgroundCommand));
vscode.languages.setLanguageConfiguration(GO_MODE.language, {
indentationRules: {
decreaseIndentPattern: /^\s*(\bcase\b.*:|\bdefault\b:|}[),]?|\)[,]?)$/,

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

@ -0,0 +1,61 @@
import vscode = require('vscode');
import * as path from 'path';
import { execFile } from 'child_process';
import { outputChannel } from './goStatus';
import { getBinPath } from './util';
import { promptForMissingTool } from './goInstallTools';
const TOOL_CMD_NAME = 'goplay';
type flags = { [key: string]: Boolean };
export const playgroundCommand = () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active.');
return;
}
const binaryLocation = getBinPath(TOOL_CMD_NAME);
if (!path.isAbsolute(binaryLocation)) {
return promptForMissingTool(TOOL_CMD_NAME);
}
outputChannel.clear();
outputChannel.show();
outputChannel.appendLine('Upload to the Go Playground in progress...\n');
const selection = editor.selection;
const code = selection.isEmpty
? editor.document.getText()
: editor.document.getText(selection);
goPlay(code, vscode.workspace.getConfiguration('go', editor.document.uri).get('playground')).then(result => {
outputChannel.append(result);
}, (e: string) => {
if (e) {
vscode.window.showErrorMessage(e);
}
});
};
export function goPlay(code: string, goConfig: vscode.WorkspaceConfiguration): Thenable<string> {
const cliArgs = Object.keys(goConfig).map(key => `-${key}=${goConfig[key]}`);
const binaryLocation = getBinPath(TOOL_CMD_NAME);
return new Promise<string>((resolve, reject) => {
execFile(binaryLocation, [...cliArgs, '-'], (err, stdout, stderr) => {
if (err && (<any>err).code === 'ENOENT') {
promptForMissingTool(TOOL_CMD_NAME);
return reject();
}
if (err) {
return reject(`${TOOL_CMD_NAME}: ${stdout || stderr || err.message}`);
}
return resolve(
`Output from the Go Playground:
${stdout || stderr}
Finished running tool: ${binaryLocation} ${cliArgs.join(' ')} -\n`
);
}).stdin.end(code);
});
}

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

@ -23,6 +23,7 @@ import { listPackages } from '../src/goImport';
import { generateTestCurrentFile, generateTestCurrentPackage, generateTestCurrentFunction } from '../src/goGenerateTests';
import { getAllPackages } from '../src/goPackages';
import { getImportPath } from '../src/util';
import { goPlay } from '../src/goPlayground';
suite('Go Extension Tests', () => {
let gopath = process.env['GOPATH'];
@ -755,4 +756,75 @@ It returns the number of bytes written and any write error encountered.
assert.equal(run[1], getImportPath(run[0]));
});
});
test('goPlay - success run', (done) => {
const validCode = `
package main
import (
"fmt"
)
func main() {
for i := 1; i < 4; i++ {
fmt.Printf("%v ", i)
}
fmt.Print("Go!")
}`;
const goConfig = Object.create(vscode.workspace.getConfiguration('go'), {
'playground': { value: { run: true, openbrowser: false, share: false } }
});
goPlay(validCode, goConfig['playground']).then(result => {
assert(
result.includes('1 2 3 Go!')
);
}, (e) => {
assert.ifError(e);
}).then(() => done(), done);
});
test('goPlay - success run & share', (done) => {
const validCode = `
package main
import (
"fmt"
)
func main() {
for i := 1; i < 4; i++ {
fmt.Printf("%v ", i)
}
fmt.Print("Go!")
}`;
const goConfig = Object.create(vscode.workspace.getConfiguration('go'), {
'playground': { value: { run: true, openbrowser: false, share: true } }
});
goPlay(validCode, goConfig['playground']).then(result => {
assert(result.includes('1 2 3 Go!'));
assert(result.includes('https://play.golang.org/'));
}, (e) => {
assert.ifError(e);
}).then(() => done(), done);
});
test('goPlay - fail', (done) => {
const invalidCode = `
package main
import (
"fmt"
)
func fantasy() {
fmt.Print("not a main package, sorry")
}`;
const goConfig = Object.create(vscode.workspace.getConfiguration('go'), {
'playground': { value: { run: true, openbrowser: false, share: false } }
});
goPlay(invalidCode, goConfig['playground']).then(result => {
assert.ifError(result);
}, (e) => {
assert.ok(e);
}).then(() => done(), done);
});
});