mirror of
https://github.com/microsoft/vscode.git
synced 2026-08-30 10:38:28 +01:00
debug: better copying of eval expression results (#187951)
For #187784. Needs DAP methods for a complete solution.
This commit is contained in:
@@ -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<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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
@@ -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<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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user