Close arguments hints tooltip when finished

The console prompt is one of two places (the other being the edit
breakpoint prompt) that uses arguments hints. However, when the user
would show the arguments hints and be finished with it (e.g. hitting
escape or entering a command), they wouldn't properly hide.

The functionality is implemented in `cursor_tooltip`, which defines
the two view effects that trigger opening/closing the tooltip. However,
there was no outside access to these effects and they were not hooked
up to the corresponding view (in this case residing in `ConsolePrompt.ts`).

To make sure that the ConsolePrompt doesn't learn too much about the
inner workings of the text editor, we expose a separate function on
the JavaScript functionality of the editor. It dispatches the close
effect on the view, which ensures that the arguments hints tooltip
is properly hidden. This is also true for entering a command,
which is implemented in `handleEnter`.

Lastly, update the internal cursor_tooltip plugin to use private methods,
to clearly denote what is part of the public API (`update`) and what
isn't (the rest).

R=yangguo@chromium.org

Fixed: 1299196, 1299186
Change-Id: I650c25f42564be8992a849b6b8deefff51ff7826
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/3477109
Auto-Submit: Tim Van der Lippe <tvanderlippe@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
This commit is contained in:
Tim van der Lippe
2022-02-21 16:23:35 +00:00
committed by Devtools-frontend LUCI CQ
parent 7961ea6fa9
commit ab78bc61ba
3 changed files with 21 additions and 7 deletions
@@ -209,6 +209,13 @@ export class ConsolePrompt extends Common.ObjectWrapper.eventMixin<EventTypes, t
{key: 'ArrowDown', run: (): boolean => this.moveHistory(1)},
{mac: 'Ctrl-p', run: (): boolean => this.moveHistory(-1, true)},
{mac: 'Ctrl-n', run: (): boolean => this.moveHistory(1, true)},
{
key: 'Escape',
run: (): boolean => {
TextEditor.JavaScript.closeArgumentsHintsTooltip(this.editor.editor);
return true;
},
},
{
key: 'Enter',
run: (): boolean => {
@@ -259,6 +266,7 @@ export class ConsolePrompt extends Common.ObjectWrapper.eventMixin<EventTypes, t
private async handleEnter(): Promise<void> {
if (await this.enterWillEvaluate()) {
this.appendCommand(this.text(), true);
TextEditor.JavaScript.closeArgumentsHintsTooltip(this.editor.editor);
this.editor.dispatch({
changes: {from: 0, to: this.editor.state.doc.length},
scrollIntoView: true,
@@ -4,11 +4,12 @@
import * as CodeMirror from '../../../third_party/codemirror.next/codemirror.next.js';
export const closeTooltip = CodeMirror.StateEffect.define<null>();
export function cursorTooltip(
source: (state: CodeMirror.EditorState, pos: number) => Promise<(() => CodeMirror.TooltipView)|null>,
): CodeMirror.Extension {
const openTooltip = CodeMirror.StateEffect.define<() => CodeMirror.TooltipView>();
const closeTooltip = CodeMirror.StateEffect.define<null>();
const state = CodeMirror.StateField.define<null|CodeMirror.Tooltip>({
create() {
@@ -41,18 +42,18 @@ export function cursorTooltip(
update(update: CodeMirror.ViewUpdate): void {
this.updateID++;
if (update.transactions.some(tr => tr.selection) && update.state.selection.main.empty) {
this.scheduleUpdate(update.view);
this.#scheduleUpdate(update.view);
}
}
scheduleUpdate(view: CodeMirror.EditorView): void {
#scheduleUpdate(view: CodeMirror.EditorView): void {
if (this.pending > -1) {
clearTimeout(this.pending);
}
this.pending = window.setTimeout(() => this.startUpdate(view), 50) as unknown as number;
this.pending = window.setTimeout(() => this.#startUpdate(view), 50) as unknown as number;
}
startUpdate(view: CodeMirror.EditorView): void {
#startUpdate(view: CodeMirror.EditorView): void {
this.pending = -1;
const {main} = view.state.selection;
if (main.empty) {
@@ -60,7 +61,7 @@ export function cursorTooltip(
void source(view.state, main.from).then(tooltip => {
if (this.updateID !== updateID) {
if (this.pending < 0) {
this.scheduleUpdate(view);
this.#scheduleUpdate(view);
}
} else if (tooltip) {
view.dispatch({effects: openTooltip.of(tooltip)});
@@ -7,7 +7,8 @@ import * as Formatter from '../../../models/formatter/formatter.js';
import * as JavaScriptMetaData from '../../../models/javascript_metadata/javascript_metadata.js';
import * as CodeMirror from '../../../third_party/codemirror.next/codemirror.next.js';
import * as UI from '../../legacy/legacy.js';
import {cursorTooltip} from './cursor_tooltip.js';
import {closeTooltip, cursorTooltip} from './cursor_tooltip.js';
export function completion(): CodeMirror.Extension {
return CodeMirror.javascript.javascriptLanguage.data.of({
@@ -424,6 +425,10 @@ export function argumentHints(): CodeMirror.Extension {
return cursorTooltip(getArgumentHints);
}
export function closeArgumentsHintsTooltip(view: CodeMirror.EditorView): void {
view.dispatch({effects: closeTooltip.of(null)});
}
async function getArgumentHints(
state: CodeMirror.EditorState, pos: number): Promise<(() => CodeMirror.TooltipView)|null> {
const node = CodeMirror.syntaxTree(state).resolveInner(pos).enterUnfinishedNodesBefore(pos);