Skip to content

Press ALT in order to lock the hover in place #200327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/vs/editor/common/config/editorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2051,6 +2051,10 @@ export interface IEditorHoverOptions {
* Defaults to false.
*/
above?: boolean;
/**
* Enable locking of the hover
*/
enableLocking?: boolean;
}

/**
Expand All @@ -2067,6 +2071,7 @@ class EditorHover extends BaseEditorOption<EditorOption.hover, IEditorHoverOptio
hidingDelay: 300,
sticky: true,
above: true,
enableLocking: true,
};
super(
EditorOption.hover, 'hover', defaults,
Expand Down Expand Up @@ -2099,6 +2104,11 @@ class EditorHover extends BaseEditorOption<EditorOption.hover, IEditorHoverOptio
default: defaults.above,
description: nls.localize('hover.above', "Prefer showing hovers above the line, if there's space.")
},
'editor.hover.enableLocking': {
type: 'boolean',
default: defaults.enableLocking,
description: nls.localize('editor.hover.enableLocking', "Enable the locking of the hover. If enabled, the value of `editor.multiCursorModifier` will be used for locking.")
},
}
);
}
Expand All @@ -2114,6 +2124,7 @@ class EditorHover extends BaseEditorOption<EditorOption.hover, IEditorHoverOptio
sticky: boolean(input.sticky, this.defaultValue.sticky),
hidingDelay: EditorIntOption.clampedInt(input.hidingDelay, this.defaultValue.hidingDelay, 0, 600000),
above: boolean(input.above, this.defaultValue.above),
enableLocking: boolean(input.enableLocking, this.defaultValue.enableLocking),
};
}
}
Expand Down Expand Up @@ -5626,7 +5637,7 @@ export const EditorOptions = {
'- `ctrlCmd` refers to a value the setting can take and should not be localized.',
'- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.'
]
}, "The modifier to be used to add multiple cursors with the mouse. The Go to Definition and Open Link mouse gestures will adapt such that they do not conflict with the [multicursor modifier](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier).")
}, "The modifier to be used to add multiple cursors with the mouse. The Go to Definition, Open Link mouse and Lock Hover gestures will adapt such that they do not conflict with the [multicursor modifier](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier).")
}
)),
multiCursorPaste: register(new EditorStringEnumOption(
Expand Down
4 changes: 4 additions & 0 deletions src/vs/editor/contrib/hover/browser/contentHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,10 @@ export class ContentHoverWidget extends ResizableContentWidget {
public goToBottom(): void {
this._hover.scrollbar.setScrollPosition({ scrollTop: this._hover.scrollbar.getScrollDimensions().scrollHeight });
}

public toggleLocked(locked: boolean): void {
this._hover.containerDomNode.classList.toggle('locked', locked);
}
}

export class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar {
Expand Down
4 changes: 4 additions & 0 deletions src/vs/editor/contrib/hover/browser/hover.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
border-radius: 3px;
}

.monaco-editor .monaco-hover.locked {
outline: 1px solid var(--vscode-editorHoverWidget-border);
}

.monaco-editor .monaco-hover a {
color: var(--vscode-textLink-foreground);
}
Expand Down
53 changes: 51 additions & 2 deletions src/vs/editor/contrib/hover/browser/hover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { MarkerHoverParticipant } from 'vs/editor/contrib/hover/browser/markerHo
import { InlineSuggestionHintsContentWidget } from 'vs/editor/contrib/inlineCompletions/browser/inlineCompletionsHintsWidget';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { RunOnceScheduler } from 'vs/base/common/async';
import * as nls from 'vs/nls';
import 'vs/css!./hover';
Expand All @@ -42,10 +43,12 @@ interface IHoverSettings {
readonly enabled: boolean;
readonly sticky: boolean;
readonly hidingDelay: number;
readonly enableLocking: boolean;
}

interface IHoverState {
mouseDown: boolean;
locked: boolean;
// TODO @aiday-mar maybe not needed, investigate this
contentHoverFocused: boolean;
activatedByDecoratorClick: boolean;
Expand All @@ -63,9 +66,11 @@ export class HoverController extends Disposable implements IEditorContribution {
private _mouseMoveEvent: IEditorMouseEvent | undefined;
private _reactToEditorMouseMoveRunner: RunOnceScheduler;

private _usingAltForLocking!: boolean;
private _hoverSettings!: IHoverSettings;
private _hoverState: IHoverState = {
mouseDown: false,
locked: false,
contentHoverFocused: false,
activatedByDecoratorClick: false
};
Expand All @@ -84,11 +89,15 @@ export class HoverController extends Disposable implements IEditorContribution {
)
);
this._hookListeners();
this._usingAltForLocking = this._editor.getOption(EditorOption.multiCursorModifier) === 'altKey';
this._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {
if (e.hasChanged(EditorOption.hover)) {
this._unhookListeners();
this._hookListeners();
}
if (e.hasChanged(EditorOption.multiCursorModifier)) {
this._usingAltForLocking = this._editor.getOption(EditorOption.multiCursorModifier) === 'altKey';
}
}));
}

Expand All @@ -102,7 +111,8 @@ export class HoverController extends Disposable implements IEditorContribution {
this._hoverSettings = {
enabled: hoverOpts.enabled,
sticky: hoverOpts.sticky,
hidingDelay: hoverOpts.delay
hidingDelay: hoverOpts.delay,
enableLocking: hoverOpts.enableLocking
};

if (hoverOpts.enabled) {
Expand Down Expand Up @@ -175,9 +185,14 @@ export class HoverController extends Disposable implements IEditorContribution {
this._cancelScheduler();
const targetElement = (mouseEvent.event.browserEvent.relatedTarget) as HTMLElement;

if (this._contentWidget?.widget.isResizing || this._contentWidget?.containsNode(targetElement)) {
if (
this._contentWidget?.widget.isResizing
|| this._contentWidget?.containsNode(targetElement)
|| this._hoverState.locked
) {
// When the content widget is resizing
// When the mouse is inside hover widget
// When the widget is locked
return;
}
if (_sticky) {
Expand Down Expand Up @@ -229,6 +244,27 @@ export class HoverController extends Disposable implements IEditorContribution {
private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void {

this._mouseMoveEvent = mouseEvent;
if (this._hoverSettings.enableLocking) {
if (this._lockHoverKeys(mouseEvent.event)) {
// When the alt key is pressed, and other key modifiers are not
if (
this._contentWidget?.isVisible
&& !this._hoverState.locked
) {
// Toggle locked state when the hover is visible and the state is not locked
this._toggleLockedState(true);
this._reactToEditorMouseMoveRunner.cancel();
return;
}
if (this._hoverState.locked) {
return;
}
}
if (this._hoverState.locked) {
this._toggleLockedState(false);
}
}

if (this._contentWidget?.isFocused || this._contentWidget?.isResizing) {
return;
}
Expand Down Expand Up @@ -338,6 +374,19 @@ export class HoverController extends Disposable implements IEditorContribution {
this._hideWidgets();
}

private _lockHoverKeys(event: IMouseEvent): boolean {
if (this._usingAltForLocking) {
return event.altKey && !event.metaKey && !event.ctrlKey && !event.shiftKey;
} else {
return event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey;
}
}

private _toggleLockedState(locked: boolean) {
this._hoverState.locked = locked;
this._contentWidget?.widget.toggleLocked(locked);
}

private _hideWidgets(): void {
if (_sticky) {
return;
Expand Down
4 changes: 4 additions & 0 deletions src/vs/monaco.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4011,6 +4011,10 @@ declare namespace monaco.editor {
* Defaults to false.
*/
above?: boolean;
/**
* Enable locking of the hover
*/
enableLocking?: boolean;
}

/**
Expand Down