Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

extension: add debug menu for var show in doc #3818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
MistaTwista wants to merge 12 commits into golang:master
base: master
Choose a base branch
Loading
from MistaTwista:feature/show_var_as_doc
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
12 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).

## Unreleased

Added menu in a debugger that will show variable in a new document with respect to special chars like `\r\n\t`

## v0.51.0 (prerelease)

Date: 2025年09月04日
Expand Down
4 changes: 4 additions & 0 deletions docs/commands.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ Finally, you can also see a full list by using a meta command: `Go: Show All Com

<!-- Everything below this line is generated. DO NOT EDIT. -->

### `Go: Open in new Document`

Open selected variable in a new document.

### `Go: Current GOPATH`

See the currently set GOPATH.
Expand Down
16 changes: 16 additions & 0 deletions extension/package.json
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@
}
},
"commands": [
{
"command": "go.debug.openVariableAsDoc",
"title": "Go: Open in new Document",
"description": "Open selected variable in a new document."
},
{
"command": "go.gopath",
"title": "Go: Current GOPATH",
Expand Down Expand Up @@ -3487,6 +3492,10 @@
{
"command": "go.explorer.open",
"when": "false"
},
{
"command": "go.debug.openVariableAsDoc",
"when": "false"
}
],
"debug/callstack/context": [
Expand All @@ -3495,6 +3504,13 @@
"when": "debugType == 'go' && (callStackItemType == 'stackFrame' || (callStackItemType == 'thread' && callStackItemStopped))"
}
],
"debug/variables/context": [
{
"command": "go.debug.openVariableAsDoc",
"when": "debugType=='go'",
"group": "navigation"
}
],
"editor/context": [
{
"when": "editorTextFocus && config.go.editorContextMenuCommands.toggleTestFile && resourceLangId == go",
Expand Down
140 changes: 140 additions & 0 deletions extension/src/goDebugCommands.ts
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------*/

import * as vscode from 'vscode';

/**
* Registers commands to improve the debugging experience for Go.
*
* Currently, it adds a command to open a variable in a new text document.
*/
export function registerGoDebugCommands(ctx: vscode.ExtensionContext) {
// Track sessions since vscode doesn't provide a list of them.
const sessions = new Map<string, vscode.DebugSession>();

ctx.subscriptions.push(
vscode.debug.onDidStartDebugSession((s) => sessions.set(s.id, s)),
vscode.debug.onDidTerminateDebugSession((s) => sessions.delete(s.id)),
vscode.workspace.registerTextDocumentContentProvider('go-debug-variable', new VariableContentProvider(sessions)),
vscode.commands.registerCommand('go.debug.openVariableAsDoc', async (ref: VariableRef) => {
const uri = VariableContentProvider.uriForRef(ref);
const doc = await vscode.workspace.openTextDocument(uri);
await vscode.window.showTextDocument(doc);
})
);
}

class VariableContentProvider implements vscode.TextDocumentContentProvider {
sessions: Map<string, vscode.DebugSession>

constructor(sessionsSet: Map<string, vscode.DebugSession>) {
this.sessions = sessionsSet;
}

static uriForRef(ref: VariableRef) {
return vscode.Uri.from({
scheme: 'go-debug-variable',
authority: `${ref.container.variablesReference}@${ref.sessionId}`,
path: `/${ref.variable.name}`
});
}

async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
const name = uri.path.replace(/^\//, '');
const [container, sessionId] = uri.authority.split('@', 2);
if (!container || !sessionId) {
throw new Error('Invalid URI');
}

const session = this.sessions.get(sessionId);
if (!session) return 'Debug session has been terminated';

const { variables } = await session.customRequest('variables', {
variablesReference: parseInt(container, 10)
}) as { variables: Variable[] };

const v = variables.find(v => v.name === name);
if (!v) return `Cannot resolve variable ${name}`;

if (!v.memoryReference) {
const { result } = await session.customRequest('evaluate', {
expression: v.evaluateName,
context: 'clipboard'
}) as { result: string };

v.value = result ?? v.value;

return parseVariable(v);
}

const chunk = 1 << 14;
let offset = 0;
const full: Uint8Array[] = [];

while (true) {
const resp = await session.customRequest('readMemory', {
memoryReference: v.memoryReference,
offset,
count: chunk
}) as { address: string; data: string; unreadableBytes: number };

if (!resp.data) break;
full.push(Buffer.from(resp.data, 'base64'));

if (resp.unreadableBytes === 0) break;
offset += chunk;
}

return Buffer.concat(full).toString('utf-8');
}
}

/**
* A reference to a variable, used to pass data between commands.
*/
interface VariableRef {
sessionId: string;
container: Container;
variable: Variable;
}

/**
* A container for variables, used to pass data between commands.
*/
interface Container {
name: string;
variablesReference: number;
expensive: boolean;
}

/**
* A variable, used to pass data between commands.
*/
interface Variable {
name: string;
value: string;
evaluateName: string;
variablesReference: number;
memoryReference?: string;
}

const escapeCodes: Record<string, string> = {
r: '\r',
n: '\n',
t: '\t'
};

/**
* Parses a variable value, unescaping special characters.
*/
function parseVariable(variable: Variable) {
const raw = variable.value.trim();

try {
return JSON.parse(raw);
} catch (_) {
return raw.replace(/\\[nrt\\"'`]/, (_, s) => (s in escapeCodes ? escapeCodes[s] : s));
}
}
2 changes: 2 additions & 0 deletions extension/src/goDebugConfiguration.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { resolveHomeDir } from './utils/pathUtils';
import { createRegisterCommand } from './commands';
import { GoExtensionContext } from './context';
import { spawn } from 'child_process';
import { registerGoDebugCommands } from './goDebugCommands';

let dlvDAPVersionChecked = false;

Expand All @@ -45,6 +46,7 @@ export class GoDebugConfigurationProvider implements vscode.DebugConfigurationPr
const registerCommand = createRegisterCommand(ctx, goCtx);
registerCommand('go.debug.pickProcess', () => pickProcess);
registerCommand('go.debug.pickGoProcess', () => pickGoProcess);
registerGoDebugCommands(ctx);
}

constructor(private defaultDebugAdapterType: string = 'go') {}
Expand Down

AltStyle によって変換されたページ (->オリジナル) /