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

Use gomodifytags to add/remove tags from struct fields #880

Merged
merged 4 commits into from
Mar 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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).
Expand Down Expand Up @@ -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)
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
}
}
```

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
42 changes: 35 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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."
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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."
}
}
}
}
}
}
3 changes: 2 additions & 1 deletion src/goInstallTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions src/goMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
140 changes: 140 additions & 0 deletions src/goModifytags.ts
Original file line number Diff line number Diff line change
@@ -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(<GoTagsConfig>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(<GoTagsConfig>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<string[]> {
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 && (<any>err).code === 'ENOENT') {
promptForMissingTool('gomodifytags');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you detect whether the tool is installed earlier, before the user has entered tag names and everything?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could, but this is the model we follow for all other tools, so will not be changing this unless we change the rest of the places

return;
}
if (err) {
vscode.window.showInformationMessage(`Cannot modify tags: ${stderr}`);
return;
}
let output = <GomodifytagsOutput>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);
}