src/goVulncheck: remove the experimental "Go: Run Vulncheck" command

With gopls v0.11.0, gopls will manage the execution of govulncheck
and produce diagnostics from the result.

Change-Id: I40cec4ba7aac328cad1e0ffcdcb9cbc0e6ef32f3
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/455556
TryBot-Result: kokoro <noreply+kokoro@google.com>
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/docs/commands.md b/docs/commands.md
index 2752332..b3d2ee6 100644
--- a/docs/commands.md
+++ b/docs/commands.md
@@ -266,7 +266,3 @@
 ### `Go: Reset Workspace Env`
 
 Reset the Go Env for the active workspace.
-
-### `Go: Run Vulncheck (Preview)`
-
-Run vulnerability check. See https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck for more details about the analysis.
diff --git a/media/vulncheckView.css b/media/vulncheckView.css
deleted file mode 100644
index 4531979..0000000
--- a/media/vulncheckView.css
+++ /dev/null
@@ -1,69 +0,0 @@
-/*---------------------------------------------------------
- * Copyright 2022 The Go Authors. All rights reserved.
- * Licensed under the MIT License. See LICENSE in the project root for license information.
- *--------------------------------------------------------*/
-
-.debug,
-.info {
-	font-weight: lighter;
-	padding-bottom: 1em;
-}
-
-.log,
-.vuln {
-	text-align: left;
-	padding-bottom: 1em;
-}
-
-.vuln-icon-info, .vuln-icon-warning {
-	padding-right: 1em;
-	font-size: 14px;
-	display: inline;
-}
-
-.vuln-icon-info {
-	color: var(--vscode-list-warningForeground);
-}
-
-.vuln-icon-warning {
-	color: var(--vscode-list-errorForeground);
-}
-
-.vuln-desc {
-	padding-top: 0.5em;
-	padding-bottom: 0.5em;
-}
-
-.vuln-details {
-	padding-bottom: 0.5em;
-}
-
-.vuln-fix:hover,
-.vuln-fix:active {
-	color: var(--vscode-textLink-activeForeground);
-}
-.vuln-fix {
-	cursor:pointer;
-	color: var(--vscode-textLink-foreground);
-	text-decoration:underline;
-}
-
-details summary {
-	cursor: pointer;
-	position: relative;
-}
-
-details summary>* {
-	display: inline;
-	position: relative;
-}
-
-.stacks {
-	padding: 1em;
-}
-
-.stack {
-	padding: 1em;
-	font-size: var(--vscode-editor-font-size);
-	font-family: var(--vscode-editor-font-family);
-}
\ No newline at end of file
diff --git a/media/vulncheckView.js b/media/vulncheckView.js
deleted file mode 100644
index a435f74..0000000
--- a/media/vulncheckView.js
+++ /dev/null
@@ -1,261 +0,0 @@
-/*---------------------------------------------------------
- * Copyright 2022 The Go Authors. All rights reserved.
- * Licensed under the MIT License. See LICENSE in the project root for license information.
- *--------------------------------------------------------*/
-
-// Script for VulncheckResultViewProvider's webview.
-
-(function () {
-
-	// @ts-ignore
-	const vscode = acquireVsCodeApi();
-
-	const logContainer = /** @type {HTMLElement} */ (document.querySelector('.log'));
-	const vulnsContainer = /** @type {HTMLElement} */ (document.querySelector('.vulns'));
-	const unaffectingContainer = /** @type {HTMLElement} */ (document.querySelector('.unaffecting'));
-	const debugContainer = /** @type {HTMLElement} */ (document.querySelector('.debug'));
-
-	vulnsContainer.addEventListener('click', (event) => {
-		let node = event && event.target;
-		let handled = false;
-		console.log(`${node.type} ${node.tagName} ${node.className} ${node.id} data:${node.dataset?.target} dir:${node.dataset?.dir}`);
-		if (node?.tagName === 'A' && node.href) {
-			// Ask vscode to handle link opening.
-			vscode.postMessage({ type: 'open', target: node.href });
-		} else if (node?.tagName === 'SPAN' && node.className === 'vuln-fix' && node.dataset?.target && node.dataset?.dir) {
-			vscode.postMessage({ type: 'fix', target: node.dataset?.target, dir: node.dataset?.dir });
-		}
-
-		if (handled) {
-			event.preventDefault();
-			event.stopPropagation();
-		}
-	});
-
-	const errorContainer = document.createElement('div');
-	document.body.appendChild(errorContainer);
-	errorContainer.className = 'error'
-	errorContainer.style.display = 'none'
-
-	function packageVersion(/** @type {string} */mod, /** @type {string} */pkg, /** @type {string|undefined} */ver) {
-		if (!ver) {
-			return 'N/A';
-		}
-
-		if (mod === 'stdlib' && ver.startsWith('v')) {
-			ver = `go${ver.slice(1)}`;
-		}
-		return `<a href="https://pkg.go.dev/${pkg}@${ver}">${pkg}@${ver}</a>`;
-	}
-
-	function modVersion(/** @type {string} */mod, /** @type {string|undefined} */ver) {
-		if (!ver) {
-			return 'N/A';
-		}
-
-		if (mod === 'stdlib' && ver.startsWith('v')) {
-			ver = `go${ver.slice(1)}`;
-		}
-		return `<a href="https://pkg.go.dev/${mod}@${ver}">${mod}@${ver}</a>`;
-	}
-
-	function offerUpgrade(/** @type {string} */dir, /** @type {string} */mod, /** @type {string|undefined} */ver) {
-		if (mod === 'stdlib') {
-			return '';
-		}
-		if (dir && mod && ver) {
-			return ` [<span class="vuln-fix" data-target="${mod}@${ver}" data-dir="${dir}">go get</span> | <span class="vuln-fix" data-target="${mod}@latest" data-dir="${dir}">go get latest</span>]`
-		}
-		return '';
-	}
-
-	function snapshotContent() {
-		const res = {
-			'log': logContainer.innerHTML,
-			'vulns': vulnsContainer.innerHTML,
-			'unaffecting': unaffectingContainer.innerHTML
-		};
-		return JSON.stringify(res);
-	}
-
-	/**
-	 * Render the document in the webview.
-	 */
-	function updateContent(/** @type {string} */ text = '{}') {
-		let json;
-		try {
-			json = JSON.parse(text);
-		} catch {
-			errorContainer.innerText = 'Error: Document is not valid json';
-			errorContainer.style.display = '';
-			return;
-		}
-		errorContainer.style.display = 'none';
-
-		const timeinfo = (startDate, durationMillisec) => {
-			if (!startDate) { return '' }
-			return durationMillisec ? `${startDate} (took ${durationMillisec} msec)` : `${startDate}`;
-		}
-		debugContainer.innerHTML = `Analyzed at: ${timeinfo(json.Start, json.Duration)}`;
-
-		const vulns = json.Vuln || [];
-		const affecting = vulns.filter((v) => v.CallStackSummaries?.length);
-		const unaffecting = vulns.filter((v) => !v.CallStackSummaries?.length);
-
-		logContainer.innerHTML = `
-<pre>cd ${json.Dir || ''}; govulncheck ${json.Pattern || ''}</pre>
-Found ${affecting?.length || 0} known vulnerabilities.`;
-		
-		vulnsContainer.innerHTML = '';
-		affecting.forEach((vuln) => {
-			const element = document.createElement('div');
-			element.className = 'vuln';
-			vulnsContainer.appendChild(element);
-
-			// TITLE - Vuln ID
-			const title = document.createElement('h2');
-			title.innerHTML = `<div class="vuln-icon-warning"><i class="codicon codicon-warning"></i></div><a href="${vuln.URL}">${vuln.ID}</a>`;
-			title.className = 'vuln-title';
-			element.appendChild(title);
-
-			// DESCRIPTION - short text (aliases)
-			const desc = document.createElement('p');
-			desc.innerHTML = Array.isArray(vuln.Aliases) && vuln.Aliases.length ? `${vuln.Details} (${vuln.Aliases.join(', ')})` : vuln.Details;
-			desc.className = 'vuln-desc';
-			element.appendChild(desc);
-
-			// DETAILS - dump of all details
-			const details = document.createElement('table');
-			details.className = 'vuln-details'
-			details.innerHTML = `
-			<tr><td>Package</td><td>${vuln.PkgPath}</td></tr>
-			<tr><td>Found in Version</td><td>${packageVersion(vuln.ModPath, vuln.PkgPath, vuln.CurrentVersion)}</td></tr>
-			<tr><td>Fixed Version</td><td>${packageVersion(vuln.ModPath, vuln.PkgPath, vuln.FixedVersion)} ${offerUpgrade(json.Dir, vuln.ModPath, vuln.FixedVersion)}</td></tr>
-			<tr><td>Affecting</td><td>${vuln.AffectedPkgs?.join('<br>')}</td></tr>
-			`;
-			element.appendChild(details);
-
-			/* TODO: Action for module version upgrade */
-			/* TODO: Explain module dependency - why am I depending on this vulnerable version? */
-
-			// EXEMPLARS - call stacks (initially hidden)
-			const examples = document.createElement('details');
-			examples.innerHTML = `<summary>${vuln.CallStackSummaries?.length || 0}+ findings</summary>`;
-
-			// Call stacks
-			const callstacksContainer = document.createElement('p');
-			callstacksContainer.className = 'stacks';
-			vuln.CallStackSummaries?.forEach((summary, idx) => {
-				const callstack = document.createElement('details');
-				const s = document.createElement('summary');
-				s.innerText = summary;
-				callstack.appendChild(s);
-
-				const stack = document.createElement('div');
-				stack.className = 'stack';
-				const cs = vuln.CallStacks[idx];
-				cs.forEach((c) => {
-					const p = document.createElement('p');
-					const pos = c.URI ? `${c.URI}?${c.Pos.line || 0}` : '';
-					p.innerHTML = pos ? `<a href="${pos}">${c.Name}</a>` : c.Name;
-					stack.appendChild(p);
-				});
-				callstack.appendChild(stack);
-
-				callstacksContainer.appendChild(callstack);
-			})
-
-			examples.appendChild(callstacksContainer);
-			element.appendChild(examples);
-		});
-
-		unaffectingContainer.innerText = '';
-		if (unaffecting.length > 0) {
-			const notice = document.createElement('div');
-			notice.className = 'info';
-			notice.innerHTML = `
-<hr></hr>The vulnerabilities below are in packages that you import, 
-but your code does not appear to call any vulnerable functions. 
-You may not need to take any action. See 
-<a href="https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck">
-https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck</a>
-for details.
-`;
-
-			unaffectingContainer.appendChild(notice);
-
-			unaffecting.forEach((vuln) => {
-				const element = document.createElement('div');
-				element.className = 'vuln';
-				unaffectingContainer.appendChild(element);
-
-				// TITLE - Vuln ID
-				const title = document.createElement('h2');
-				title.innerHTML = `<div class="vuln-icon-info"><i class="codicon codicon-info"></i></div><a href="${vuln.URL}">${vuln.ID}</a>`;
-				title.className = 'vuln-title';
-				element.appendChild(title);
-
-				// DESCRIPTION - short text (aliases)
-				const desc = document.createElement('p');
-				desc.innerHTML = Array.isArray(vuln.Aliases) && vuln.Aliases.length ? `${vuln.Details} (${vuln.Aliases.join(', ')})` : vuln.Details;
-				desc.className = 'vuln-desc';
-				element.appendChild(desc);
-
-				// DETAILS - dump of all details
-				// TODO(hyangah):
-				//   - include the current version & package name when gopls provides them.
-				//   - offer upgrade like affect vulnerabilities. We will need to install another event listener
-				//     on unaffectingContainer. See vulnsContainer.addEventListener.
-				const details = document.createElement('table');
-				details.className = 'vuln-details'
-				if (vuln.FixedVersion) {
-					details.innerHTML = `<tr><td>Fixed Version</td><td>${modVersion(vuln.ModPath, vuln.FixedVersion)}</td></tr>`;
-				} else {
-					details.innerHTML = `<tr><td>Fixed Version</td><td>unavailable for ${vuln.ModPath}</td></tr>`;
-				}
-				element.appendChild(details);
-			});
-		}
-	}
-
-	// Message Passing between Extension and Webview
-	//
-	//  Extension sends 'update' to Webview to trigger rerendering.
-	//  Webview sends 'link' to Extension to forward all link
-	//     click events so the extension can handle the event.
-	//
-	//  Extension sends 'snapshot-request' to trigger dumping
-	//     of the current DOM in the 'vulns' container.
-	//  Webview sends 'snapshot-result' to the extension
-	//     as the response to snapshot-request.
-
-	// Handle messages sent from the extension to the webview
-	window.addEventListener('message', event => {
-		const message = event.data; // The json data that the extension sent
-		switch (message.type) {
-			case 'update':
-				const text = message.text;
-
-				updateContent(text);
-				// Then persist state information.
-				// This state is returned in the call to `vscode.getState` below when a webview is reloaded.
-				vscode.setState({ text });
-				return;
-			// Message for testing. Returns a current DOM in a serialized format.
-			case 'snapshot-request':
-				const result = snapshotContent();
-				vscode.postMessage({ type: 'snapshot-result', target: result });
-				return;
-		}
-	});
-
-	// Webviews are normally torn down when not visible and re-created when they become visible again.
-	// State lets us save information across these re-loads
-	const state = vscode.getState();
-	if (state) {
-		updateContent(state.text);
-	};
-	// TODO: Handle 'details' expansion info and store the state using
-	// vscode.setState or retainContextWhenHidden. Currently, we are storing only
-	// the document text. (see windowEventHandler)
-}());
diff --git a/package.json b/package.json
index f5b47e4..83203f6 100644
--- a/package.json
+++ b/package.json
@@ -537,12 +537,6 @@
         "description": "Reset the Go Env for the active workspace.",
         "icon": "$(settings-remove)",
         "enablement": "workspaceFolderCount > 0"
