hover.ts 7.7 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

import 'vs/css!./hover';
A
Alex Dima 已提交
9
import * as nls from 'vs/nls';
J
Johannes Rieken 已提交
10
import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes';
A
Alex Dima 已提交
11
import * as platform from 'vs/base/common/platform';
J
Johannes Rieken 已提交
12 13 14 15
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IModeService } from 'vs/editor/common/services/modeService';
import { Range } from 'vs/editor/common/core/range';
A
Alex Dima 已提交
16
import * as editorCommon from 'vs/editor/common/editorCommon';
J
Johannes Rieken 已提交
17
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
A
Alex Dima 已提交
18
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
J
Johannes Rieken 已提交
19 20 21 22
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
import { ModesContentHoverWidget } from './modesContentHover';
import { ModesGlyphHoverWidget } from './modesGlyphHover';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
23
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
24
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
25
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
A
Alex Dima 已提交
26

27
@editorContribution
J
Joao Moreno 已提交
28
export class ModesHoverController implements editorCommon.IEditorContribution {
E
Erich Gamma 已提交
29

30
	private static ID = 'editor.contrib.hover';
E
Erich Gamma 已提交
31

A
Alex Dima 已提交
32
	private _editor: ICodeEditor;
J
Johannes Rieken 已提交
33
	private _toUnhook: IDisposable[];
E
Erich Gamma 已提交
34

A
Alex Dima 已提交
35 36
	private _contentWidget: ModesContentHoverWidget;
	private _glyphWidget: ModesGlyphHoverWidget;
E
Erich Gamma 已提交
37

A
Alex Dima 已提交
38 39
	static get(editor: editorCommon.ICommonCodeEditor): ModesHoverController {
		return editor.getContribution<ModesHoverController>(ModesHoverController.ID);
I
isidor 已提交
40 41
	}

A
Alex Dima 已提交
42
	constructor(editor: ICodeEditor,
43 44
		@IOpenerService openerService: IOpenerService,
		@IModeService modeService: IModeService
45
	) {
E
Erich Gamma 已提交
46 47 48 49
		this._editor = editor;

		this._toUnhook = [];

A
Alex Dima 已提交
50
		if (editor.getConfiguration().contribInfo.hover) {
A
Alex Dima 已提交
51 52 53
			this._toUnhook.push(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e)));
			this._toUnhook.push(this._editor.onMouseMove((e: IEditorMouseEvent) => this._onEditorMouseMove(e)));
			this._toUnhook.push(this._editor.onMouseLeave((e: IEditorMouseEvent) => this._hideWidgets()));
J
Johannes Rieken 已提交
54
			this._toUnhook.push(this._editor.onKeyDown((e: IKeyboardEvent) => this._onKeyDown(e)));
A
Alex Dima 已提交
55 56
			this._toUnhook.push(this._editor.onDidChangeModel(() => this._hideWidgets()));
			this._toUnhook.push(this._editor.onDidChangeModelDecorations(() => this._onModelDecorationsChanged()));
A
Alex Dima 已提交
57 58 59 60 61
			this._toUnhook.push(this._editor.onDidScrollChange((e) => {
				if (e.scrollTopChanged || e.scrollLeftChanged) {
					this._hideWidgets();
				}
			}));
E
Erich Gamma 已提交
62

63
			this._contentWidget = new ModesContentHoverWidget(editor, openerService, modeService);
J
Joao Moreno 已提交
64
			this._glyphWidget = new ModesGlyphHoverWidget(editor, openerService, modeService);
E
Erich Gamma 已提交
65 66 67 68 69 70 71 72
		}
	}

	private _onModelDecorationsChanged(): void {
		this._contentWidget.onModelDecorationsChanged();
		this._glyphWidget.onModelDecorationsChanged();
	}

A
Alex Dima 已提交
73
	private _onEditorMouseDown(mouseEvent: IEditorMouseEvent): void {
E
Erich Gamma 已提交
74 75
		var targetType = mouseEvent.target.type;

A
Alex Dima 已提交
76
		if (targetType === MouseTargetType.CONTENT_WIDGET && mouseEvent.target.detail === ModesContentHoverWidget.ID) {
E
Erich Gamma 已提交
77 78 79 80
			// mouse down on top of content hover widget
			return;
		}

A
Alex Dima 已提交
81
		if (targetType === MouseTargetType.OVERLAY_WIDGET && mouseEvent.target.detail === ModesGlyphHoverWidget.ID) {
E
Erich Gamma 已提交
82 83 84 85 86 87 88
			// mouse down on top of overlay hover widget
			return;
		}

		this._hideWidgets();
	}

