diff --git a/CHANGELOG.md b/CHANGELOG.md index f9c912cd8..d8c692076 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## 0.6.56 - Coming Soon + +* [Ramya Rao (@ramya-rao-a)](https://github.com/ramya-rao-a) + * Use [gomodifytags](https://github.com/fatih/gomodifytags) to modify tags on selected struct fields. + * If there is no selection, then the whole struct under the cursor will be selected for the tag modification. + * `Go: Add Tags` adds tags configured in `go.addTags` setting to selected struct fields. By default, `json` tags are added. Examples: + * To add `xml` tags, set `go.addTags` to `{"tags": "xml"}` + * To add `xml` with `cdata` option, set `go.addTags` to `{"tags": "xml", "options": "xml=cdata"}` + * To add both `json` and `xml` tags, set `go.addTags` to `{"tags": "json,xml"}` + * `Go: Remove Tags` removes tags configured in `go.removeTags` setting from selected struct fields. By default, all tags are removed. To remove only say `xml` tags, set `go.removeTags` to `{"tags": "xml"}` + * To be prompted for tags instead of using the configured ones, set `go.addTags` and/or `go.removeTags` to `{"promptForTags": true}` + + ## 0.6.55 - 3rd March, 2017 * Re-publishing the extension from a non Windows machine as the fix for [Bug 438](https://github.com/Microsoft/vscode-go/issues/438) worked only on Windows machines. For details read the discussion in [PR 838](https://github.com/Microsoft/vscode-go/pull/838). @@ -193,7 +206,7 @@ For details read the discussion in [PR 838](https://github.com/Microsoft/vscode- ## 0.6.44 - 12th October 2016 * [Ludwig Valda Vasquez (@bredov)](https://github.com/bredov) * New configuration `go.formatFlags` to pass flags to the formatting tool [PR #461](https://github.com/Microsoft/vscode-go/pull/461) -* [Dan Mace (@@ironcladlou](https://github.com/ironcladlou) +* [Dan Mace (@ironcladlou](https://github.com/ironcladlou) * New command to execute the last run test. The command is `Go: Test Previous` [PR #478](https://github.com/Microsoft/vscode-go/pull/478) * Send test output to a distinct output channel [PR #499](https://github.com/Microsoft/vscode-go/pull/499) * [Cedric Lamoriniere (@cedriclam)](https://github.com/cedriclam) diff --git a/README.md b/README.md index bc750b9a5..6781bc29e 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ This extension adds rich language support for the Go language to VS Code, includ - Format (using `goreturns` or `goimports` or `gofmt`) - Generate unit tests skeleton (using `gotests`) - Add Imports (using `gopkgs`) +- Add/Remove Tags on struct fields (using `gomodifytags`) - [_partially implemented_] Debugging (using `delve`) ### IDE Features @@ -78,6 +79,16 @@ The following Visual Studio Code settings along with their *default* values that "go.docsTool": "godoc", // Pick 'godoc' or 'gogetdoc' to get documentation. In Go 1.5, godoc is used regardless of the choice here. "go.useLanguageServer": false // Experimental: Not available in Windows. Use Go language server from Sourcegraph for Hover, Definition, Find All References, Signature Help, File Outline and Workspace Symbol features + "go.addTags": { + "tags": "json", // Comma separated tags that will get added by the Add Tags command + "options": "json=omitempty", // Comma separated tag options that will get added by the Add Tags command. + "promptForTags": false // If true, then user will be prompted to provide tags and options to be added by the Add Tags command. + }, + "go.removeTags": { + "tags": "", // Comma separated tags that will get removed by the Remove Tags command. If empty, all tags are removed. + "options": "", // Comma separated tag options that will get removed by the Remove Tags command. + "promptForTags": false // If true, then user will be prompted to provide tags and options to be removed by the Remove Tags command. + } } ``` @@ -126,6 +137,8 @@ In addition to integrated editing features, the extension also provides several * `Go: Generates unit tests (file)` Generates unit tests for the current file * `Go: Generates unit tests (function)` Generates unit tests for the selected function in the current file * `Go: Install Tools` Installs/updates all the Go tools that the extension depends on +* `Go: Add Tags` Adds configured tags to selected struct fields. +* `Go: Remove Tags` Removes configured tags from selected struct fields. ### _Optional_: Debugging @@ -179,6 +192,7 @@ If you wish to have the extension use a separate GOPATH for its tools, provide t - guru: `go get -u -v golang.org/x/tools/cmd/guru` - gotests: `go get -u -v github.com/cweill/gotests/...` - godoc: `go get -u -v golang.org/x/tools/cmd/godoc` +- gomodifytags: `go get -u -v github.com/fatih/gomodifytags` To install the tools manually in the current GOPATH, just paste and run: ```bash @@ -194,6 +208,7 @@ go get -u -v github.com/newhook/go-symbols go get -u -v golang.org/x/tools/cmd/guru go get -u -v github.com/cweill/gotests/... go get -u -v golang.org/x/tools/cmd/godoc +go get -u -v github.com/fatih/gomodifytags ``` And for debugging: diff --git a/package.json b/package.json index fd72dbd46..23a350ba3 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,16 @@ "command": "go.toggle.test.file", "title": "Go: Toggle Test File", "description": "Toggles between file in current active editor and the corresponding test file." + }, + { + "command": "go.add.tags", + "title": "Go: Add Tags", + "description": "Add tags configured in go.addTags setting to selected struct using gomodifytags" + }, + { + "command": "go.remove.tags", + "title": "Go: Remove Tags", + "description": "Remove tags configured in go.removeTags setting from selected struct using gomodifytags" } ], "debuggers": [ @@ -159,7 +169,7 @@ { "label": "Go: Launch package", "description": "Debug the package in the program attribute", - "body":{ + "body": { "name": "${2:Launch Package}", "type": "go", "request": "launch", @@ -170,7 +180,7 @@ { "label": "Go: Launch file", "description": "Debug the file in the program attribute", - "body":{ + "body": { "name": "${2:Launch file}", "type": "go", "request": "launch", @@ -181,7 +191,7 @@ { "label": "Go: Launch test package", "description": "Debug the test package in the program attribute", - "body":{ + "body": { "name": "${2:Launch test package}", "type": "go", "request": "launch", @@ -192,7 +202,7 @@ { "label": "Go: Launch test function", "description": "Debug the test function in the args, ensure program attributes points to right package", - "body":{ + "body": { "name": "${3:Launch test function}", "type": "go", "request": "launch", @@ -412,7 +422,7 @@ "default": null, "description": "Specifies the GOPATH to use when no environment variable is set. The inferred GOPATH from workspace root overrides this, if go.inferGopath is set to true." }, - "go.toolsGopath": { + "go.toolsGopath": { "type": "string", "default": "", "description": "Location to install the Go tools that the extension depends on if you don't want them in your GOPATH." @@ -461,7 +471,7 @@ "default": true, "description": "Enable gocode's autobuild feature" }, - "go.useCodeSnippetsOnFunctionSuggest": { + "go.useCodeSnippetsOnFunctionSuggest": { "type": "boolean", "default": false, "description": "Complete functions with their parameter signature" @@ -489,8 +499,26 @@ "type": "boolean", "default": false, "description": "If false, the import statements will be excluded while using the Go to Symbol in File feature" + }, + "go.addTags": { + "type": "object", + "default": { + "tags": "json", + "options": "json=omitempty", + "promptForTags": false + }, + "description": "Tags and options configured here will be used by the Add Tags command to add tags to struct fields. If promptForTags is true, then user will be prompted for tags and options. By default, json tags are added." + }, + "go.removeTags": { + "type": "object", + "default": { + "tags": "", + "options": "", + "promptForTags": false + }, + "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." } } } } -} +} \ No newline at end of file diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts index d16fb1639..b09cfc648 100644 --- a/src/goInstallTools.ts +++ b/src/goInstallTools.ts @@ -25,7 +25,8 @@ function getTools(goVersion: SemVersion): { [key: string]: string } { 'go-outline': 'github.com/lukehoban/go-outline', 'go-symbols': 'github.com/newhook/go-symbols', 'guru': 'golang.org/x/tools/cmd/guru', - 'gorename': 'golang.org/x/tools/cmd/gorename' + 'gorename': 'golang.org/x/tools/cmd/gorename', + 'gomodifytags': 'github.com/fatih/gomodifytags' }; // Install the doc/def tool that was chosen by the user diff --git a/src/goMain.ts b/src/goMain.ts index 29717d636..efc17b331 100644 --- a/src/goMain.ts +++ b/src/goMain.ts @@ -31,6 +31,7 @@ import { installAllTools, checkLanguageServer } from './goInstallTools'; import { isGoPathSet, getBinPath, sendTelemetryEvent } from './util'; import { LanguageClient } from 'vscode-languageclient'; import { clearCacheForTools } from './goPath'; +import { addTags, removeTags } from './goModifytags'; let diagnosticCollection: vscode.DiagnosticCollection; @@ -101,6 +102,14 @@ export function activate(ctx: vscode.ExtensionContext): void { } })); + ctx.subscriptions.push(vscode.commands.registerCommand('go.add.tags', (args) => { + addTags(args); + })); + + ctx.subscriptions.push(vscode.commands.registerCommand('go.remove.tags', (args) => { + removeTags(args); + })); + ctx.subscriptions.push(vscode.commands.registerCommand('go.test.cursor', (args) => { let goConfig = vscode.workspace.getConfiguration('go'); testAtCursor(goConfig, args); diff --git a/src/goModifytags.ts b/src/goModifytags.ts new file mode 100644 index 000000000..6fe00f53d --- /dev/null +++ b/src/goModifytags.ts @@ -0,0 +1,140 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------*/ + +'use strict'; + +import vscode = require('vscode'); +import { byteOffsetAt, getBinPath } from './util'; +import cp = require('child_process'); +import { promptForMissingTool } from './goInstallTools'; + +// Interface for the output from gomodifytags +interface GomodifytagsOutput { + start: number; + end: number; + lines: string[]; +} + +// Interface for settings configuration for adding and removing tags +interface GoTagsConfig { + tags: string; + options: string; + promptForTags: boolean; +} + +export function addTags(commandArgs: GoTagsConfig) { + let args = getCommonArgs(); + if (!args) { + return; + } + + getTagsAndOptions(vscode.workspace.getConfiguration('go')['addTags'], commandArgs).then(([tags, options]) => { + if (!tags && !options) { + return; + } + if (tags) { + args.push('--add-tags'); + args.push(tags); + } + if (options) { + args.push('--add-options'); + args.push(options); + } + runGomodifytags(args); + }); + +} + +export function removeTags(commandArgs: GoTagsConfig) { + let args = getCommonArgs(); + if (!args) { + return; + } + + getTagsAndOptions(vscode.workspace.getConfiguration('go')['removeTags'], commandArgs).then(([tags, options]) => { + if (!tags && !options) { + args.push('--clear-tags'); + args.push('--clear-options'); + } + if (tags) { + args.push('--remove-tags'); + args.push(tags); + } + if (options) { + args.push('--remove-options'); + args.push(options); + } + runGomodifytags(args); + }); +} + +function getCommonArgs(): string[] { + let editor = vscode.window.activeTextEditor; + if (!editor) { + vscode.window.showInformationMessage('No editor is active.'); + return; + } + if (!editor.document.fileName.endsWith('.go')) { + vscode.window.showInformationMessage('Current file is not a Go file.'); + return; + } + let args = ['-modified', '-format', 'json']; + if (editor.selection.start.line === editor.selection.end.line && editor.selection.start.character === editor.selection.end.character) { + // Add tags to the whole struct + let offset = byteOffsetAt(editor.document, editor.selection.start); + args.push('-offset'); + args.push(offset.toString()); + } else if (editor.selection.start.line <= editor.selection.end.line) { + // Add tags to selected lines + args.push('-line'); + args.push(`${editor.selection.start.line + 1},${editor.selection.end.line + 1}`); + } + + return args; +} + +function getTagsAndOptions(config: GoTagsConfig, commandArgs: GoTagsConfig): Thenable { + let tags = commandArgs && commandArgs.hasOwnProperty('tags') ? commandArgs['tags'] : config['tags']; + let options = commandArgs && commandArgs.hasOwnProperty('options') ? commandArgs['options'] : config['options']; + let promptForTags = commandArgs && commandArgs.hasOwnProperty('promptForTags') ? commandArgs['promptForTags'] : config['promptForTags']; + + if (!promptForTags) { + return Promise.resolve([tags, options]); + } + + return vscode.window.showInputBox({ + value: 'json', + prompt: 'Enter comma separated tag names' + }).then(inputTags => { + return vscode.window.showInputBox({ + value: 'json=omitempty,xml=cdata', + prompt: 'Enter comma separated options' + }).then(inputOptions => { + return [inputTags, inputOptions]; + }); + }); +} + +function runGomodifytags(args: string[]) { + let gomodifytags = getBinPath('gomodifytags'); + let editor = vscode.window.activeTextEditor; + let fileContents = editor.document.getText(); + let input = editor.document.fileName + '\n' + fileContents.length + '\n' + fileContents; + let p = cp.execFile(gomodifytags, args, (err, stdout, stderr) => { + if (err && (err).code === 'ENOENT') { + promptForMissingTool('gomodifytags'); + return; + } + if (err) { + vscode.window.showInformationMessage(`Cannot modify tags: ${stderr}`); + return; + } + let output = JSON.parse(stdout); + vscode.window.activeTextEditor.edit(editBuilder => { + editBuilder.replace(new vscode.Range(output.start - 1, 0, output.end, 0), output.lines.join('\n') + '\n'); + }); + }); + p.stdin.end(input); +} \ No newline at end of file