src/goLanguageServer.ts: add config to overwrite vscode-go codelens

When gopls is enabled, it is used to identity code lens, which are then
intercepted by vscode-go. This CL adds a flag which is used to prevent
these codelens from being overwritten.

The flags are in this format in settings.json
"go.overwriteGoplsMiddleware": {
  "codelens": {
    "test": true,
    "bench": true,
    ...
  }
}

Change-Id: Ib1b1b64880afcae4519b2683fea9f081e7e86ff2
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/246265
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/docs/settings.md b/docs/settings.md
index 591b180..04ba5f7 100644
--- a/docs/settings.md
+++ b/docs/settings.md
@@ -161,6 +161,10 @@
 
 Use gotype on the file currently being edited and report any semantic or syntactic errors found after configured delay.
 
+### `go.overwriteGoplsMiddleware`
+
+This option provides a set of flags which determine if vscode-go should intercept certain commands from gopls. These flags assume the `gopls` settings, which enable codelens from gopls, are also present.
+
 ### `go.playground`
 
 
diff --git a/package.json b/package.json
index 84840e0..271b7cc 100644
--- a/package.json
+++ b/package.json
@@ -1575,6 +1575,34 @@
           "description": "Feature level setting to enable/disable code lens for references and run/debug tests",
           "scope": "resource"
         },
+        "go.overwriteGoplsMiddleware": {
+          "type": "object",
+          "properties": {
+            "codelens": {
+              "type": "object",
+              "properties": {
+                "test": {
+                  "type": "boolean",
+                  "default": false,
+                  "description": "'test' codelens will be handled by gopls if true"
+                },
+                "bench": {
+                  "type": "boolean",
+                  "default": false,
+                  "description": "'benchmark' codelens will be handled by gopls if true"
+                }
+              }
+            },
+            "default": {
+              "codelens": {
+                "test": false,
+                "bench": false
+              }
+            }
+          },
+          "scope": "resource",
+          "description": "This option provides a set of flags which determine if vscode-go should intercept certain commands from gopls. These flags assume the `gopls` settings, which enable codelens from gopls, are also present."
+        },
         "go.addTags": {
           "type": "object",
           "properties": {
diff --git a/src/goLanguageServer.ts b/src/goLanguageServer.ts
index 22c0938..6ba2bb8 100644
--- a/src/goLanguageServer.ts
+++ b/src/goLanguageServer.ts
@@ -18,7 +18,6 @@
 	CloseAction,
 	CompletionItemKind,
 	ErrorAction,
-	ExecuteCommandSignature,
 	HandleDiagnosticsSignature,
 	InitializeError,
 	LanguageClient,
@@ -268,39 +267,20 @@
 					if (!codeLens || codeLens.length === 0) {
 						return codeLens;
 					}
+					const goplsEnabledLens = (getGoConfig().get('overwriteGoplsMiddleware') as any)?.codelens ?? {};
 					return codeLens.reduce((lenses: vscode.CodeLens[], lens: vscode.CodeLens) => {
 						switch (lens.command.title) {
 							case 'run test': {
-								const args = lens.command.arguments;
-								return [
-									...lenses,
-									new vscode.CodeLens(lens.range, {
-										...lens.command,
-										command: 'go.test.cursor',
-										arguments: [{ functionName: args[args.indexOf('-run') + 1] }],
-									}),
-									new vscode.CodeLens(lens.range, {
-										title: 'debug test',
-										command: 'go.debug.cursor',
-										arguments: [{ functionName: args[args.indexOf('-run') + 1] }],
-									}),
-								];
+								if (goplsEnabledLens.test) {
+									return [...lenses, lens];
+								}
+								return [...lenses, ...createTestCodeLens(lens)];
 							}
 							case 'run benchmark': {
-								const args = lens.command.arguments;
-								return [
-									...lenses,
-									new vscode.CodeLens(lens.range, {
-										...lens.command,
-										command: 'go.benchmark.cursor',
-										arguments: [{ functionName: args[args.indexOf('-bench') + 1] }],
-									}),
-									new vscode.CodeLens(lens.range, {
-										title: 'debug benchmark',
-										command: 'go.debug.cursor',
-										arguments: [{ functionName: args[args.indexOf('-bench') + 1] }],
-									}),
-								];
+								if (goplsEnabledLens.bench) {
+									return [...lenses, lens];
+								}
+								return [...lenses, ...createBenchmarkCodeLens(lens)];
 							}
 							default: {
 								return [...lenses, lens];
@@ -420,6 +400,39 @@
 	return c;
 }
 
+// createTestCodeLens adds the go.test.cursor and go.debug.cursor code lens
+function createTestCodeLens(lens: vscode.CodeLens): vscode.CodeLens[] {
+	const args = lens.command.arguments;
+	return [
+		new vscode.CodeLens(lens.range, {
+			...lens.command,
+			command: 'go.test.cursor',
+			arguments: [{ functionName: args[args.indexOf('-run') + 1] }],
+		}),
+		new vscode.CodeLens(lens.range, {
+			title: 'debug test',
+			command: 'go.debug.cursor',
+			arguments: [{ functionName: args[args.indexOf('-run') + 1] }],
+		}),
+	];
+}
+
+function createBenchmarkCodeLens(lens: vscode.CodeLens): vscode.CodeLens[] {
+	const args = lens.command.arguments;
+	return [
+		new vscode.CodeLens(lens.range, {
+			...lens.command,
+			command: 'go.benchmark.cursor',
+			arguments: [{ functionName: args[args.indexOf('-bench') + 1] }],
+		}),
+		new vscode.CodeLens(lens.range, {
+			title: 'debug benchmark',
+			command: 'go.debug.cursor',
+			arguments: [{ functionName: args[args.indexOf('-bench') + 1] }],
+		}),
+	];
+}
+
 // registerUsualProviders registers the language feature providers if the language server is not enabled.
 function registerDefaultProviders(ctx: vscode.ExtensionContext) {
 	const completionProvider = new GoCompletionItemProvider(ctx.globalState);