Path: blob/main/extensions/copilot/src/extension/conversation/vscode-node/logWorkspaceState.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/456import * as vscode from 'vscode';7import { IDebugOutputService } from '../../../platform/debug/common/debugOutputService';8import { IGitService } from '../../../platform/git/common/gitService';9import { ILanguageDiagnosticsService } from '../../../platform/languages/common/languageDiagnosticsService';10import { ILanguageFeaturesService } from '../../../platform/languages/common/languageFeaturesService';11import { ITabsAndEditorsService } from '../../../platform/tabs/common/tabsAndEditorsService';12import { ITerminalService } from '../../../platform/terminal/common/terminalService';13import { IWorkspaceService } from '../../../platform/workspace/common/workspaceService';14import { ISerializedDiagnosticRelatedInformation, ISerializedWorkspaceState } from '../../../platform/workspaceState/common/promptContextModel';15import { coalesce } from '../../../util/vs/base/common/arrays';16import { Disposable } from '../../../util/vs/base/common/lifecycle';17import { relativePath } from '../../../util/vs/base/common/resources';18import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation';19import { IExtensionContribution } from '../../common/contributions';2021export class LogWorkspaceStateContribution extends Disposable implements IExtensionContribution {22constructor(23@IInstantiationService instantiationService: IInstantiationService,24) {25super();2627// register command "Developer: Log Workbench State"28this._register(vscode.commands.registerCommand('github.copilot.debug.workbenchState', async () => {29const symbolQueries = await vscode.window.showInputBox({30prompt: 'Enter a comma-separated list of symbol queries. Can be left blank if not using WorkspaceSymbols',31});32// Show a quick input asking the user for a file name33const fileName = await vscode.window.showInputBox({34prompt: 'Enter a file name - .state.json will be appended as the extension',35value: 'workspaceState',36});37if (!fileName) {38return;39}40const state = await instantiationService.createInstance(WorkspaceStateSnapshotHelper).captureWorkspaceStateSnapshot(symbolQueries?.split(',') ?? []);41// Get workspace root42const workspaceRoot = vscode.workspace.workspaceFolders?.[0].uri;43if (!workspaceRoot) {44return;45}46// Write the file47const fileUri = vscode.Uri.joinPath(workspaceRoot, `${fileName}.state.json`);48let serializedState = JSON.stringify(state, null, 2);49// Replace workspaceRoot with `./` to make the file path relative50serializedState = serializedState.replace(new RegExp(`${workspaceRoot.fsPath}/`, 'g'), './');51vscode.workspace.fs.writeFile(fileUri, Buffer.from(serializedState));52}));53}54}5556export class WorkspaceStateSnapshotHelper {57/**58* Constructs a new instance of the PromptContextModel.59*60* @param tabAndEditorsService - Service for managing tabs and editors.61* @param languageDiagnosticService - Service for providing language diagnostics.62* @param languageService - Service for language features.63* @param workspaceService - Service for workspace management.64* @param terminalService - Service for terminal operations.65* @param debugOutputService - Service for debug output.66* @param gitService - Service for Git operations.67*/68constructor(69@ITabsAndEditorsService private readonly tabAndEditorsService: ITabsAndEditorsService,70@ILanguageDiagnosticsService private readonly languageDiagnosticService: ILanguageDiagnosticsService,71@ILanguageFeaturesService private readonly languageService: ILanguageFeaturesService,72@IWorkspaceService private readonly workspaceService: IWorkspaceService,73@ITerminalService private readonly terminalService: ITerminalService,74@IDebugOutputService private readonly debugOutputService: IDebugOutputService,75@IGitService private readonly gitService: IGitService76) { }7778public async captureWorkspaceStateSnapshot(symbolQueries: string[]): Promise<ISerializedWorkspaceState> {79const workspaceFoldersFilePaths = this.workspaceService.getWorkspaceFolders().map(w => w.fsPath + '/');80const notebookDocumentFilePaths = this.workspaceService.notebookDocuments.map(d => d.uri.fsPath);81const symbols = (await Promise.all(symbolQueries.map(q => this.languageService.getWorkspaceSymbols(q)))).flat();82const serializedSymbols = symbols.map(s => ({83name: s.name,84kind: s.kind,85containerName: s.containerName,86filePath: s.location.uri.fsPath,87start: s.location.range.start,88end: s.location.range.end,89}));90const activeFileDiagnostics = !this.tabAndEditorsService.activeTextEditor ? [] : this.languageDiagnosticService.getDiagnostics(this.tabAndEditorsService.activeTextEditor.document.uri).map(d => ({91start: d.range.start,92end: d.range.end,93message: d.message,94severity: d.severity,95relatedInformation: d.relatedInformation?.map(serializeRelatedInformation)96}));97const activeTextEditor = this.tabAndEditorsService.activeTextEditor ? {98selections: this.tabAndEditorsService.activeTextEditor?.selections.map(s => ({99anchor: s.anchor,100active: s.active,101isReversed: s.isReversed,102})) ?? [],103documentFilePath: this.tabAndEditorsService.activeTextEditor?.document.uri.fsPath ?? '',104visibleRanges: this.tabAndEditorsService.activeTextEditor?.visibleRanges.map(r => ({105start: r.start,106end: r.end107})) ?? [],108languageId: this.tabAndEditorsService.activeTextEditor?.document.languageId ?? 'javascript',109} : undefined;110const terminalLastCommand = this.terminalService.terminalLastCommand ? {111commandLine: this.terminalService.terminalLastCommand.commandLine,112cwd: typeof this.terminalService.terminalLastCommand.cwd === 'object' ? this.terminalService.terminalLastCommand.cwd.toString() : this.terminalService.terminalLastCommand.cwd,113exitCode: this.terminalService.terminalLastCommand.exitCode,114output: this.terminalService.terminalLastCommand.output,115} : undefined;116const workspaceState: ISerializedWorkspaceState = {117workspaceFoldersFilePaths,118workspaceFolderFilePath: undefined,119symbols: serializedSymbols,120activeFileDiagnostics,121activeTextEditor,122debugConsoleOutput: this.debugOutputService.consoleOutput,123terminalBuffer: this.terminalService.terminalBuffer,124terminalLastCommand,125terminalSelection: this.terminalService.terminalSelection,126terminalShellType: this.terminalService.terminalShellType,127repoContexts: this.gitService.repositories,128notebookDocumentFilePaths,129textDocumentFilePaths: coalesce(this.workspaceService.textDocuments.map(doc => {130const parentFolder = this.workspaceService.getWorkspaceFolder(doc.uri);131return parentFolder ? relativePath(parentFolder, doc.uri) : undefined;132})),133activeNotebookEditor: undefined134};135136return workspaceState;137}138}139140function serializeRelatedInformation(r: vscode.DiagnosticRelatedInformation): ISerializedDiagnosticRelatedInformation {141return {142filePath: r.location.uri.fsPath,143start: r.location.range.start,144end: r.location.range.end,145message: r.message146};147}148149150