Skip to content

Commit

Permalink
debug: better copying of eval expression results (#187951)
Browse files Browse the repository at this point in the history
For #187784. Needs DAP methods for a complete solution.
  • Loading branch information
connor4312 authored Jul 14, 2023
1 parent 6c94c8e commit 5eb82ae
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 17 deletions.
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

0 comments on commit 5eb82ae

Please sign in to comment.