A
Alex Dima 已提交
89
	private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void {
E
Erich Gamma 已提交
90
		var targetType = mouseEvent.target.type;
A
Alex Dima 已提交
91
		var stopKey = platform.isMacintosh ? 'metaKey' : 'ctrlKey';
E
Erich Gamma 已提交
92

A
Alex Dima 已提交
93
		if (targetType === MouseTargetType.CONTENT_WIDGET && mouseEvent.target.detail === ModesContentHoverWidget.ID && !mouseEvent.event[stopKey]) {
E
Erich Gamma 已提交
94 95 96 97
			// mouse moved on top of content hover widget
			return;
		}

A
Alex Dima 已提交
98
		if (targetType === MouseTargetType.OVERLAY_WIDGET && mouseEvent.target.detail === ModesGlyphHoverWidget.ID && !mouseEvent.event[stopKey]) {
E
Erich Gamma 已提交
99 100 101 102
			// mouse moved on top of overlay hover widget
			return;
		}

A
Alex Dima 已提交
103
		if (this._editor.getConfiguration().contribInfo.hover && targetType === MouseTargetType.CONTENT_TEXT) {
E
Erich Gamma 已提交
104
			this._glyphWidget.hide();
I
isidor 已提交
105
			this._contentWidget.startShowingAt(mouseEvent.target.range, false);
A
Alex Dima 已提交
106
		} else if (targetType === MouseTargetType.GUTTER_GLYPH_MARGIN) {
E
Erich Gamma 已提交
107 108 109 110 111 112 113
			this._contentWidget.hide();
			this._glyphWidget.startShowingAt(mouseEvent.target.position.lineNumber);
		} else {
			this._hideWidgets();
		}
	}

A
Alex Dima 已提交
114 115
	private _onKeyDown(e: IKeyboardEvent): void {
		var stopKey = platform.isMacintosh ? KeyCode.Meta : KeyCode.Ctrl;
E
Erich Gamma 已提交
116 117 118 119 120 121 122 123 124 125 126
		if (e.keyCode !== stopKey) {
			// Do not hide hover when Ctrl/Meta is pressed
			this._hideWidgets();
		}
	}

	private _hideWidgets(): void {
		this._glyphWidget.hide();
		this._contentWidget.hide();
	}

127
	public showContentHover(range: Range, focus: boolean): void {
I
isidor 已提交
128 129 130
		this._contentWidget.startShowingAt(range, focus);
	}

E
Erich Gamma 已提交
131 132 133 134 135
	public getId(): string {
		return ModesHoverController.ID;
	}

	public dispose(): void {
A
Alex Dima 已提交
136
		this._toUnhook = dispose(this._toUnhook);
E
Erich Gamma 已提交
137 138 139 140 141 142 143 144 145 146 147
		if (this._glyphWidget) {
			this._glyphWidget.dispose();
			this._glyphWidget = null;
		}
		if (this._contentWidget) {
			this._contentWidget.dispose();
			this._contentWidget = null;
		}
	}
}

A
Alex Dima 已提交
148
@editorAction
A
Alex Dima 已提交
149
class ShowHoverAction extends EditorAction {
I
isidor 已提交
150

A
Alex Dima 已提交
151
	constructor() {
152 153 154 155 156 157
		super({
			id: 'editor.action.showHover',
			label: nls.localize('showHover', "Show Hover"),
			alias: 'Show Hover',
			precondition: null,
			kbOpts: {
158
				kbExpr: EditorContextKeys.textFocus,
A
Alex Dima 已提交
159
				primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_I)
160 161
			}
		});
I
isidor 已提交
162 163
	}

J
Johannes Rieken 已提交
164
	public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void {
165 166 167 168
		let controller = ModesHoverController.get(editor);
		if (!controller) {
			return;
		}
A
Alex Dima 已提交
169
		const position = editor.getPosition();
I
isidor 已提交
170
		const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
171
		controller.showContentHover(range, true);
I
isidor 已提交
172 173
	}
}
174

175 176
// theming

177 178 179
export const editorHoverHighlight = registerColor('editor.hoverHighlightBackground', { light: '#ADD6FF26', dark: '#264f7840', hc: '#ADD6FF26' }, nls.localize('hoverHighlight', 'Highlight below the word for which a hover is shown.'));
export const editorHoverBackground = registerColor('editorHoverWidget.background', { light: '#F3F3F3', dark: '#2D2D30', hc: '#0C141F' }, nls.localize('hoverBackground', 'Background color of the editor hover.'));
export const editorHoverBorder = registerColor('editorHoverWidget.border', { light: '#CCCCCC', dark: '#555555', hc: '#CCCCCC' }, nls.localize('hoverBorder', 'Border color of the editor hover.'));
180 181

registerThemingParticipant((theme, collector) => {
182 183 184 185
	let editorHoverHighlightColor = theme.getColor(editorHoverHighlight);
	if (editorHoverHighlightColor) {
		collector.addRule(`.monaco-editor.${theme.selector} .hoverHighlight { background-color: ${editorHoverHighlightColor}; }`);
	}
M
Martin Aeschlimann 已提交
186 187 188 189 190 191 192 193 194
	let hoverBackground = theme.getColor(editorHoverBackground);
	if (hoverBackground) {
		collector.addRule(`.monaco-editor.${theme.selector} .monaco-editor-hover { background-color: ${hoverBackground}; }`);
	}
	let hoverBorder = theme.getColor(editorHoverBorder);
	if (hoverBorder) {
		collector.addRule(`.monaco-editor.${theme.selector} .monaco-editor-hover { border: 1px solid ${hoverBorder}; }`);
		collector.addRule(`.monaco-editor.${theme.selector} .monaco-editor-hover .hover-row:not(:first-child):not(:empty) { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
	}
195
});