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 <hxjiang@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
kokoro-CI: kokoro <noreply+kokoro@google.com>
diff --git a/docs/commands.md b/docs/commands.md
index cd61af7..6730c7c 100644
--- a/docs/commands.md
+++ b/docs/commands.md
@@ -169,11 +169,11 @@
### `Go: Add Tags To Struct Fields`
-Add tags configured in go.addTags setting to selected struct using gomodifytags
+Add tags configured in go.addTags setting to selected struct using gomodifytags (via gopls)
### `Go: Remove Tags From Struct Fields`
-Remove tags configured in go.removeTags setting from selected struct using gomodifytags
+Remove tags configured in go.removeTags setting from selected struct using gomodifytags (via gopls)
### `Go: Show All Commands...`
diff --git a/docs/features.md b/docs/features.md
index 953ac4b..4396c32 100644
--- a/docs/features.md
+++ b/docs/features.md
@@ -253,7 +253,7 @@
### Add or remove struct tags
-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.
+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.
<div style="text-align: center;"><img src="images/addtagstostructfields.gif" alt="Add tags to struct fields" style="width: 75%"> </div>
diff --git a/docs/tools.md b/docs/tools.md
index 10ff1ed..fc09e84 100644
--- a/docs/tools.md
+++ b/docs/tools.md
@@ -48,7 +48,9 @@
### [`gomodifytags`](https://pkg.go.dev/github.com/fatih/gomodifytags?tab=overview)
-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.
+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
+version of gopls has a gopls.modify_tags command which directly invokes the
+gomodifytags library.
### [`impl`](https://github.com/josharian/impl)
diff --git a/extension/package.json b/extension/package.json
index 14bd3ab..6928346 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -391,12 +391,12 @@
{
"command": "go.add.tags",
"title": "Go: Add Tags To Struct Fields",
- "description": "Add tags configured in go.addTags setting to selected struct using gomodifytags"
+ "description": "Add tags configured in go.addTags setting to selected struct using gomodifytags (via gopls)"
},
{
"command": "go.remove.tags",
"title": "Go: Remove Tags From Struct Fields",
- "description": "Remove tags configured in go.removeTags setting from selected struct using gomodifytags"
+ "description": "Remove tags configured in go.removeTags setting from selected struct using gomodifytags (via gopls)"
},
{
"command": "go.show.commands",
diff --git a/extension/src/goModifytags.ts b/extension/src/goModifytags.ts
index faf00e7..d097031 100644
--- a/extension/src/goModifytags.ts
+++ b/extension/src/goModifytags.ts
@@ -16,6 +16,8 @@
import { byteOffsetAt, getBinPath, getFileArchive } from './util';
import { TelemetryKey, telemetryReporter } from './goTelemetry';
+const COMMAND = 'gopls.modify_tags';
+
// Interface for the output from gomodifytags
interface GomodifytagsOutput {
start: number;
@@ -23,6 +25,22 @@
lines: string[];
}
+// Interface for the arguments passed to gopls.modify_tags command. URI and range
+// are required parameters collected by the extension based on the open editor,
+// and the rest of the args are collected by user input or user settings.
+interface GoModifyTagsArgs {
+ URI: string;
+ range: vscode.Range;
+ add?: string;
+ addOptions?: string;
+ remove?: string;
+ removeOptions?: string;
+ transform?: string;
+ valueFormat?: string;
+ clear?: boolean;
+ clearOptions?: boolean;
+}
+
// Interface for settings configuration for adding and removing tags
interface GoTagsConfig {
[key: string]: any;
@@ -32,45 +50,84 @@
template: string;
}
-export const addTags: CommandFactory = () => (commandArgs: GoTagsConfig) => {
- const args = getCommonArgs();
- if (!args) {
- return;
- }
-
- getTagsAndOptions(<GoTagsConfig>getGoConfig()['addTags'], commandArgs).then(
- ([tags, options, transformValue, template]) => {
- if (!tags && !options) {
- return;
- }
- if (tags) {
- args.push('--add-tags');
- args.push(tags);
- }
- if (options) {
- args.push('--add-options');
- args.push(options);
- }
- if (transformValue) {
- args.push('--transform');
- args.push(transformValue);
- }
- if (template) {
- args.push('--template');
- args.push(template);
- }
- runGomodifytags(args);
+export const addTags: CommandFactory = (_ctx, goCtx) => async (commandArgs: GoTagsConfig) => {
+ const useGoplsCommand = goCtx.serverInfo?.Commands?.includes(COMMAND);
+ if (useGoplsCommand) {
+ const args = getCommonArgs();
+ if (!args) {
+ return;
}
- );
+ const [tags, options, transformValue, template] = await getTagsAndOptions(getGoConfig()?.addTags, commandArgs);
+ if (!tags && !options) {
+ return;
+ }
+ if (tags) {
+ args.add = tags;
+ }
+ if (options) {
+ args.addOptions = options;
+ }
+ if (transformValue) {
+ args.transform = transformValue;
+ }
+ if (template) {
+ args.valueFormat = template;
+ }
+ await vscode.commands.executeCommand(COMMAND, args);
+ } else {
+ const args = getCommonArgsOld();
+ if (!args) {
+ return;
+ }
+ const [tags, options, transformValue, template] = await getTagsAndOptions(getGoConfig()?.addTags, commandArgs);
+ if (!tags && !options) {
+ return;
+ }
+ if (tags) {
+ args.push('--add-tags');
+ args.push(tags);
+ }
+ if (options) {
+ args.push('--add-options');
+ args.push(options);
+ }
+ if (transformValue) {
+ args.push('--transform');
+ args.push(transformValue);
+ }
+ if (template) {
+ args.push('--template');
+ args.push(template);
+ }
+ runGomodifytags(args);
+ }
};
-export const removeTags: CommandFactory = () => (commandArgs: GoTagsConfig) => {
- const args = getCommonArgs();
- if (!args) {
- return;
- }
-
- getTagsAndOptions(<GoTagsConfig>getGoConfig()['removeTags'], commandArgs).then(([tags, options]) => {
+export const removeTags: CommandFactory = (_ctx, goCtx) => async (commandArgs: GoTagsConfig) => {
+ const useGoplsCommand = goCtx.serverInfo?.Commands?.includes(COMMAND);
+ if (useGoplsCommand) {
+ const args = getCommonArgs();
+ if (!args) {
+ return;
+ }
+ const [tags, options] = await getTagsAndOptions(getGoConfig()?.removeTags, commandArgs);
+ if (!tags && !options) {
+ args.clear = true;
+ args.clearOptions = true;
+ }
+ if (tags) {
+ args.remove = tags;
+ }
+ if (options) {
+ args.removeOptions = options;
+ }
+ vscode.commands.executeCommand(COMMAND, args);
+ } else {
+ const args = getCommonArgsOld();
+ if (!args) {
+ return;
+ }
+ const [tags, options] = await getTagsAndOptions(getGoConfig()?.removeTags, commandArgs);
if (!tags && !options) {
args.push('--clear-tags');
args.push('--clear-options');
@@ -84,18 +141,19 @@
args.push(options);
}
runGomodifytags(args);
- });
+ }
};
-function getCommonArgs(): string[] {
+// getCommonArgsOld produces the flags used for executing the gomodifytags binary.
+function getCommonArgsOld(): string[] | undefined {
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active.');
- return [];
+ return undefined;
}
if (!editor.document.fileName.endsWith('.go')) {
vscode.window.showInformationMessage('Current file is not a Go file.');
- return [];
+ return undefined;
}
const args = ['-modified', '-file', editor.document.fileName, '-format', 'json'];
if (
@@ -115,61 +173,61 @@
return args;
}
-function getTagsAndOptions(config: GoTagsConfig, commandArgs: GoTagsConfig): Thenable<(string | undefined)[]> {
- const tags = commandArgs && commandArgs.hasOwnProperty('tags') ? commandArgs['tags'] : config['tags'];
- const options = commandArgs && commandArgs.hasOwnProperty('options') ? commandArgs['options'] : config['options'];
- const promptForTags =
- commandArgs && commandArgs.hasOwnProperty('promptForTags')
- ? commandArgs['promptForTags']
- : config['promptForTags'];
- const transformValue: string =
- commandArgs && commandArgs.hasOwnProperty('transform') ? commandArgs['transform'] : config['transform'];
- const format: string =
- commandArgs && commandArgs.hasOwnProperty('template') ? commandArgs['template'] : config['template'];
+// getCommonArgs produces the args used for calling the gopls.modify_tags command.
+function getCommonArgs(): GoModifyTagsArgs | undefined {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ vscode.window.showInformationMessage('No editor is active.');
+ return undefined;
+ }
+ if (!editor.document.fileName.endsWith('.go')) {
+ vscode.window.showInformationMessage('Current file is not a Go file.');
+ return undefined;
+ }
+ const args: GoModifyTagsArgs = {
+ URI: editor.document.uri.toString(),
+ range: editor.selection
+ };
+ return args;
+}
+
+async function getTagsAndOptions(config: GoTagsConfig, commandArgs: GoTagsConfig): Promise<(string | undefined)[]> {
+ const tags = commandArgs && commandArgs.tags ? commandArgs.tags : config.tags;
+ const options = commandArgs && commandArgs.options ? commandArgs.options : config.options;
+ const promptForTags = commandArgs && commandArgs.promptForTags ? commandArgs.promptForTags : config.promptForTags;
+ const transformValue: string = commandArgs && commandArgs.transform ? commandArgs.transform : config.transform;
+ const format: string = commandArgs && commandArgs.template ? commandArgs.template : config.template;
if (!promptForTags) {
return Promise.resolve([tags, options, transformValue, format]);
}
- return vscode.window
- .showInputBox({
- value: tags,
- prompt: 'Enter comma separated tag names'
- })
- .then((inputTags) => {
- return vscode.window
- .showInputBox({
- value: options,
- prompt: 'Enter comma separated options'
- })
- .then((inputOptions) => {
- return vscode.window
- .showInputBox({
- value: transformValue,
- prompt: 'Enter transform value'
- })
- .then((transformOption) => {
- return vscode.window
- .showInputBox({
- value: format,
- prompt: 'Enter template value'
- })
- .then((template) => {
- return [inputTags, inputOptions, transformOption, template];
- });
- });
- });
- });
+ const inputTags = await vscode.window.showInputBox({
+ value: tags,
+ prompt: 'Enter comma separated tag names'
+ });
+ const inputOptions = await vscode.window.showInputBox({
+ value: options,
+ prompt: 'Enter comma separated options'
+ });
+ const transformOption = await vscode.window.showInputBox({
+ value: transformValue,
+ prompt: 'Enter transform value'
+ });
+ const template = await vscode.window.showInputBox({
+ value: format,
+ prompt: 'Enter template value'
+ });
+ return [inputTags, inputOptions, transformOption, template];
}
-function runGomodifytags(args: string[]) {
+async function runGomodifytags(args: string[]) {
telemetryReporter.add(TelemetryKey.TOOL_USAGE_GOMODIFYTAGS, 1);
-
- const gomodifytags = getBinPath('gomodifytags');
const editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
+ const gomodifytags = getBinPath('gomodifytags');
const input = getFileArchive(editor.document);
const p = cp.execFile(gomodifytags, args, { env: toolExecutionEnvironment() }, (err, stdout, stderr) => {
if (err && (<any>err).code === 'ENOENT') {
diff --git a/extension/src/goToolsInformation.ts b/extension/src/goToolsInformation.ts
index 2a0ee8b..f4c81b3 100644
--- a/extension/src/goToolsInformation.ts
+++ b/extension/src/goToolsInformation.ts
@@ -9,7 +9,7 @@
name: 'gomodifytags',
importPath: 'github.com/fatih/gomodifytags',
modulePath: 'github.com/fatih/gomodifytags',
- replacedByGopls: false,
+ replacedByGopls: true,
isImportant: false,
description: 'Modify tags on structs',
defaultVersion: 'v1.17.0'