src/bazel/bazelExplore.ts (189 lines of code) (raw):

import vscode = require('vscode'); import { ExtensionContext, Memento, TestController, workspace } from 'vscode'; import { BazelGoTestRunner } from '../bazel/bazelRun'; import { GoExtensionContext } from '../context'; import { GoDocumentSymbolProvider } from '../goDocumentSymbols'; import { outputChannel } from '../goStatus'; import { GoTestExplorer, isVscodeTestingAPIAvailable } from '../goTest/explore'; import { ProvideSymbols } from '../goTest/resolve'; import { isInTest, Workspace } from '../goTest/utils'; import { getFromGlobalState, updateGlobalState } from '../stateUtils'; const toggleBazelCoverageCommand = 'go.bazel.toggleCoverage'; const lastCoverageStatusKey = 'bazelCoverageLastStatus'; export class BazelGoTestExplorer extends GoTestExplorer { extensionCtx: ExtensionContext; static setup(context: ExtensionContext, goCtx: GoExtensionContext): BazelGoTestExplorer { if (!isVscodeTestingAPIAvailable) { const err = new Error('VSCode Testing API is unavailable'); vscode.commands.executeCommand('go.reportErrorTrace', 'BazelGoTestExplorer.setup', err); throw err; } const ctrl = vscode.tests.createTestController('bazel', 'Bazel'); const symProvider = GoDocumentSymbolProvider(goCtx, true); const inst = new this( goCtx, workspace, ctrl, context.workspaceState, (doc, token) => symProvider.provideDocumentSymbols(doc, token), context ); context.subscriptions.push(ctrl); inst.setupUI(); inst.setupListeners(); inst.setupFileWatchers(); inst.setupCoverageStatusBarItem(); return inst; } constructor( goCtx: GoExtensionContext, workspace: Workspace, ctrl: TestController, workspaceState: Memento, provideDocumentSymbols: ProvideSymbols, extensionCtx: ExtensionContext ) { super(goCtx, workspace, ctrl, workspaceState, provideDocumentSymbols, BazelGoTestRunner); this.extensionCtx = extensionCtx; const runner: BazelGoTestRunner = this.runner as BazelGoTestRunner; if (this.runner instanceof BazelGoTestRunner) { runner.registerCoverageCommand(extensionCtx); runner.registerTestPackageCommand(extensionCtx); } else { vscode.window.showErrorMessage('Failed to enable the Run Test With Coverage command.'); } } setupUI(): void { // Process already open editors vscode.window.visibleTextEditors.forEach((ed) => { this.documentUpdate(ed.document); }); this.extensionCtx.subscriptions.push( vscode.commands.registerCommand('go.test.refresh', async (item) => { if (!item) { await vscode.window.showErrorMessage('No test selected'); return; } try { await this.resolver.resolve(item); this.resolver.updateGoTestContext(); } catch (error) { const m = 'Failed to resolve tests'; outputChannel.appendLine(`${m}: ${error}`); outputChannel.show(); await vscode.window.showErrorMessage(m); } }) ); } setupListeners(): void { this.extensionCtx.subscriptions.push( workspace.onDidChangeConfiguration(async (x) => { try { await this.didChangeConfiguration(x); } catch (error) { if (isInTest()) throw error; else outputChannel.appendLine(`Failed while handling 'onDidChangeConfiguration': ${error}`); } }) ); vscode.commands.registerCommand('go.test.getAllChildren', async (item) => { if (!item) { await vscode.window.showErrorMessage('No test selected'); return; } try { await this.resolver.getAllTestsUnderDirectory(item); this.resolver.updateGoTestContext(); } catch (error) { const m = 'Failed to resolve tests'; outputChannel.appendLine(`${m}: ${error}`); outputChannel.show(); await vscode.window.showErrorMessage(m); } }); this.extensionCtx.subscriptions.push( workspace.onDidOpenTextDocument(async (x) => { try { await this.didOpenTextDocument(x); } catch (error) { if (isInTest()) throw error; else outputChannel.appendLine(`Failed while handling 'onDidOpenTextDocument': ${error}`); } }) ); this.extensionCtx.subscriptions.push( workspace.onDidChangeTextDocument(async (x) => { try { await this.didChangeTextDocument(x); } catch (error) { if (isInTest()) throw error; else outputChannel.appendLine(`Failed while handling 'onDidChangeTextDocument': ${error}`); } }) ); this.extensionCtx.subscriptions.push( workspace.onDidChangeWorkspaceFolders(async (x) => { try { await this.didChangeWorkspaceFolders(x); } catch (error) { if (isInTest()) throw error; else outputChannel.appendLine(`Failed while handling 'onDidChangeWorkspaceFolders': ${error}`); } }) ); } setupFileWatchers(): void { const watcher = workspace.createFileSystemWatcher('**/*_test.go', false, true, false); this.extensionCtx.subscriptions.push(watcher); this.extensionCtx.subscriptions.push( watcher.onDidCreate(async (x) => { try { await this.didCreateFile(x); } catch (error) { if (isInTest()) throw error; else outputChannel.appendLine(`Failed while handling 'FileSystemWatcher.onDidCreate': ${error}`); } }) ); this.extensionCtx.subscriptions.push( watcher.onDidDelete(async (x) => { try { await this.didDeleteFile(x); } catch (error) { if (isInTest()) throw error; else outputChannel.appendLine(`Failed while handling 'FileSystemWatcher.onDidDelete': ${error}`); } }) ); } setupCoverageStatusBarItem(): void { const coverageStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100); coverageStatusBarItem.command = toggleBazelCoverageCommand; const updateStatusBarItem = () => { coverageStatusBarItem.text = `Coverage ${this.goCtx.coverageEnabled ? 'Enabled' : 'Disabled'}`; updateGlobalState(lastCoverageStatusKey, this.goCtx.coverageEnabled); }; // use persisting coverage value if available const lastCoverageEnabled = getFromGlobalState(lastCoverageStatusKey); if (lastCoverageEnabled !== undefined) { this.goCtx.coverageEnabled = lastCoverageEnabled; } this.extensionCtx.subscriptions.push(coverageStatusBarItem); this.extensionCtx.subscriptions.push( vscode.commands.registerCommand(toggleBazelCoverageCommand, () => { this.goCtx.coverageEnabled = !this.goCtx.coverageEnabled; updateStatusBarItem(); if (this.goCtx.coverageEnabled === false) vscode.commands.executeCommand('go.coverageTree.clear'); }) ); updateStatusBarItem(); coverageStatusBarItem.show(); } } export function warnIfDuplicateGoExtension(): void { const extensionMatch = vscode.extensions.all.filter((extension) => extension.id === 'golang.go'); if (extensionMatch.length > 0) { vscode.window.showErrorMessage( 'Action Needed: Conflicting extension detected. In order for the "Go with Bazel" extension to work correctly, please uninstall the "Go" extension. Only one of these may be installed at a time.' ); } }