-      },
-      {
-        "command": "go.vulncheck.run",
-        "title": "Go: Run Vulncheck (Preview)",
-        "description": "Run vulnerability check. See https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck for more details about the analysis.",
-        "enablement": "go.goplsIsRunning"
       }
     ],
     "breakpoints": [
@@ -2857,17 +2851,6 @@
           "when": "go.hasProfiles"
         }
       ]
-    },
-    "customEditors": [
-      {
-        "viewType": "vulncheck.view",
-        "displayName": "Vulnerability Report",
-        "selector": [
-          {
-            "filenamePattern": "*.vulncheck.json"
-          }
-        ]
-      }
-    ]
+    }
   }
 }
\ No newline at end of file
diff --git a/src/goMain.ts b/src/goMain.ts
index 873f2eb..67f144d 100644
--- a/src/goMain.ts
+++ b/src/goMain.ts
@@ -64,8 +64,6 @@
 import { GoTestExplorer, isVscodeTestingAPIAvailable } from './goTest/explore';
 import { killRunningPprof } from './goTest/profile';
 import { GoExplorerProvider } from './goExplorer';
-import { VulncheckProvider, VulncheckResultViewProvider } from './goVulncheck';
-
 import { GoExtensionContext } from './context';
 import * as commands from './commands';
 
