Skip to content

Commit

Permalink
ATL-988: Aligned the hover size to the expression.
Browse files Browse the repository at this point in the history
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
  • Loading branch information
Akos Kitta authored and kittaakos committed Mar 31, 2021
1 parent 8a692d0 commit 80bddc2
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ import { SearchInWorkspaceResultTreeWidget as TheiaSearchInWorkspaceResultTreeWi
import { SearchInWorkspaceResultTreeWidget } from './theia/search-in-workspace/search-in-workspace-result-tree-widget';
import { MonacoEditorProvider } from './theia/monaco/monaco-editor-provider';
import { MonacoEditorProvider as TheiaMonacoEditorProvider } from '@theia/monaco/lib/browser/monaco-editor-provider';
import { DebugEditorModel } from './theia/debug/debug-editor-model';
import { DebugEditorModelFactory } from '@theia/debug/lib/browser/editor/debug-editor-model';

const ElementQueries = require('css-element-queries/src/ElementQueries');

Expand Down Expand Up @@ -417,6 +419,11 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(DebugConfigurationManager).toSelf().inSingletonScope();
rebind(TheiaDebugConfigurationManager).toService(DebugConfigurationManager);

// Patch for the debug hover: https://github.com/eclipse-theia/theia/pull/9256/
rebind(DebugEditorModelFactory).toDynamicValue(({ container }) => <DebugEditorModelFactory>(editor =>
DebugEditorModel.createModel(container, editor)
)).inSingletonScope();

// Preferences
bindArduinoPreferences(bind);

Expand Down
36 changes: 36 additions & 0 deletions arduino-ide-extension/src/browser/style/debug.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* TODO: remove after https://github.com/eclipse-theia/theia/pull/9256/ */

/* To fix colors in Theia. */
.theia-debug-hover-title.number,
.theia-debug-console-variable.number {
color: var(--theia-variable-number-variable-color);
}
.theia-debug-hover-title.boolean,
.theia-debug-console-variable.boolean {
color: var(--theia-variable-boolean-variable-color);
}
.theia-debug-hover-title.string,
.theia-debug-console-variable.string {
color: var(--theia-variable-string-variable-color);
}

/* To unset the default debug hover dimension. */
.theia-debug-hover {
min-width: unset;
min-height: unset;
width: unset;
height: unset;
}

/* To adjust the left padding in the hover title. */
.theia-debug-hover-title {
padding-left: 5px;
}

/* Use the default Theia dimensions only iff the expression is complex (`!!expression.hasChildren~) */
.theia-debug-hover.complex-value {
min-width: 324px;
min-height: 324px;
width: 324px;
height: 324px;
}
1 change: 1 addition & 0 deletions arduino-ide-extension/src/browser/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@import './terminal.css';
@import './editor.css';
@import './settings-dialog.css';
@import './debug.css';

.theia-input.warning:focus {
outline-width: 1px;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import debounce from 'p-debounce';
import { inject, injectable, postConstruct, interfaces, Container } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
import { MonacoConfigurationService } from '@theia/monaco/lib/browser/monaco-frontend-module';
import { INLINE_VALUE_DECORATION_KEY } from '@theia/debug/lib/browser/editor//debug-inline-value-decorator';
import { DebugEditor } from '@theia/debug/lib/browser/editor/debug-editor';
import { DebugExceptionWidget } from '@theia/debug/lib/browser/editor/debug-exception-widget';
import { DebugBreakpointWidget } from '@theia/debug/lib/browser/editor/debug-breakpoint-widget';
import { DebugEditorModel as TheiaDebugEditorModel } from '@theia/debug/lib/browser/editor/debug-editor-model';
import { createDebugHoverWidgetContainer } from './debug-hover-widget'

// TODO: Remove after https://github.com/eclipse-theia/theia/pull/9256/
@injectable()
export class DebugEditorModel extends TheiaDebugEditorModel {

static createContainer(parent: interfaces.Container, editor: DebugEditor): Container {
const child = createDebugHoverWidgetContainer(parent, editor);
child.bind(DebugEditorModel).toSelf();
child.bind(DebugBreakpointWidget).toSelf();
child.bind(DebugExceptionWidget).toSelf();
return child;
}

static createModel(parent: interfaces.Container, editor: DebugEditor): DebugEditorModel {
return DebugEditorModel.createContainer(parent, editor).get(DebugEditorModel);
}

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

protected readonly toDisposeOnRenderFrames = new DisposableCollection();

@postConstruct()
protected init(): void {
this.toDispose.push(this.toDisposeOnRenderFrames);
super.init();
}

protected async updateEditorHover(): Promise<void> {
if (this.isCurrentEditorFrame(this.uri)) {
const codeEditor = this.editor.getControl();
codeEditor.updateOptions({ hover: { enabled: false } });
this.toDisposeOnRenderFrames.push(Disposable.create(() => {
const model = codeEditor.getModel()!;
const overrides = {
resource: model.uri,
overrideIdentifier: (model as any).getLanguageIdentifier().language,
};
const { enabled, delay, sticky } = this.configurationService._configuration.getValue('editor.hover', overrides, undefined);
codeEditor.updateOptions({
hover: {
enabled,
delay,
sticky
}
});
}));
}
}

private isCurrentEditorFrame(uri: URI): boolean {
return this.sessions.currentFrame?.source?.uri.toString() === uri.toString();
}

protected readonly renderFrames = debounce(async () => {
if (this.toDispose.disposed) {
return;
}
this.toDisposeOnRenderFrames.dispose();

this.toggleExceptionWidget();
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);
this.updateEditorHover();
}, 100);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { injectable } from 'inversify';
import { ExpressionItem, DebugVariable } from '@theia/debug/lib/browser/console/debug-console-items';
import { DebugHoverSource as TheiaDebugHoverSource } from '@theia/debug/lib/browser/editor/debug-hover-source';

// TODO: remove after https://github.com/eclipse-theia/theia/pull/9256/.
@injectable()
export class DebugHoverSource extends TheiaDebugHoverSource {

async evaluate2(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;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { injectable, interfaces, Container } from 'inversify';
import { Widget } from '@phosphor/widgets';
import { SourceTreeWidget } from '@theia/core/lib/browser/source-tree';
import { DisposableCollection } from '@theia/core/lib/common/disposable';
import { DebugEditor } from '@theia/debug/lib/browser/editor/debug-editor';
import { DebugVariable } from '@theia/debug/lib/browser/console/debug-console-items';
import { DebugExpressionProvider } from '@theia/debug/lib/browser/editor/debug-expression-provider';
import { DebugHoverSource as TheiaDebugHoverSource } from '@theia/debug/lib/browser/editor/debug-hover-source';
import { DebugHoverWidget as TheiaDebugHoverWidget, ShowDebugHoverOptions } from '@theia/debug/lib/browser/editor/debug-hover-widget';
import { DebugHoverSource } from './debug-hover-source';

export function createDebugHoverWidgetContainer(parent: interfaces.Container, editor: DebugEditor): Container {
const child = SourceTreeWidget.createContainer(parent, {
virtualized: false
});
child.bind(DebugEditor).toConstantValue(editor);
child.bind(TheiaDebugHoverSource).toSelf();
child.bind(DebugHoverSource).toSelf();
child.rebind(TheiaDebugHoverSource).to(DebugHoverSource);
child.unbind(SourceTreeWidget);
child.bind(DebugExpressionProvider).toSelf();
child.bind(TheiaDebugHoverWidget).toSelf();
child.bind(DebugHoverWidget).toSelf();
child.rebind(TheiaDebugHoverWidget).to(DebugHoverWidget);
return child;
}

// TODO: remove patch after https://github.com/eclipse-theia/theia/pull/9256/
@injectable()
export class DebugHoverWidget extends TheiaDebugHoverWidget {

protected async doShow(options: ShowDebugHoverOptions | undefined = this.options): Promise<void> {
if (!this.isEditorFrame()) {
this.hide();
return;
}
if (!options) {
this.hide();
return;
}
if (this.options && this.options.selection.equalsRange(options.selection)) {
return;
}
if (!this.isAttached) {
Widget.attach(this, this.contentNode);
}

this.options = options;
const matchingExpression = this.expressionProvider.get(this.editor.getControl().getModel()!, options.selection);
if (!matchingExpression) {
this.hide();
return;
}
const toFocus = new DisposableCollection();
if (this.options.focus === true) {
toFocus.push(this.model.onNodeRefreshed(() => {
toFocus.dispose();
this.activate();
}));
}
const expression = await (this.hoverSource as DebugHoverSource).evaluate2(matchingExpression);
if (!expression || !expression.value) {
toFocus.dispose();
this.hide();
return;
}

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(); // Here we cannot call `super.show()` but have to call `show` on the `Widget` prototype.
Widget.prototype.show.call(this);
await new Promise<void>(resolve => {
setTimeout(() => window.requestAnimationFrame(() => {
this.editor.getControl().layoutContentWidget(this);
resolve();
}), 0);
});
}

}

0 comments on commit 80bddc2

Please sign in to comment.