Skip to content
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

debug: better copying of eval expression results #187951

Merged
merged 1 commit into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 28 additions & 7 deletions src/vs/workbench/contrib/debug/browser/repl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ import { HistoryNavigator } from 'vs/base/common/history';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { removeAnsiEscapeCodes } from 'vs/base/common/strings';
import { ThemeIcon } from 'vs/base/common/themables';
import { URI as uri } from 'vs/base/common/uri';
import 'vs/css!./media/repl';
import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorAction, registerEditorAction } from 'vs/editor/browser/editorExtensions';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { EditorOption, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions';
import { EDITOR_FONT_DEFAULTS, EditorOption } from 'vs/editor/common/config/editorOptions';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { IDecorationOptions } from 'vs/editor/common/editorCommon';
Expand Down Expand Up @@ -55,18 +56,17 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { editorForeground, resolveColorValue } from 'vs/platform/theme/common/colorRegistry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ThemeIcon } from 'vs/base/common/themables';
import { FilterViewPane, IViewPaneOptions, ViewAction } from 'vs/workbench/browser/parts/views/viewPane';
import { IViewDescriptorService, IViewsService } from 'vs/workbench/common/views';
import { getSimpleCodeEditorWidgetOptions, getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems';
import { debugConsoleClearAll, debugConsoleEvaluationPrompt } from 'vs/workbench/contrib/debug/browser/debugIcons';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { ReplFilter } from 'vs/workbench/contrib/debug/browser/replFilter';
import { ReplAccessibilityProvider, ReplDataSource, ReplDelegate, ReplEvaluationInputsRenderer, ReplEvaluationResultsRenderer, ReplGroupRenderer, ReplRawObjectsRenderer, ReplOutputElementRenderer, ReplVariablesRenderer } from 'vs/workbench/contrib/debug/browser/replViewer';
import { CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_REPL, CONTEXT_MULTI_SESSION_REPL, DEBUG_SCHEME, getStateLabel, IDebugConfiguration, IDebugService, IDebugSession, IReplConfiguration, IReplElement, IReplOptions, REPL_VIEW_ID, State } from 'vs/workbench/contrib/debug/common/debug';
import { ReplAccessibilityProvider, ReplDataSource, ReplDelegate, ReplEvaluationInputsRenderer, ReplEvaluationResultsRenderer, ReplGroupRenderer, ReplOutputElementRenderer, ReplRawObjectsRenderer, ReplVariablesRenderer } from 'vs/workbench/contrib/debug/browser/replViewer';
import { CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_REPL, CONTEXT_MULTI_SESSION_REPL, DEBUG_SCHEME, IDebugConfiguration, IDebugService, IDebugSession, IReplConfiguration, IReplElement, IReplOptions, REPL_VIEW_ID, State, getStateLabel } from 'vs/workbench/contrib/debug/common/debug';
import { Variable } from 'vs/workbench/contrib/debug/common/debugModel';
import { ReplGroup } from 'vs/workbench/contrib/debug/common/replModel';
import { ReplEvaluationResult, ReplGroup } from 'vs/workbench/contrib/debug/common/replModel';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';

const $ = dom.$;
Expand Down Expand Up @@ -1045,12 +1045,33 @@ registerAction2(class extends Action2 {

async run(accessor: ServicesAccessor, element: IReplElement): Promise<void> {
const clipboardService = accessor.get(IClipboardService);
const debugService = accessor.get(IDebugService);
const nativeSelection = window.getSelection();
const selectedText = nativeSelection?.toString();
if (selectedText && selectedText.length > 0) {
await clipboardService.writeText(selectedText);
return clipboardService.writeText(selectedText);
} else if (element) {
await clipboardService.writeText(element.toString());
return clipboardService.writeText(await this.tryEvaluateAndCopy(debugService, element) || element.toString());
}
}

private async tryEvaluateAndCopy(debugService: IDebugService, element: IReplElement): Promise<string | undefined> {
// todo: we should expand DAP to allow copying more types here (#187784)
if (!(element instanceof ReplEvaluationResult)) {
return;
}

const stackFrame = debugService.getViewModel().focusedStackFrame;
const session = debugService.getViewModel().focusedSession;
if (!stackFrame || !session || !session.capabilities.supportsClipboardContext) {
return;
}

try {
const evaluation = await session.evaluate(element.originalExpression, stackFrame.frameId, 'clipboard');
return evaluation?.body.result;
} catch (e) {
return;
}
}
});
4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/debug/browser/replViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,14 +239,14 @@ export class ReplVariablesRenderer extends AbstractExpressionsRenderer<IExpressi

public renderElement(node: ITreeNode<IExpression | ReplVariableElement, FuzzyScore>, _index: number, data: IExpressionTemplateData): void {
const element = node.element;
super.renderExpressionElement(element instanceof ReplVariableElement ? element.expr : element, node, data);
super.renderExpressionElement(element instanceof ReplVariableElement ? element.expression : element, node, data);
}

protected renderExpression(expression: IExpression | ReplVariableElement, data: IExpressionTemplateData, highlights: IHighlight[]): void {
const isReplVariable = expression instanceof ReplVariableElement;
if (isReplVariable || !expression.name) {
data.label.set('');
renderExpressionValue(isReplVariable ? expression.expr : expression, data.value, { showHover: false, colorize: true, linkDetector: this.linkDetector });
renderExpressionValue(isReplVariable ? expression.expression : expression, data.value, { showHover: false, colorize: true, linkDetector: this.linkDetector });
data.expression.classList.remove('nested-variable');
} else {
renderVariable(expression as Variable, data, true, highlights, this.linkDetector);
Expand Down
12 changes: 6 additions & 6 deletions src/vs/workbench/contrib/debug/common/replModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,19 @@ export class ReplVariableElement implements INestingReplElement {
private readonly id = generateUuid();

constructor(
public readonly expr: IExpression,
public readonly expression: IExpression,
public readonly severity: severity,
public readonly sourceData?: IReplElementSource,
) {
this.hasChildren = expr.hasChildren;
this.hasChildren = expression.hasChildren;
}

getChildren(): IReplElement[] | Promise<IReplElement[]> {
return this.expr.getChildren();
return this.expression.getChildren();
}

toString(): string {
return this.expr.toString();
return this.expression.toString();
}

getId(): string {
Expand Down Expand Up @@ -169,7 +169,7 @@ export class ReplEvaluationResult extends ExpressionContainer implements IReplEl
return this._available;
}

constructor() {
constructor(public readonly originalExpression: string) {
super(undefined, undefined, 0, generateUuid());
}

Expand Down Expand Up @@ -271,7 +271,7 @@ export class ReplModel {

async addReplExpression(session: IDebugSession, stackFrame: IStackFrame | undefined, name: string): Promise<void> {
this.addReplElement(new ReplEvaluationInput(name));
const result = new ReplEvaluationResult();
const result = new ReplEvaluationResult(name);
await result.evaluateExpression(name, session, stackFrame, 'repl');
this.addReplElement(result);
}
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/debug/test/browser/repl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ suite('Debug - REPL', () => {
const keyValueObject = { 'key1': 2, 'key2': 'value' };
repl.appendToRepl(session, { output: '', expression: new RawObjectReplElement('fakeid', 'fake', keyValueObject), sev: severity.Info });
const element = <ReplVariableElement>repl.getReplElements()[3];
assert.strictEqual(element.expr.value, 'Object');
assert.deepStrictEqual((element.expr as RawObjectReplElement).valueObj, keyValueObject);
assert.strictEqual(element.expression.value, 'Object');
assert.deepStrictEqual((element.expression as RawObjectReplElement).valueObj, keyValueObject);

repl.removeReplExpressions();
assert.strictEqual(repl.getReplElements().length, 0);
Expand Down