mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
Add watch without selection (#171449)
* 🎁 Support adding expression to watch list without text selection Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com> * 🔨 Remove non-empty selection from "Add to Watch" pre-conditions Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com> * 🔨 Refactor duplicate expression extraction methods into a util function Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com> * 🔨 Make cancellation token parameter optional Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com> * 🔨 Omit unnecessary cancellation token argument Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com> * 🔥 Remove unused import Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com> Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com>
This commit is contained in:
parent
844b64be07
commit
f777adc490
|
@ -10,7 +10,6 @@ import { URI } from 'vs/base/common/uri';
|
|||
import 'vs/css!./media/debug.contribution';
|
||||
import 'vs/css!./media/debugHover';
|
||||
import { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ICommandActionTitle, Icon } from 'vs/platform/action/common/action';
|
||||
import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
|
@ -123,7 +122,7 @@ registerDebugCommandPaletteItem(JUMP_TO_CURSOR_ID, { value: nls.localize('jumpTo
|
|||
registerDebugCommandPaletteItem(JUMP_TO_CURSOR_ID, { value: nls.localize('SetNextStatement', "Set Next Statement"), original: 'Set Next Statement' }, CONTEXT_JUMP_TO_CURSOR_SUPPORTED);
|
||||
registerDebugCommandPaletteItem(RunToCursorAction.ID, { value: RunToCursorAction.LABEL, original: 'Run to Cursor' }, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')));
|
||||
registerDebugCommandPaletteItem(SelectionToReplAction.ID, { value: SelectionToReplAction.LABEL, original: 'Evaluate in Debug Console' }, CONTEXT_IN_DEBUG_MODE);
|
||||
registerDebugCommandPaletteItem(SelectionToWatchExpressionsAction.ID, { value: SelectionToWatchExpressionsAction.LABEL, original: 'Add to Watch' }, ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection, CONTEXT_IN_DEBUG_MODE));
|
||||
registerDebugCommandPaletteItem(SelectionToWatchExpressionsAction.ID, { value: SelectionToWatchExpressionsAction.LABEL, original: 'Add to Watch' }, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE));
|
||||
registerDebugCommandPaletteItem(TOGGLE_INLINE_BREAKPOINT_ID, { value: nls.localize('inlineBreakpoint', "Inline Breakpoint"), original: 'Inline Breakpoint' });
|
||||
registerDebugCommandPaletteItem(DEBUG_START_COMMAND_ID, DEBUG_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))));
|
||||
registerDebugCommandPaletteItem(DEBUG_RUN_COMMAND_ID, DEBUG_RUN_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))));
|
||||
|
|
|
@ -10,6 +10,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||
import { EditorAction, EditorAction2, IActionOptions, registerEditorAction } from 'vs/editor/browser/editorExtensions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
import { MessageController } from 'vs/editor/contrib/message/browser/messageController';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
|
@ -23,6 +24,7 @@ import { PanelFocusContext } from 'vs/workbench/common/contextkeys';
|
|||
import { IViewsService } from 'vs/workbench/common/views';
|
||||
import { openBreakpointSource } from 'vs/workbench/contrib/debug/browser/breakpointsView';
|
||||
import { BreakpointWidgetContext, BREAKPOINT_EDITOR_CONTRIBUTION_ID, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE, CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED, CONTEXT_EXCEPTION_WIDGET_VISIBLE, CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE, CONTEXT_IN_DEBUG_MODE, CONTEXT_LANGUAGE_SUPPORTS_DISASSEMBLE_REQUEST, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, IDebugConfiguration, IDebugEditorContribution, IDebugService, REPL_VIEW_ID, WATCH_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { getEvaluatableExpressionAtPosition } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { DisassemblyViewInput } from 'vs/workbench/contrib/debug/common/disassemblyViewInput';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
|
@ -330,7 +332,7 @@ export class SelectionToWatchExpressionsAction extends EditorAction {
|
|||
id: SelectionToWatchExpressionsAction.ID,
|
||||
label: SelectionToWatchExpressionsAction.LABEL,
|
||||
alias: 'Debug: Add to Watch',
|
||||
precondition: ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection, EditorContextKeys.editorTextFocus),
|
||||
precondition: ContextKeyExpr.and(EditorContextKeys.editorTextFocus),
|
||||
contextMenuOpts: {
|
||||
group: 'debug',
|
||||
order: 1
|
||||
|
@ -341,13 +343,33 @@ export class SelectionToWatchExpressionsAction extends EditorAction {
|
|||
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const viewsService = accessor.get(IViewsService);
|
||||
const languageFeaturesService = accessor.get(ILanguageFeaturesService);
|
||||
if (!editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const text = editor.getModel().getValueInRange(editor.getSelection());
|
||||
let expression: string | undefined = undefined;
|
||||
|
||||
const model = editor.getModel();
|
||||
const selection = editor.getSelection();
|
||||
|
||||
if (!selection.isEmpty()) {
|
||||
expression = model.getValueInRange(selection);
|
||||
} else {
|
||||
const position = editor.getPosition();
|
||||
const evaluatableExpression = await getEvaluatableExpressionAtPosition(languageFeaturesService, model, position);
|
||||
if (!evaluatableExpression) {
|
||||
return;
|
||||
}
|
||||
expression = evaluatableExpression.matchingExpression;
|
||||
}
|
||||
|
||||
if (!expression) {
|
||||
return;
|
||||
}
|
||||
|
||||
await viewsService.openView(WATCH_VIEW_ID);
|
||||
debugService.addWatchExpression(text);
|
||||
debugService.addWatchExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,7 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
|||
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
import * as nls from 'vs/nls';
|
||||
|
@ -33,7 +32,7 @@ import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
|
|||
import { VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView';
|
||||
import { IDebugService, IDebugSession, IExpression, IExpressionContainer, IStackFrame } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Expression, Variable } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { getExactExpressionStartAndEnd } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { getEvaluatableExpressionAtPosition } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
|
@ -363,7 +362,7 @@ class DebugHoverComputer {
|
|||
}
|
||||
|
||||
const model = this.editor.getModel();
|
||||
const result = await this.doCompute(model, position, token);
|
||||
const result = await getEvaluatableExpressionAtPosition(this.languageFeaturesService, model, position, token);
|
||||
if (!result) {
|
||||
return { rangeChanged: false };
|
||||
}
|
||||
|
@ -377,44 +376,6 @@ class DebugHoverComputer {
|
|||
return { rangeChanged, range: this._currentRange };
|
||||
}
|
||||
|
||||
private async doCompute(model: ITextModel, position: Position, token: CancellationToken): Promise<{ range: IRange; matchingExpression: string } | null> {
|
||||
if (this.languageFeaturesService.evaluatableExpressionProvider.has(model)) {
|
||||
const supports = this.languageFeaturesService.evaluatableExpressionProvider.ordered(model);
|
||||
|
||||
const results = coalesce(await Promise.all(supports.map(async support => {
|
||||
try {
|
||||
return await support.provideEvaluatableExpression(model, position, token);
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
})));
|
||||
|
||||
if (results.length > 0) {
|
||||
let matchingExpression = results[0].expression;
|
||||
const range = results[0].range;
|
||||
|
||||
if (!matchingExpression) {
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
matchingExpression = lineContent.substring(range.startColumn - 1, range.endColumn - 1);
|
||||
}
|
||||
|
||||
return { range, matchingExpression };
|
||||
}
|
||||
} else { // old one-size-fits-all strategy
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
const { start, end } = getExactExpressionStartAndEnd(lineContent, position.column, position.column);
|
||||
|
||||
// use regex to extract the sub-expression #9821
|
||||
const matchingExpression = lineContent.substring(start - 1, end);
|
||||
return {
|
||||
matchingExpression,
|
||||
range: new Range(position.lineNumber, start, position.lineNumber, start + matchingExpression.length)
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async evaluate(session: IDebugSession): Promise<IExpression | undefined> {
|
||||
if (!this._currentExpression) {
|
||||
this.logService.error('No expression to evaluate');
|
||||
|
|
|
@ -11,6 +11,12 @@ import { deepClone } from 'vs/base/common/objects';
|
|||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
|
||||
const _formatPIIRegexp = /{([^}]+)}/g;
|
||||
|
||||
|
@ -115,6 +121,44 @@ export function getExactExpressionStartAndEnd(lineContent: string, looseStart: n
|
|||
{ start: 0, end: 0 };
|
||||
}
|
||||
|
||||
export async function getEvaluatableExpressionAtPosition(languageFeaturesService: ILanguageFeaturesService, model: ITextModel, position: Position, token?: CancellationToken): Promise<{ range: IRange; matchingExpression: string } | null> {
|
||||
if (languageFeaturesService.evaluatableExpressionProvider.has(model)) {
|
||||
const supports = languageFeaturesService.evaluatableExpressionProvider.ordered(model);
|
||||
|
||||
const results = coalesce(await Promise.all(supports.map(async support => {
|
||||
try {
|
||||
return await support.provideEvaluatableExpression(model, position, token ?? CancellationToken.None);
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
})));
|
||||
|
||||
if (results.length > 0) {
|
||||
let matchingExpression = results[0].expression;
|
||||
const range = results[0].range;
|
||||
|
||||
if (!matchingExpression) {
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
matchingExpression = lineContent.substring(range.startColumn - 1, range.endColumn - 1);
|
||||
}
|
||||
|
||||
return { range, matchingExpression };
|
||||
}
|
||||
} else { // old one-size-fits-all strategy
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
const { start, end } = getExactExpressionStartAndEnd(lineContent, position.column, position.column);
|
||||
|
||||
// use regex to extract the sub-expression #9821
|
||||
const matchingExpression = lineContent.substring(start - 1, end);
|
||||
return {
|
||||
matchingExpression,
|
||||
range: new Range(position.lineNumber, start, position.lineNumber, start + matchingExpression.length)
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// RFC 2396, Appendix A: https://www.ietf.org/rfc/rfc2396.txt
|
||||
const _schemePattern = /^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/;
|
||||
|
||||
|
|
Loading…
Reference in a new issue