Skip to content

Commit

Permalink
fixed double hover issue in debug mode
Browse files Browse the repository at this point in the history
made the hover widget size "dynamic"

Signed-off-by: Akos Kitta <[email protected]>
  • Loading branch information
Akos Kitta committed Mar 25, 2021
1 parent 3782e9b commit efbd89c
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 27 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
77 changes: 64 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 'invers
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,91 @@ 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 hover editor-contribution from Code when
* the editor has the `currentFrame`. Otherwise, both `textdocument/hover`
* and the debug hover are visible at the same time when hovering over a symbol.
*/
protected async updateEditorHover(): Promise<void> {
if (this.sessions.isCurrentEditorFrame(this.uri)) {
this.disableEditorHover();
this.toDisposeOnUpdate.push(Disposable.create(() => this.enableEditorHover()));
}
}

protected disableEditorHover(): void {
this.editor.getControl().updateOptions({ hover: { enabled: false } });
}

protected enableEditorHover(): void {
const model = this.editor.getControl().getModel()!;
const overrides = {
resource: model.uri,
overrideIdentifier: model.getLanguageIdentifier().language,
};
const { enabled, delay, sticky } = this.configurationService._configuration.getValue('editor.hover', overrides, undefined);
this.editor.getControl().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 +223,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
23 changes: 16 additions & 7 deletions packages/debug/src/browser/editor/debug-hover-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,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 +127,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 +144,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 @@ -159,8 +162,8 @@ export class DebugHoverWidget extends SourceTreeWidget implements monaco.editor.
}
super.show();
this.options = options;
const expression = this.expressionProvider.get(this.editor.getControl().getModel()!, options.selection);
if (!expression) {
const rawExpression = this.expressionProvider.get(this.editor.getControl().getModel()!, options.selection);
if (!rawExpression) {
this.hide();
return;
}
Expand All @@ -171,17 +174,23 @@ export class DebugHoverWidget extends SourceTreeWidget implements monaco.editor.
this.activate();
}));
}
if (!await this.hoverSource.evaluate(expression)) {
const expression = await this.hoverSource.evaluate(rawExpression);
if (!expression) {
toFocus.dispose();
this.hide();
return;
}

this.domNode.classList.remove('complex-value');
if (expression.hasElements) {
this.domNode.classList.add('complex-value');
}

this.editor.getControl().layoutContentWidget(this);
}

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
11 changes: 7 additions & 4 deletions packages/debug/src/browser/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -342,16 +342,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 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 efbd89c

Please sign in to comment.