Skip to content

Commit 9493800

Browse files
committed
extension/src: call gopls command for modify tags
When the user has the newer version of gopls, call the gopls command modify_tags which uses the modifytags library to implement adding and removing struct tags. If the user does not have the latest gopls, we maintain the old behavior of downloading and invoking the gomodifytags executable. Change-Id: If01e9ff0a1eeb127ec5139b5b3cb97ef938ce620 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/652017 Reviewed-by: Hongxiang Jiang <[email protected]> Reviewed-by: Robert Findley <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> kokoro-CI: kokoro <[email protected]>
1 parent 0b77054 commit 9493800

File tree

6 files changed

+150
-90
lines changed

6 files changed

+150
-90
lines changed

docs/commands.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,11 @@ Start the Go language server's maintainer interface (a web server).
169169

170170
### `Go: Add Tags To Struct Fields`
171171

172-
Add tags configured in go.addTags setting to selected struct using gomodifytags
172+
Add tags configured in go.addTags setting to selected struct using gomodifytags (via gopls)
173173

174174
### `Go: Remove Tags From Struct Fields`
175175

176-
Remove tags configured in go.removeTags setting from selected struct using gomodifytags
176+
Remove tags configured in go.removeTags setting from selected struct using gomodifytags (via gopls)
177177

178178
### `Go: Show All Commands...`
179179

