diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index a65674a80f96a..b12c97f0b8f54 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -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'; @@ -55,7 +56,6 @@ 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'; @@ -63,10 +63,10 @@ import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/d 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.$; @@ -1045,12 +1045,33 @@ registerAction2(class extends Action2 { async run(accessor: ServicesAccessor, element: IReplElement): Promise { 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 { + // 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; } } }); diff --git a/src/vs/workbench/contrib/debug/browser/replViewer.ts b/src/vs/workbench/contrib/debug/browser/replViewer.ts index 4193677ab1ec9..1ba443a95f18a 100644 --- a/src/vs/workbench/contrib/debug/browser/replViewer.ts +++ b/src/vs/workbench/contrib/debug/browser/replViewer.ts @@ -239,14 +239,14 @@ export class ReplVariablesRenderer extends AbstractExpressionsRenderer, _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); diff --git a/src/vs/workbench/contrib/debug/common/replModel.ts b/src/vs/workbench/contrib/debug/common/replModel.ts index 9e28f1d66d18d..4402ed3f3b5c9 100644 --- a/src/vs/workbench/contrib/debug/common/replModel.ts +++ b/src/vs/workbench/contrib/debug/common/replModel.ts @@ -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 { - return this.expr.getChildren(); + return this.expression.getChildren(); } toString(): string { - return this.expr.toString(); + return this.expression.toString(); } getId(): string { @@ -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()); } @@ -271,7 +271,7 @@ export class ReplModel { async addReplExpression(session: IDebugSession, stackFrame: IStackFrame | undefined, name: string): Promise { this.addReplElement(new ReplEvaluationInput(name)); - const result = new ReplEvaluationResult(); + const result = new ReplEvaluationResult(name); await result.evaluateExpression(name, session, stackFrame, 'repl'); this.addReplElement(result); } diff --git a/src/vs/workbench/contrib/debug/test/browser/repl.test.ts b/src/vs/workbench/contrib/debug/test/browser/repl.test.ts index 276f3e74aecfc..a04f2ed196330 100644 --- a/src/vs/workbench/contrib/debug/test/browser/repl.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/repl.test.ts @@ -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 = 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);