@@ -170,8 +168,6 @@
 	}
 
 	GoExplorerProvider.setup(ctx);
-	VulncheckProvider.setup(ctx, goCtx);
-	VulncheckResultViewProvider.register(ctx, goCtx);
 
 	registerCommand('go.test.generate.package', goGenerateTests.generateTestCurrentPackage);
 	registerCommand('go.test.generate.file', goGenerateTests.generateTestCurrentFile);
diff --git a/src/goVulncheck.ts b/src/goVulncheck.ts
deleted file mode 100644
index 7866655..0000000
--- a/src/goVulncheck.ts
+++ /dev/null
@@ -1,479 +0,0 @@
-/*---------------------------------------------------------
- * Copyright 2022 The Go Authors. All rights reserved.
- * Licensed under the MIT License. See LICENSE in the project root for license information.
- *--------------------------------------------------------*/
-
-import path from 'path';
-import fs from 'fs';
-import * as vscode from 'vscode';
-import { GoExtensionContext } from './context';
-import { getBinPath } from './util';
-import * as cp from 'child_process';
-import { toolExecutionEnvironment } from './goEnv';
-import { killProcessTree } from './utils/processUtils';
-import * as readline from 'readline';
-import { URI } from 'vscode-uri';
-import { promisify } from 'util';
-import { runGoEnv } from './goModules';
-import { ExecuteCommandParams, ExecuteCommandRequest } from 'vscode-languageserver-protocol';
-
-export class VulncheckResultViewProvider implements vscode.CustomTextEditorProvider {
-	public static readonly viewType = 'vulncheck.view';
-
-	public static register(
-		{ extensionUri, subscriptions }: vscode.ExtensionContext,
-		goCtx: GoExtensionContext
-	): VulncheckResultViewProvider {
-		const provider = new VulncheckResultViewProvider(extensionUri, goCtx);
-		subscriptions.push(vscode.window.registerCustomEditorProvider(VulncheckResultViewProvider.viewType, provider));
-		return provider;
-	}
-
-	constructor(private readonly extensionUri: vscode.Uri, private readonly goCtx: GoExtensionContext) {}
-
-	/**
-	 * Called when our custom editor is opened.
-	 */
-	public async resolveCustomTextEditor(
-		document: vscode.TextDocument,
-		webviewPanel: vscode.WebviewPanel,
-		_: vscode.CancellationToken // eslint-disable-line @typescript-eslint/no-unused-vars
-	): Promise<void> {
-		// Setup initial content for the webview
-		webviewPanel.webview.options = { enableScripts: true };
-		webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview);
-
-		// Receive message from the webview.
-		webviewPanel.webview.onDidReceiveMessage(this.handleMessage, this);
-
-		function updateWebview() {
-			webviewPanel.webview.postMessage({ type: 'update', text: document.getText() });
-		}
-
-		// Hook up event handlers so that we can synchronize the webview with the text document.
-		//
-		// The text document acts as our model, so we have to sync change in the document to our
-		// editor and sync changes in the editor back to the document.
-		//
-		// Remember that a single text document can also be shared between multiple custom
-		// editors (this happens for example when you split a custom editor)
-		const changeDocumentSubscription = vscode.workspace.onDidChangeTextDocument((e) => {
-			if (e.document.uri.toString() === document.uri.toString()) {
-				updateWebview();
-			}
-		});
-
-		// Make sure we get rid of the listener when our editor is closed.
-		webviewPanel.onDidDispose(() => {
-			changeDocumentSubscription.dispose();
-		});
-
-		updateWebview();
-	}
-
-	/**
-	 * Get the static html used for the editor webviews.
-	 */
-	private getHtmlForWebview(webview: vscode.Webview): string {
-		const mediaUri = vscode.Uri.joinPath(this.extensionUri, 'media');
-		// Local path to script and css for the webview
-		const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(mediaUri, 'vulncheckView.js'));
-		const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath(mediaUri, 'reset.css'));
-		const styleVSCodeUri = webview.asWebviewUri(vscode.Uri.joinPath(mediaUri, 'vscode.css'));
-		const styleMainUri = webview.asWebviewUri(vscode.Uri.joinPath(mediaUri, 'vulncheckView.css'));
-		const codiconsUri = webview.asWebviewUri(vscode.Uri.joinPath(mediaUri, 'codicon.css'));
-
-		// Use a nonce to whitelist which scripts can be run
-		const nonce = getNonce();
-
-		return /* html */ `
-			<!DOCTYPE html>
-			<html lang="en">
-			<head>
-				<meta charset="UTF-8">
-				<!--
-				Use a content security policy to only allow loading images from https or from our extension directory,
-				and only allow scripts that have a specific nonce.
-				-->
-				<!--
-					Use a content security policy to only allow loading specific resources in the webview
-				-->
-				<meta http-equiv="Content-Security-Policy" content="default-src 'none'; font-src ${webview.cspSource}; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';">
-				<meta name="viewport" content="width=device-width, initial-scale=1.0">
-				<link href="${styleResetUri}" rel="stylesheet" />
-				<link href="${styleVSCodeUri}" rel="stylesheet" />
-				<link href="${styleMainUri}" rel="stylesheet" />
-				<link href="${codiconsUri}" rel="stylesheet" />
-				<title>Vulnerability Report - govulncheck</title>
-			</head>
-			<body>
-			    Vulncheck is an experimental tool.<br>
-				Share feedback at <a href="https://go.dev/s/vsc-vulncheck-feedback">go.dev/s/vsc-vulncheck-feedback</a>.
-
-				<div class="log"></div>
-				<div class="vulns"></div>
-				<div class="unaffecting"></div>
-				<div class="debug"></div>
-				<script nonce="${nonce}" src="${scriptUri}"></script>
-			</body>
-			</html>`;
-	}
-
-	private async handleMessage(e: { type: string; target?: string; dir?: string }): Promise<void> {
-		switch (e.type) {
-			case 'open':
-				{
-					if (!e.target) return;
-					const uri = safeURIParse(e.target);
-					if (!uri || !uri.scheme) return;
-					if (uri.scheme === 'https') {
-						vscode.env.openExternal(uri);
-					} else if (uri.scheme === 'file') {
-						const line = uri.query ? Number(uri.query.split(':')[0]) : undefined;
-						const range = line ? new vscode.Range(line, 0, line, 0) : undefined;
-						vscode.window.showTextDocument(
-							vscode.Uri.from({ scheme: uri.scheme, path: uri.path }),
-							// prefer the first column to present the source.
-							{ viewColumn: vscode.ViewColumn.One, selection: range }
-						);
-					}
-				}
-				return;
-			case 'fix':
-				{
-					if (!e.target || !e.dir) return;
-					const modFile = await getGoModFile(vscode.Uri.file(e.dir));
-					if (modFile) {
-						await goplsUpgradeDependency(this.goCtx, vscode.Uri.file(modFile), [e.target], false);
-						// TODO: run go mod tidy?
-					}
-				}
-				return;
-			case 'snapshot-result':
-				// response for `snapshot-request`.
-				return;
-			default:
-				console.log(`unrecognized type message: ${e.type}`);
-		}
-	}
-}
-
-const GOPLS_UPGRADE_DEPENDENCY = 'gopls.upgrade_dependency';
-async function goplsUpgradeDependency(
-	goCtx: GoExtensionContext,
-	goModFileUri: vscode.Uri,
-	goCmdArgs: string[],
-	addRequire: boolean
-): Promise<void> {
-	const { languageClient } = goCtx;
-	const uri = languageClient?.code2ProtocolConverter.asUri(goModFileUri);
-	const params: ExecuteCommandParams = {
-		command: GOPLS_UPGRADE_DEPENDENCY,
-		arguments: [
-			{
-				URI: uri,
-				GoCmdArgs: goCmdArgs,
-				AddRequire: addRequire
-			}
-		]
-	};
-	return await languageClient?.sendRequest(ExecuteCommandRequest.type, params);
-}
-
-async function getGoModFile(dir: vscode.Uri): Promise<string | undefined> {
-	try {
-		const p = await runGoEnv(dir, ['GOMOD']);
-		return p['GOMOD'] === '/dev/null' || p['GOMOD'] === 'NUL' ? '' : p['GOMOD'];
-	} catch (e) {
-		vscode.window.showErrorMessage(`Failed to find 'go.mod' for ${dir}: ${e}`);
-	}
-	return;
-}
-
-export class VulncheckProvider {
-	static scheme = 'govulncheck';
-	static setup({ subscriptions }: vscode.ExtensionContext, goCtx: GoExtensionContext) {
-		const channel = goCtx.govulncheckOutputChannel || vscode.window.createOutputChannel('govulncheck');
-		const instance = new this(channel);
-		subscriptions.push(
-			vscode.commands.registerCommand('go.vulncheck.run', async () => {
-				instance.run(goCtx);
-			})
-		);
-		return instance;
-	}
-
-	constructor(private channel: vscode.OutputChannel) {}
-
-	private running = false;
-
-	async run(goCtx: GoExtensionContext) {
-		if (this.running) {
-			vscode.window.showWarningMessage('another vulncheck is in progress');
-			return;
-		}
-		try {
-			this.running = true;
-			await this.runInternal(goCtx);
-		} finally {
-			this.running = false;
-		}
-	}
-
-	private async runInternal(goCtx: GoExtensionContext) {
-		const pick = await vscode.window.showQuickPick(['Current Package', 'Current Module', 'Workspace']);
-		let dir, pattern: string;
-		const document = vscode.window.activeTextEditor?.document;
-		switch (pick) {
-			case 'Current Package':
-				if (!document) {
-					vscode.window.showErrorMessage('vulncheck error: no current package');
-					return;
-				}
-				if (document.languageId !== 'go') {
-					vscode.window.showErrorMessage(
-						'File in the active editor is not a Go file, cannot find current package to check.'
-					);
-					return;
-				}
-				dir = path.dirname(document.fileName);
-				pattern = '.';
-				break;
-			case 'Current Module':
-				dir = await moduleDir(document);
-				if (!dir) {
-					vscode.window.showErrorMessage('vulncheck error: no current module');
-					return;
-				}
-				pattern = './...';
-				break;
-			case 'Workspace':
-				dir = await this.activeDir();
-				pattern = './...';
-				break;
-			default:
-				return;
-		}
-		if (!dir) {
-			return;
-		}
-
-		this.channel.clear();
-		this.channel.show();
-		this.channel.appendLine(`cd ${dir}; gopls vulncheck ${pattern}`);
-
-		try {
-			const start = new Date();
-			const vuln = await vulncheck(goCtx, dir, pattern, this.channel);
-
-			if (vuln?.Vuln?.length) {
-				fillAffectedPkgs(vuln.Vuln);
-
-				// record run info.
-				vuln.Start = start;
-				vuln.Duration = Date.now() - start.getTime();
-				vuln.Dir = dir;
-				vuln.Pattern = pattern;
-
-				// write to file and visualize it!
-				const fname = path.join(dir, `vulncheck-${Date.now()}.vulncheck.json`);
-				const writeFile = promisify(fs.writeFile);
-				await writeFile(fname, JSON.stringify(vuln));
-				const uri = URI.file(fname);
-				const viewColumn = vscode.ViewColumn.Beside;
-				vscode.commands.executeCommand(
-					'vscode.openWith',
-					uri,
-					VulncheckResultViewProvider.viewType,
-					viewColumn
-				);
-				this.channel.appendLine(`Vulncheck - result written in ${fname}`);
-			} else {
-				this.channel.appendLine('Vulncheck - found no vulnerability');
-			}
-		} catch (e) {
-			vscode.window.showErrorMessage(`error running vulncheck: ${e}`);
-			this.channel.appendLine(`Vulncheck failed: ${e}`);
-		}
-		this.channel.show();
-	}
-
-	private async activeDir() {
-		const folders = vscode.workspace.workspaceFolders;
-		if (!folders || folders.length === 0) return;
-		let dir: string | undefined = '';
-		if (folders.length === 1) {
-			dir = folders[0].uri.path;
-		} else {
-			const pick = await vscode.window.showQuickPick(
-				folders.map((f) => ({ label: f.name, description: f.uri.path }))
-			);
-			dir = pick?.description;
-		}
-		return dir;
-	}
-}
-
-async function moduleDir(document: vscode.TextDocument | undefined) {
-	const docDir = document && document.fileName && path.dirname(document.fileName);
-	if (!docDir) {
-		return;
-	}
-	const modFile = await getGoModFile(vscode.Uri.file(docDir));
-	if (!modFile) {
-		return;
-	}
-	return path.dirname(modFile);
-}
-
-// run `gopls vulncheck`.
-export async function vulncheck(
-	goCtx: GoExtensionContext,
-	dir: string,
-	pattern = './...',
-	channel: { appendLine: (msg: string) => void }
-): Promise<VulncheckReport> {
-	const { languageClient, serverInfo } = goCtx;
-	const COMMAND = 'gopls.run_govulncheck';
-	if (!languageClient || !serverInfo?.Commands?.includes(COMMAND)) {
-		throw new Error('this feature requires gopls v0.10.2 or newer');
-	}
-	// TODO: read back the actual package configuration from gopls.
-	const gopls = getBinPath('gopls');
-	const options: vscode.ProgressOptions = {
-		cancellable: true,
-		title: 'Run govulncheck',
-		location: vscode.ProgressLocation.Notification
-	};
-	const task = vscode.window.withProgress<VulncheckReport>(options, (progress, token) => {
-		const p = cp.spawn(gopls, ['vulncheck', pattern], {
-			cwd: dir,
-			env: toolExecutionEnvironment(vscode.Uri.file(dir))
-		});
-
-		progress.report({ message: `starting command ${gopls} from ${dir}  (pid; ${p.pid})` });
-
-		const d = token.onCancellationRequested(() => {
-			channel.appendLine(`gopls vulncheck (pid: ${p.pid}) is cancelled`);
-			killProcessTree(p);
-			d.dispose();
-		});
-
-		const promise = new Promise<VulncheckReport>((resolve, reject) => {
-			const rl = readline.createInterface({ input: p.stderr });
-			rl.on('line', (line) => {
-				channel.appendLine(line);
-				const msg = line.match(/^\d+\/\d+\/\d+\s+\d+:\d+:\d+\s+(.*)/);
-				if (msg && msg[1]) {
-					progress.report({ message: msg[1] });
-				}
-			});
-
-			let buf = '';
-			p.stdout.on('data', (chunk) => {
-				buf += chunk;
-			});
-			p.stdout.on('close', () => {
-				try {
-					const res: VulncheckReport = JSON.parse(buf);
-					resolve(res);
-				} catch (e) {
-					if (token.isCancellationRequested) {
-						reject('analysis cancelled');
-					} else {
-						channel.appendLine(buf);
-						reject('vulncheck failed: see govulncheck OUTPUT');
-					}
-				}
-			});
-		});
-		return promise;
-	});
-	return await task;
-}
-
-interface VulncheckReport {
-	// Vulns populated by gopls vulncheck run.
-	Vuln?: Vuln[];
-
-	// analysis run information.
-	Pattern?: string;
-	Dir?: string;
-
-	Start?: Date;
-	Duration?: number; // milliseconds
-}
-
-interface Vuln {
-	ID: string;
-	Details: string;
-	Aliases: string[];
-	Symbol: string;
-	PkgPath: string;
-	ModPath: string;
-	URL: string;
-	CurrentVersion: string;
-	FixedVersion: string;
-	CallStacks?: CallStack[][];
-	CallStacksSummary?: string[];
-
-	// Derived from call stacks.
-	// TODO(hyangah): add to gopls vulncheck.
-	AffectedPkgs?: string[];
-}
-
-interface CallStack {
-	Name: string;
-	URI: string;
-	Pos: {
-		line: number;
-		character: number;
-	};
-}
-
-function getNonce() {
-	let text = '';
-	const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
-	for (let i = 0; i < 32; i++) {
-		text += possible.charAt(Math.floor(Math.random() * possible.length));
-	}
-	return text;
-}
-
-function safeURIParse(s: string): URI | undefined {
-	try {
-		return URI.parse(s);
-	} catch (_) {
-		return undefined;
-	}
-}
-
-// Computes the AffectedPkgs attribute if it's not present.
-// Exported for testing.
-// TODO(hyangah): move this logic to gopls vulncheck or govulncheck.
-export function fillAffectedPkgs(vulns: Vuln[] | undefined): Vuln[] {
-	if (!vulns) return [];
-
-	const re = new RegExp(/^(\S+)\/([^/\s]+)$/);
-	vulns.forEach((vuln) => {
-		// If it's already set by gopls vulncheck, great!
-		if (vuln.AffectedPkgs) return;
-
-		const affected = new Set<string>();
-		vuln.CallStacks?.forEach((cs) => {
-			if (!cs || cs.length === 0) {
-				return;
-			}
-			const name = cs[0].Name || '';
-			const m = name.match(re);
-			if (!m) {
-				name && affected.add(name);
-			} else {
-				const pkg = m[2] && m[2].split('.')[0];
-				affected.add(`${m[1]}/${pkg}`);
-			}
-		});
-		vuln.AffectedPkgs = Array.from(affected);
-	});
-	return vulns;
-}
diff --git a/test/gopls/vulncheck.test.ts b/test/gopls/vulncheck.test.ts
index 65dc9dd..879f8f1 100644
--- a/test/gopls/vulncheck.test.ts
+++ b/test/gopls/vulncheck.test.ts
@@ -4,9 +4,6 @@
  *--------------------------------------------------------*/
 import assert from 'assert';
 import path = require('path');
