Skip to content

Commit

Permalink
GH-9262: Fixed multiple hover issues for currentFrame editor.
Browse files Browse the repository at this point in the history
Enabled debug hover coloring for strings, numbers, and booleans.

Closes #9262

Signed-off-by: Akos Kitta <[email protected]>
  • Loading branch information
Akos Kitta authored and kittaakos committed Apr 1, 2021
1 parent 71f762c commit 22dcd7e
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 33 deletions.
21 changes: 20 additions & 1 deletion packages/debug/src/browser/debug-session-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,29 @@ export class DebugSessionManager {
return this.state > DebugState.Inactive;
}

isCurrentEditorFrame(uri: URI | string | monaco.Uri): boolean {
return this.currentFrame?.source?.uri.toString() === (uri instanceof URI ? uri : new URI(uri)).toString();
}

protected async saveAll(): Promise<boolean> {
if (!this.shell.canSaveAll()) {
return true; // Nothing to save.
}
try {
await this.shell.saveAll();
return true;
} catch (error) {
console.error(error);
return false;
}
}

async start(options: DebugSessionOptions): Promise<DebugSession | undefined> {
return this.progressService.withProgress('Start...', 'debug', async () => {
try {
await this.shell.saveAll();
if (!await this.saveAll()) {
return undefined;
}
await this.fireWillStartDebugSession();
const resolved = await this.resolveConfiguration(options);

Expand Down
72 changes: 59 additions & 13 deletions packages/debug/src/browser/editor/debug-editor-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { injectable, inject, postConstruct, interfaces, Container } from '@theia
import URI from '@theia/core/lib/common/uri';
import { Disposable, DisposableCollection, MenuPath, isOSX } from '@theia/core';
import { ContextMenuRenderer } from '@theia/core/lib/browser';
import { MonacoConfigurationService } from '@theia/monaco/lib/browser/monaco-frontend-module';
import { BreakpointManager } from '../breakpoint/breakpoint-manager';
import { DebugSourceBreakpoint } from '../model/debug-source-breakpoint';
import { DebugSessionManager } from '../debug-session-manager';
Expand Down Expand Up @@ -50,6 +51,7 @@ export class DebugEditorModel implements Disposable {
static CONTEXT_MENU: MenuPath = ['debug-editor-context-menu'];

protected readonly toDispose = new DisposableCollection();
protected readonly toDisposeOnUpdate = new DisposableCollection();

protected uri: URI;

Expand All @@ -58,7 +60,7 @@ export class DebugEditorModel implements Disposable {

protected currentBreakpointDecorations: string[] = [];

protected frameDecorations: string[] = [];
protected editorDecorations: string[] = [];
protected topFrameRange: monaco.Range | undefined;

protected updatingDecorations = false;
Expand Down Expand Up @@ -87,6 +89,9 @@ export class DebugEditorModel implements Disposable {
@inject(DebugInlineValueDecorator)
readonly inlineValueDecorator: DebugInlineValueDecorator;

@inject(MonacoConfigurationService)
readonly configurationService: monaco.services.IConfigurationService;

@postConstruct()
protected init(): void {
this.uri = new URI(this.editor.getControl().getModel()!.uri.toString());
Expand All @@ -98,48 +103,86 @@ export class DebugEditorModel implements Disposable {
this.editor.getControl().onMouseMove(event => this.handleMouseMove(event)),
this.editor.getControl().onMouseLeave(event => this.handleMouseLeave(event)),
this.editor.getControl().onKeyDown(() => this.hover.hide({ immediate: false })),
this.editor.getControl().onDidChangeModelContent(() => this.renderFrames()),
this.editor.getControl().onDidChangeModelContent(() => this.update()),
this.editor.getControl().getModel()!.onDidChangeDecorations(() => this.updateBreakpoints()),
this.sessions.onDidChange(() => this.renderFrames())
this.sessions.onDidChange(() => this.update()),
this.toDisposeOnUpdate
]);
this.renderFrames();
this.update();
this.render();
}

dispose(): void {
this.toDispose.dispose();
}

protected readonly renderFrames = debounce(async () => {
protected readonly update = debounce(async () => {
if (this.toDispose.disposed) {
return;
}
this.toDisposeOnUpdate.dispose();
this.toggleExceptionWidget();
await this.updateEditorDecorations();
this.updateEditorHover();
}, 100);

/**
* To disable the default editor-contribution hover from Code when
* the editor has the `currentFrame`. Otherwise, both `textdocument/hover`
* and the debug hovers are visible at the same time when hovering over a symbol.
*/
protected async updateEditorHover(): Promise<void> {
if (this.sessions.isCurrentEditorFrame(this.uri)) {
const codeEditor = this.editor.getControl();
codeEditor.updateOptions({ hover: { enabled: false } });
this.toDisposeOnUpdate.push(Disposable.create(() => {
const model = codeEditor.getModel()!;
const overrides = {
resource: model.uri,
overrideIdentifier: model.getLanguageIdentifier().language,
};
const { enabled, delay, sticky } = this.configurationService._configuration.getValue('editor.hover', overrides, undefined);
codeEditor.updateOptions({
hover: {
enabled,
delay,
sticky
}
});
}));
}
}

protected async updateEditorDecorations(): Promise<void> {
const [newFrameDecorations, inlineValueDecorations] = await Promise.all([
this.createFrameDecorations(),
this.createInlineValueDecorations()
]);
const codeEditor = this.editor.getControl();
codeEditor.removeDecorations(INLINE_VALUE_DECORATION_KEY);
codeEditor.setDecorations(INLINE_VALUE_DECORATION_KEY, inlineValueDecorations);
this.frameDecorations = this.deltaDecorations(this.frameDecorations, newFrameDecorations);
}, 100);
this.editorDecorations = this.deltaDecorations(this.editorDecorations, newFrameDecorations);
}

protected async createInlineValueDecorations(): Promise<monaco.editor.IDecorationOptions[]> {
const { currentFrame } = this.sessions;
if (!currentFrame || !currentFrame.source || currentFrame.source.uri.toString() !== this.uri.toString()) {
if (!this.sessions.isCurrentEditorFrame(this.uri)) {
return [];
}
const { currentFrame } = this.sessions;
return this.inlineValueDecorator.calculateDecorations(this, currentFrame);
}

protected createFrameDecorations(): monaco.editor.IModelDeltaDecoration[] {
const decorations: monaco.editor.IModelDeltaDecoration[] = [];
const { currentFrame, topFrame } = this.sessions;
if (!currentFrame || !currentFrame.source || currentFrame.source.uri.toString() !== this.uri.toString()) {
return decorations;
if (!currentFrame) {
return [];
}

if (!this.sessions.isCurrentEditorFrame(this.uri)) {
return [];
}

const decorations: monaco.editor.IModelDeltaDecoration[] = [];
const columnUntilEOLRange = new monaco.Range(currentFrame.raw.line, currentFrame.raw.column, currentFrame.raw.line, 1 << 30);
const range = new monaco.Range(currentFrame.raw.line, currentFrame.raw.column, currentFrame.raw.line, currentFrame.raw.column + 1);

Expand Down Expand Up @@ -175,7 +218,10 @@ export class DebugEditorModel implements Disposable {

protected async toggleExceptionWidget(): Promise<void> {
const { currentFrame } = this.sessions;
if (!currentFrame || !currentFrame.source || currentFrame.source.uri.toString() !== this.uri.toString()) {
if (!currentFrame) {
return;
}
if (!this.sessions.isCurrentEditorFrame(this.uri)) {
this.exceptionWidget.hide();
return;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/debug/src/browser/editor/debug-hover-source.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ export class DebugHoverSource extends TreeSource {
this.fireDidChange();
}

async evaluate(expression: string): Promise<boolean> {
async evaluate(expression: string): Promise<ExpressionItem | DebugVariable | undefined> {
const evaluated = await this.doEvaluate(expression);
const elements = evaluated && await evaluated.getElements();
this._expression = evaluated;
this.elements = elements ? [...elements] : [];
this.fireDidChange();
return !!evaluated;
return evaluated;
}
protected async doEvaluate(expression: string): Promise<ExpressionItem | DebugVariable | undefined> {
const { currentSession } = this.sessions;
Expand Down
47 changes: 38 additions & 9 deletions packages/debug/src/browser/editor/debug-hover-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { DebugSessionManager } from '../debug-session-manager';
import { DebugEditor } from './debug-editor';
import { DebugExpressionProvider } from './debug-expression-provider';
import { DebugHoverSource } from './debug-hover-source';
import { DebugVariable } from '../console/debug-console-items';

export interface ShowDebugHoverOptions {
selection: monaco.Range
Expand Down Expand Up @@ -113,9 +114,12 @@ export class DebugHoverWidget extends SourceTreeWidget implements monaco.editor.
show(options?: ShowDebugHoverOptions): void {
this.schedule(() => this.doShow(options), options && options.immediate);
}

hide(options?: HideDebugHoverOptions): void {
this.schedule(() => this.doHide(), options && options.immediate);
}

protected readonly doSchedule = debounce((fn: () => void) => fn(), 300);
protected schedule(fn: () => void, immediate: boolean = true): void {
if (immediate) {
this.doSchedule.cancel();
Expand All @@ -124,7 +128,6 @@ export class DebugHoverWidget extends SourceTreeWidget implements monaco.editor.
this.doSchedule(fn);
}
}
protected readonly doSchedule = debounce((fn: () => void) => fn(), 300);

protected options: ShowDebugHoverOptions | undefined;
protected doHide(): void {
Expand All @@ -142,6 +145,7 @@ export class DebugHoverWidget extends SourceTreeWidget implements monaco.editor.
this.options = undefined;
this.editor.getControl().layoutContentWidget(this);
}

protected async doShow(options: ShowDebugHoverOptions | undefined = this.options): Promise<void> {
if (!this.isEditorFrame()) {
this.hide();
Expand All @@ -157,10 +161,10 @@ export class DebugHoverWidget extends SourceTreeWidget implements monaco.editor.
if (!this.isAttached) {
Widget.attach(this, this.contentNode);
}
super.show();

this.options = options;
const expression = this.expressionProvider.get(this.editor.getControl().getModel()!, options.selection);
if (!expression) {
const matchingExpression = this.expressionProvider.get(this.editor.getControl().getModel()!, options.selection);
if (!matchingExpression) {
this.hide();
return;
}
Expand All @@ -171,17 +175,42 @@ export class DebugHoverWidget extends SourceTreeWidget implements monaco.editor.
this.activate();
}));
}
if (!await this.hoverSource.evaluate(expression)) {
const expression = await this.hoverSource.evaluate(matchingExpression);
if (!expression) {
toFocus.dispose();
this.hide();
return;
}
this.editor.getControl().layoutContentWidget(this);

this.contentNode.hidden = false;
['number', 'boolean', 'string'].forEach(token => this.titleNode.classList.remove(token));
this.domNode.classList.remove('complex-value');
if (expression.hasElements) {
this.domNode.classList.add('complex-value');
} else {
this.contentNode.hidden = true;
if (expression.type === 'number' || expression.type === 'boolean' || expression.type === 'string') {
this.titleNode.classList.add(expression.type);
} else if (!isNaN(+expression.value)) {
this.titleNode.classList.add('number');
} else if (DebugVariable.booleanRegex.test(expression.value)) {
this.titleNode.classList.add('boolean');
} else if (DebugVariable.stringRegex.test(expression.value)) {
this.titleNode.classList.add('string');
}
}

super.show();
await new Promise<void>(resolve => {
setTimeout(() => window.requestAnimationFrame(() => {
this.editor.getControl().layoutContentWidget(this);
resolve();
}), 0);
});
}

protected isEditorFrame(): boolean {
const { currentFrame } = this.sessions;
return !!currentFrame && !!currentFrame.source &&
this.editor.getControl().getModel()!.uri.toString() === currentFrame.source.uri.toString();
return this.sessions.isCurrentEditorFrame(this.editor.getControl().getModel()!.uri);
}

getPosition(): monaco.editor.IContentWidgetPosition {
Expand Down
21 changes: 13 additions & 8 deletions packages/debug/src/browser/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -185,16 +185,19 @@
color: var(--theia-variable-value-color);
}

.theia-debug-hover-title.number,
.theia-debug-console-variable.number {
color: var(--theia-number-variable-color);
color: var(--theia-variable-number-variable-color);
}

.theia-debug-hover-title.boolean,
.theia-debug-console-variable.boolean {
color: var(--theia-boolean-variable-color);
color: var(--theia-variable-boolean-variable-color);
}

.theia-debug-hover-title.string,
.theia-debug-console-variable.string {
color: var(--theia-string-variable-color);
color: var(--theia-variable-string-variable-color);
}

.theia-debug-console-variable .name {
Expand Down Expand Up @@ -342,16 +345,19 @@
.theia-debug-hover {
display: flex;
flex-direction: column;
min-width: 324px;
min-height: 324px;
width: 324px;
height: 324px;
border: 1px solid var(--theia-editorHoverWidget-border);
background: var(--theia-editorHoverWidget-background);
/* TODO color: var(--theia-editorHoverWidget-foreground); with a newer Monaco version */
color: var(--theia-editorWidget-foreground);
}

.theia-debug-hover.complex-value {
min-width: 324px;
min-height: 324px;
width: 324px;
height: 324px;
}

.theia-debug-hover .theia-source-tree {
height: 100%;
width: 100%;
Expand All @@ -362,7 +368,6 @@
white-space: nowrap;
text-overflow: ellipsis;
padding: var(--theia-ui-padding);
padding-left: calc(var(--theia-ui-padding)*2);
border-bottom: 1px solid var(--theia-editorHoverWidget-border);
}

Expand Down
8 changes: 8 additions & 0 deletions packages/monaco/src/typings/monaco/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,14 @@ declare module monaco.editor {

// https://github.com/microsoft/vscode/blob/e683ace9e5acadba0e8bde72d793cb2cb83e58a7/src/vs/editor/common/model.ts#L623
createSnapshot(): ITextSnapshot | null;

/**
* Get the language associated with this model.
* @internal
*/
// https://github.com/theia-ide/vscode/blob/standalone/0.19.x/src/vs/editor/common/model.ts#L833-L837
getLanguageIdentifier(): monaco.services.LanguageIdentifier;

}

}
Expand Down

0 comments on commit 22dcd7e

Please sign in to comment.