docs/features.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ For known issues with this feature see [golang/go#37170](https://github.com/gola
253253

254254
### Add or remove struct tags
255255

256-
Use the [`Go: Add Tags to Struct Fields`](commands.md#go-add-tags-to-struct-fields) command to automatically generate or remove [tags](https://pkg.go.dev/reflect?tab=doc#StructTag) for your struct. This feature is provided by the [`gomodifytags`](tools.md#gomodifytags) tool.
256+
Use the [`Go: Add Tags to Struct Fields`](commands.md#go-add-tags-to-struct-fields) command to automatically generate or remove [tags](https://pkg.go.dev/reflect?tab=doc#StructTag) for your struct. This feature is provided by the [`gomodifytags`](tools.md#gomodifytags) tool invoked via gopls.
257257

258258
<div style="text-align: center;"><img src="images/addtagstostructfields.gif" alt="Add tags to struct fields" style="width: 75%"> </div>
259259

docs/tools.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ This tool provides support for the [`Go: Run on Go Playground`](features.md#go-p
4848

4949
### [`gomodifytags`](https://pkg.go.dev/github.com/fatih/gomodifytags?tab=overview)
5050

51-
This tool provides support for the [`Go: Add Tags to Struct Fields`](features.md#add-or-remove-struct-tags) and [`Go: Remove Tags From Struct Fields`](features.md#add-or-remove-struct-tags) commands.
51+
This tool provides support for the [`Go: Add Tags to Struct Fields`](features.md#add-or-remove-struct-tags) and [`Go: Remove Tags From Struct Fields`](features.md#add-or-remove-struct-tags) commands when using older versions of gopls. The latest
52+
version of gopls has a gopls.modify_tags command which directly invokes the
53+
gomodifytags library.
5254

5355
### [`impl`](https://github.com/josharian/impl)
5456

extension/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,12 +391,12 @@
391391
{
392392
"command": "go.add.tags",
393393
"title": "Go: Add Tags To Struct Fields",
394-
"description": "Add tags configured in go.addTags setting to selected struct using gomodifytags"
394+
"description": "Add tags configured in go.addTags setting to selected struct using gomodifytags (via gopls)"
395395
},
396396
{
397397
"command": "go.remove.tags",
398398
"title": "Go: Remove Tags From Struct Fields",
399-
"description": "Remove tags configured in go.removeTags setting from selected struct using gomodifytags"
399+
"description": "Remove tags configured in go.removeTags setting from selected struct using gomodifytags (via gopls)"
400400
},
401401
{
402402
"command": "go.show.commands",

extension/src/goModifytags.ts

Lines changed: 141 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,31 @@ import { promptForMissingTool, promptForUpdatingTool } from './goInstallTools';
1616
import { byteOffsetAt, getBinPath, getFileArchive } from './util';
1717
import { TelemetryKey, telemetryReporter } from './goTelemetry';
1818

19+
const COMMAND = 'gopls.modify_tags';
20+
1921
// Interface for the output from gomodifytags
2022
interface GomodifytagsOutput {
2123
start: number;
2224
end: number;
2325
lines: string[];
2426
}
2527

28+
// Interface for the arguments passed to gopls.modify_tags command. URI and range
29+
// are required parameters collected by the extension based on the open editor,
30+
// and the rest of the args are collected by user input or user settings.
31+
interface GoModifyTagsArgs {
32+
URI: string;
33+
range: vscode.Range;
34+
add?: string;
35+
addOptions?: string;
36+
remove?: string;
37+
removeOptions?: string;
38+
transform?: string;
39+
valueFormat?: string;
40+
clear?: boolean;
41+
clearOptions?: boolean;
42+
}
43+
2644
// Interface for settings configuration for adding and removing tags
2745
interface GoTagsConfig {
2846
[key: string]: any;
@@ -32,45 +50,84 @@ interface GoTagsConfig {
3250
template: string;
3351
}
3452

35-
export const addTags: CommandFactory = () => (commandArgs: GoTagsConfig) => {
36-
const args = getCommonArgs();
37-
if (!args) {
38-
return;
53+
export const addTags: CommandFactory = (_ctx, goCtx) => async (commandArgs: GoTagsConfig) => {
54+
const useGoplsCommand = goCtx.serverInfo?.Commands?.includes(COMMAND);
55+
if (useGoplsCommand) {
56+
const args = getCommonArgs();
57+
if (!args) {
58+
return;
59+
}
60+
const [tags, options, transformValue, template] = await getTagsAndOptions(getGoConfig()?.addTags, commandArgs);
61+
if (!tags && !options) {
62+
return;
63+
}
64+
if (tags) {
65+
args.add = tags;
66+
}
67+
if (options) {
68+
args.addOptions = options;
69+
}
70+
if (transformValue) {
71+
args.transform = transformValue;
72+
}
73+
if (template) {
74+
args.valueFormat = template;
75+
}
76+
await vscode.commands.executeCommand(COMMAND, args);
77+
} else {
78+
const args = getCommonArgsOld();
79+
if (!args) {
80+
return;
81+
}
82+
const [tags, options, transformValue, template] = await getTagsAndOptions(getGoConfig()?.addTags, commandArgs);
83+
if (!tags && !options) {
84+
return;
85+
}
86+
if (tags) {
87+
args.push('--add-tags');
88+
args.push(tags);
89+
}
90+
if (options) {
91+
args.push('--add-options');
92+
args.push(options);
93+
}
94+
if (transformValue) {
95+
args.push('--transform');
96+
args.push(transformValue);
97+
}
98+
if (template) {
99+
args.push('--template');
100+
args.push(template);
101+
}
102+
runGomodifytags(args);
39103
}
40-
41-
getTagsAndOptions(<GoTagsConfig>getGoConfig()['addTags'], commandArgs).then(
42-
([tags, options, transformValue, template]) => {
43-
if (!tags && !options) {
44-
return;
45-
}
46-
if (tags) {
47-
args.push('--add-tags');
48-
args.push(tags);
49-
}
50-
if (options) {
51-
args.push('--add-options');
52-
args.push(options);
53-
}
54-
if (transformValue) {
55-
args.push('--transform');
56-
args.push(transformValue);
57-
}
58-
if (template) {
59-
args.push('--template');
60-
args.push(template);
61-
}
62-
runGomodifytags(args);
63-
}
64-
);
65104
};
66105

67-
export const removeTags: CommandFactory = () => (commandArgs: GoTagsConfig) => {
68-
const args = getCommonArgs();
69-
if (!args) {
70-
return;
71-
}
72-
73-
getTagsAndOptions(<GoTagsConfig>getGoConfig()['removeTags'], commandArgs).then(([tags, options]) => {
106+
export const removeTags: CommandFactory = (_ctx, goCtx) => async (commandArgs: GoTagsConfig) => {
107+
const useGoplsCommand = goCtx.serverInfo?.Commands?.includes(COMMAND);
108+
if (useGoplsCommand) {
109+
const args = getCommonArgs();
110+
if (!args) {
111+
return;
112+
}
113+
const [tags, options] = await getTagsAndOptions(getGoConfig()?.removeTags, commandArgs);
114+
if (!tags && !options) {
115+
args.clear = true;
116+
args.clearOptions = true;
117+
}
118+
if (tags) {
119+
args.remove = tags;
120+
}
121+
if (options) {
122+
args.removeOptions = options;
123+
}
124+
vscode.commands.executeCommand(COMMAND, args);
125+
} else {
126+
const args = getCommonArgsOld();
127+
if (!args) {
128+
return;
129+
}
130+
const [tags, options] = await getTagsAndOptions(getGoConfig()?.removeTags, commandArgs);
74131
if (!tags && !options) {
75132
args.push('--clear-tags');
76133
args.push('--clear-options');
@@ -84,18 +141,19 @@ export const removeTags: CommandFactory = () => (commandArgs: GoTagsConfig) => {
84141
args.push(options);
85142
}
86143
runGomodifytags(args);
87-
});
144+
}
88145
};
89146

90-
function getCommonArgs(): string[] {
147+
// getCommonArgsOld produces the flags used for executing the gomodifytags binary.
148+
function getCommonArgsOld(): string[] | undefined {
91149
const editor = vscode.window.activeTextEditor;
92150
if (!editor) {
93151
vscode.window.showInformationMessage('No editor is active.');
94-
return [];
152+
return undefined;
95153
}
96154
if (!editor.document.fileName.endsWith('.go')) {
97155
vscode.window.showInformationMessage('Current file is not a Go file.');
98-
return [];
156+
return undefined;
99157
}
100158
const args = ['-modified', '-file', editor.document.fileName, '-format', 'json'];
101159
if (
@@ -115,61 +173,61 @@ function getCommonArgs(): string[] {
115173
return args;
116174
}
117175

118-
function getTagsAndOptions(config: GoTagsConfig, commandArgs: GoTagsConfig): Thenable<(string | undefined)[]> {
119-
const tags = commandArgs && commandArgs.hasOwnProperty('tags') ? commandArgs['tags'] : config['tags'];
120-
const options = commandArgs && commandArgs.hasOwnProperty('options') ? commandArgs['options'] : config['options'];
121-
const promptForTags =
122-
commandArgs && commandArgs.hasOwnProperty('promptForTags')
123-
? commandArgs['promptForTags']
124-
: config['promptForTags'];
125-
const transformValue: string =
126-
commandArgs && commandArgs.hasOwnProperty('transform') ? commandArgs['transform'] : config['transform'];
127-
const format: string =
128-
commandArgs && commandArgs.hasOwnProperty('template') ? commandArgs['template'] : config['template'];
176+
// getCommonArgs produces the args used for calling the gopls.modify_tags command.
177+
function getCommonArgs(): GoModifyTagsArgs | undefined {
178+
const editor = vscode.window.activeTextEditor;
179+
if (!editor) {
180+
vscode.window.showInformationMessage('No editor is active.');
181+
return undefined;
182+
}
183+
if (!editor.document.fileName.endsWith('.go')) {
184+
vscode.window.showInformationMessage('Current file is not a Go file.');
185+
return undefined;
186+
}
187+
const args: GoModifyTagsArgs = {
188+
URI: editor.document.uri.toString(),
189+
range: editor.selection
190+
};
191+
return args;
192+
}
193+
194+
async function getTagsAndOptions(config: GoTagsConfig, commandArgs: GoTagsConfig): Promise<(string | undefined)[]> {
195+
const tags = commandArgs && commandArgs.tags ? commandArgs.tags : config.tags;
196+
const options = commandArgs && commandArgs.options ? commandArgs.options : config.options;
197+
const promptForTags = commandArgs && commandArgs.promptForTags ? commandArgs.promptForTags : config.promptForTags;
198+
const transformValue: string = commandArgs && commandArgs.transform ? commandArgs.transform : config.transform;
199+
const format: string = commandArgs && commandArgs.template ? commandArgs.template : config.template;
129200

130201
if (!promptForTags) {
131202
return Promise.resolve([tags, options, transformValue, format]);
132203
}
133204

134-
return vscode.window
135-
.showInputBox({
136-
value: tags,
137-
prompt: 'Enter comma separated tag names'
138-
})
139-
.then((inputTags) => {
140-
return vscode.window
141-
.showInputBox({
142-
value: options,
143-
prompt: 'Enter comma separated options'
144-
})
145-
.then((inputOptions) => {
146-
return vscode.window
147-
.showInputBox({
148-
value: transformValue,
149-
prompt: 'Enter transform value'
150-
})
151-
.then((transformOption) => {
152-
return vscode.window
153-
.showInputBox({
154-
value: format,
155-
prompt: 'Enter template value'
156-
})
157-
.then((template) => {
158-
return [inputTags, inputOptions, transformOption, template];
159-
});
160-
});
161-
});
162-
});
205+
const inputTags = await vscode.window.showInputBox({
206+
value: tags,
207+
prompt: 'Enter comma separated tag names'
208+
});
209+
const inputOptions = await vscode.window.showInputBox({
210+
value: options,
211+
prompt: 'Enter comma separated options'
212+
});
213+
const transformOption = await vscode.window.showInputBox({
214+
value: transformValue,
215+
prompt: 'Enter transform value'
216+
});
217+
const template = await vscode.window.showInputBox({
218+
value: format,
219+
prompt: 'Enter template value'
220+
});
221+
return [inputTags, inputOptions, transformOption, template];
163222
}
164223

165-
function runGomodifytags(args: string[]) {
224+
async function runGomodifytags(args: string[]) {
166225
telemetryReporter.add(TelemetryKey.TOOL_USAGE_GOMODIFYTAGS, 1);
167-
168-
const gomodifytags = getBinPath('gomodifytags');
169226
const editor = vscode.window.activeTextEditor;
170227
if (!editor) {
171228
return;
172229
}
230+
const gomodifytags = getBinPath('gomodifytags');
173231
const input = getFileArchive(editor.document);
174232
const p = cp.execFile(gomodifytags, args, { env: toolExecutionEnvironment() }, (err, stdout, stderr) => {
175233
if (err && (<any>err).code === 'ENOENT') {

extension/src/goToolsInformation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const allToolsInformation: { [key: string]: Tool } = {
99
name: 'gomodifytags',
1010
importPath: 'github.com/fatih/gomodifytags',
1111
modulePath: 'github.com/fatih/gomodifytags',
12-
replacedByGopls: false,
12+
replacedByGopls: true,
1313
isImportant: false,
1414
description: 'Modify tags on structs',
1515
defaultVersion: 'v1.17.0'

0 commit comments

Comments
 (0)