-import vscode = require('vscode');
-import { extensionId } from '../../src/const';
-import goVulncheck = require('../../src/goVulncheck');
 import { VulncheckReport, writeVulns } from '../../src/goVulncheck2';
 import fs = require('fs');
 
@@ -68,156 +65,3 @@
 		]);
 	});
 });
-
-suite('vulncheck result viewer tests', () => {
-	const webviewId = 'vulncheck';
-	const extensionUri = vscode.extensions.getExtension(extensionId)!.extensionUri;
-	const fixtureDir = path.join(__dirname, '..', '..', '..', 'test', 'testdata', 'vuln');
-
-	const disposables: vscode.Disposable[] = [];
-	function _register<T extends vscode.Disposable>(disposable: T) {
-		disposables.push(disposable);
-		return disposable;
-	}
-	let provider: goVulncheck.VulncheckResultViewProvider;
-
-	setup(() => {
-		provider = new goVulncheck.VulncheckResultViewProvider(extensionUri, {});
-	});
-
-	teardown(async () => {
-		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
-		vscode.Disposable.from(...disposables).dispose();
-	});
-
-	test('populates webview', async () => {
-		const doTest = async (tag: string) => {
-			const webviewPanel = _register(
-				vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, {})
-			);
-			const source = path.join(fixtureDir, 'test.vulncheck.json');
-			const doc = await vscode.workspace.openTextDocument(source);
-			console.timeLog(tag, 'opened document');
-			const canceller = new vscode.CancellationTokenSource();
-			_register(canceller);
-
-			const watcher = getMessage<{ type: string; target?: string }>(webviewPanel);
-
-			await provider.resolveCustomTextEditor(doc, webviewPanel, canceller.token);
-			console.timeLog(tag, 'resolved custom text editor');
-
-			webviewPanel.reveal();
-
-			// Trigger snapshotContent that sends `snapshot-result` as a result.
-			webviewPanel.webview.postMessage({ type: 'snapshot-request' });
-			console.timeLog(tag, 'posted snapshot-request');
-
-			const res = await watcher;
-			console.timeLog(tag, 'received message');
-
-			assert.deepStrictEqual(res.type, 'snapshot-result', `want snapshot-result, got ${JSON.stringify(res)}`);
-			// res.target type is defined in vulncheckView.js.
-			const { log = '', vulns = '', unaffecting = '' } = JSON.parse(res.target ?? '{}');
-
-			assert(
-				log.includes('1 known vulnerabilities'),
-				`expected "1 known vulnerabilities", got ${JSON.stringify(res.target)}`
-			);
-			assert(
-				vulns.includes('GO-2021-0113') &&
-					vulns.includes('<td>Affecting</td><td>github.com/golang/vscode-go/test/testdata/vuln</td>'),
-				`expected "Affecting" section, got ${JSON.stringify(res.target)}`
-			);
-			// Unaffecting vulnerability's ID is reported.
-			assert(
-				unaffecting.includes('GO-2021-0000') && unaffecting.includes('golang.org/x/text'),
-				`expected reports about unaffecting vulns, got ${JSON.stringify(res.target)}`
-			);
-		};
-		try {
-			console.time('populates-webview');
-			await doTest('populates-webview');
-		} catch (e) {
-			console.timeLog('populates-webview', `error thrown: ${e}`);
-			throw e;
-		} finally {
-			console.timeEnd('populates-webview');
-		}
-	}).timeout(5_000);
-
-	test('handles empty input', async () => {
-		const webviewPanel = _register(
-			vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, {})
-		);
-		// Empty doc.
-		const doc = await vscode.workspace.openTextDocument(
-			vscode.Uri.file('bogus.vulncheck.json').with({ scheme: 'untitled' })
-		);
-		const canceller = new vscode.CancellationTokenSource();
-		_register(canceller);
-
-		const watcher = getMessage<{ type: string; target?: string }>(webviewPanel);
-
-		await provider.resolveCustomTextEditor(doc, webviewPanel, canceller.token);
-		webviewPanel.reveal();
-
-		// Trigger snapshotContent that sends `snapshot-result` as a result.
-		webviewPanel.webview.postMessage({ type: 'snapshot-request' });
-		const res = await watcher;
-		assert.deepStrictEqual(res.type, 'snapshot-result', `want snapshot-result, got ${JSON.stringify(res)}`);
-		const { log = '', vulns = '', unaffecting = '' } = JSON.parse(res.target ?? '{}');
-		assert(!log && !vulns && !unaffecting, res.target);
-	});
-
-	// TODO: test corrupted/incomplete json file handling.
-});
-
-function getMessage<R = { type: string; target?: string }>(webview: vscode.WebviewPanel): Promise<R> {
-	return new Promise<R>((resolve) => {
-		const sub = webview.webview.onDidReceiveMessage((message) => {
-			sub.dispose();
-			resolve(message);
-		});
-	});
-}
-suite('fillAffectedPkgs', () => {
-	test('compute from the first call stack entry', async () => {
-		const data = JSON.parse(`{
-		"Vuln": [{
-			"CallStacks": [
-				[
-				  {
-					"Name": "github.com/golang/vscode-go/test/testdata/vuln.main",
-					"URI": "file:///vuln/test.go",
-					"Pos": { "line": 9, "character": 0 }
-				  },
-				  {
-					"Name": "golang.org/x/text/language.Parse",
-					"URI": "file:///foo/bar.go",
-					"Pos": { "line": 227, "character": 0 }
-				  }
-				]
-			]}]}`);
-		goVulncheck.fillAffectedPkgs(data.Vuln);
-		assert.deepStrictEqual(data.Vuln[0].AffectedPkgs, ['github.com/golang/vscode-go/test/testdata/vuln']);
-	});
-
-	test('callstacks missing', async () => {
-		const data = JSON.parse('{ "Vuln": [{}] }');
-		goVulncheck.fillAffectedPkgs(data.Vuln);
-		assert.deepStrictEqual(data.Vuln[0].AffectedPkgs, []);
-	});
-
-	test('callstacks empty', async () => {
-		const data = JSON.parse('{ "Vuln": [{"CallStacks": []}] }');
-		goVulncheck.fillAffectedPkgs(data.Vuln);
-		assert.deepStrictEqual(data.Vuln[0].AffectedPkgs, []);
-	});
-
-	test('first call stack entry is missing Name', async () => {
-		const data = JSON.parse(`{
-		"Vuln": [{ "CallStacks": [ [ { "URI": "file:///vuln/test.go" } ] ]}]}`);
-		goVulncheck.fillAffectedPkgs(data.Vuln);
-		assert.deepStrictEqual(data.Vuln[0].AffectedPkgs, []);
-	});
-});
diff --git a/test/testdata/vuln/test.vulncheck.json b/test/testdata/vuln/test.vulncheck.json
deleted file mode 100644
index 653c554..0000000
--- a/test/testdata/vuln/test.vulncheck.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
-  "Vuln": [
-    {
-      "ID": "GO-2021-0113",
-      "Details": "Due to improper index calculation, an incorrectly formatted language tag can cause Parse\nto panic via an out of bounds read. If Parse is used to process untrusted user inputs,\nthis may be used as a vector for a denial of service attack.\n",
-      "Aliases": [
-        "CVE-2021-38561"
-      ],
-      "Symbol": "Parse",
-      "PkgPath": "golang.org/x/text/language",
-      "ModPath": "golang.org/x/text",
-      "URL": "https://pkg.go.dev/vuln/GO-2021-0113",
-      "CurrentVersion": "v0.0.0-20170915032832-14c0d48ead0c",
-      "FixedVersion": "v0.3.7",
-      "AffectedPkgs": ["github.com/golang/vscode-go/test/testdata/vuln"],
-      "CallStacks": [
-        [
-          {
-            "Name": "github.com/golang/vscode-go/test/testdata/vuln.main",
-            "URI": "file:///Users/hakim/projects/vscode-go/test/testdata/vuln/test.go",
-            "Pos": {
-              "line": 9,
-              "character": 0
-            }
-          },
-          {
-            "Name": "golang.org/x/text/language.Parse",
-            "URI": "file:///Users/hakim/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/language/parse.go",
-            "Pos": {
-              "line": 227,
-              "character": 0
-            }
-          }
-        ]
-      ],
-      "CallStackSummaries": [
-        "github.com/golang/vscode-go/test/testdata/vuln.main calls golang.org/x/text/language.Parse"
-      ]
-    },
-    {
-      "ID": "GO-2021-0000",
-      "Details": "Bogus Report",
-      "Symbol": "Parse",
-      "ModPath": "golang.org/x/text",
-      "URL": "https://pkg.go.dev/vuln/GO-2021-0000"
-    }
-  ],
-  "Start": "2022-05-16T13:43:54.437Z",
-  "Duration": 1407,
-  "Dir": "/Users/hakim/projects/vscode-go/test/testdata/vuln",
-  "Pattern": "./..."
-}