hover.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  6. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  7. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  8. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  9. return c > 3 && r && Object.defineProperty(target, key, r), r;
  10. };
  11. var __param = (this && this.__param) || function (paramIndex, decorator) {
  12. return function (target, key) { decorator(target, key, paramIndex); }
  13. };
  14. import { KeyChord } from '../../../base/common/keyCodes.js';
  15. import { DisposableStore } from '../../../base/common/lifecycle.js';
  16. import { EditorAction, registerEditorAction, registerEditorContribution } from '../../browser/editorExtensions.js';
  17. import { Range } from '../../common/core/range.js';
  18. import { EditorContextKeys } from '../../common/editorContextKeys.js';
  19. import { IModeService } from '../../common/services/modeService.js';
  20. import { GotoDefinitionAtPositionEditorContribution } from '../gotoSymbol/link/goToDefinitionAtPosition.js';
  21. import { ModesContentHoverWidget } from './modesContentHover.js';
  22. import { ModesGlyphHoverWidget } from './modesGlyphHover.js';
  23. import * as nls from '../../../nls.js';
  24. import { IContextKeyService } from '../../../platform/contextkey/common/contextkey.js';
  25. import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
  26. import { IOpenerService } from '../../../platform/opener/common/opener.js';
  27. import { editorHoverBackground, editorHoverBorder, editorHoverForeground, editorHoverHighlight, editorHoverStatusBarBackground, textCodeBlockBackground, textLinkActiveForeground, textLinkForeground } from '../../../platform/theme/common/colorRegistry.js';
  28. import { registerThemingParticipant } from '../../../platform/theme/common/themeService.js';
  29. let ModesHoverController = class ModesHoverController {
  30. constructor(_editor, _instantiationService, _openerService, _modeService, _contextKeyService) {
  31. this._editor = _editor;
  32. this._instantiationService = _instantiationService;
  33. this._openerService = _openerService;
  34. this._modeService = _modeService;
  35. this._toUnhook = new DisposableStore();
  36. this._isMouseDown = false;
  37. this._hoverClicked = false;
  38. this._contentWidget = null;
  39. this._glyphWidget = null;
  40. this._hookEvents();
  41. this._didChangeConfigurationHandler = this._editor.onDidChangeConfiguration((e) => {
  42. if (e.hasChanged(52 /* hover */)) {
  43. this._unhookEvents();
  44. this._hookEvents();
  45. }
  46. });
  47. this._hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(_contextKeyService);
  48. }
  49. static get(editor) {
  50. return editor.getContribution(ModesHoverController.ID);
  51. }
  52. _hookEvents() {
  53. const hideWidgetsEventHandler = () => this._hideWidgets();
  54. const hoverOpts = this._editor.getOption(52 /* hover */);
  55. this._isHoverEnabled = hoverOpts.enabled;
  56. this._isHoverSticky = hoverOpts.sticky;
  57. if (this._isHoverEnabled) {
  58. this._toUnhook.add(this._editor.onMouseDown((e) => this._onEditorMouseDown(e)));
  59. this._toUnhook.add(this._editor.onMouseUp((e) => this._onEditorMouseUp(e)));
  60. this._toUnhook.add(this._editor.onMouseMove((e) => this._onEditorMouseMove(e)));
  61. this._toUnhook.add(this._editor.onKeyDown((e) => this._onKeyDown(e)));
  62. this._toUnhook.add(this._editor.onDidChangeModelDecorations(() => this._onModelDecorationsChanged()));
  63. }
  64. else {
  65. this._toUnhook.add(this._editor.onMouseMove((e) => this._onEditorMouseMove(e)));
  66. this._toUnhook.add(this._editor.onKeyDown((e) => this._onKeyDown(e)));
  67. }
  68. this._toUnhook.add(this._editor.onMouseLeave(hideWidgetsEventHandler));
  69. this._toUnhook.add(this._editor.onDidChangeModel(hideWidgetsEventHandler));
  70. this._toUnhook.add(this._editor.onDidScrollChange((e) => this._onEditorScrollChanged(e)));
  71. }
  72. _unhookEvents() {
  73. this._toUnhook.clear();
  74. }
  75. _onModelDecorationsChanged() {
  76. var _a, _b;
  77. (_a = this._contentWidget) === null || _a === void 0 ? void 0 : _a.onModelDecorationsChanged();
  78. (_b = this._glyphWidget) === null || _b === void 0 ? void 0 : _b.onModelDecorationsChanged();
  79. }
  80. _onEditorScrollChanged(e) {
  81. if (e.scrollTopChanged || e.scrollLeftChanged) {
  82. this._hideWidgets();
  83. }
  84. }
  85. _onEditorMouseDown(mouseEvent) {
  86. this._isMouseDown = true;
  87. const targetType = mouseEvent.target.type;
  88. if (targetType === 9 /* CONTENT_WIDGET */ && mouseEvent.target.detail === ModesContentHoverWidget.ID) {
  89. this._hoverClicked = true;
  90. // mouse down on top of content hover widget
  91. return;
  92. }
  93. if (targetType === 12 /* OVERLAY_WIDGET */ && mouseEvent.target.detail === ModesGlyphHoverWidget.ID) {
  94. // mouse down on top of overlay hover widget
  95. return;
  96. }
  97. if (targetType !== 12 /* OVERLAY_WIDGET */ && mouseEvent.target.detail !== ModesGlyphHoverWidget.ID) {
  98. this._hoverClicked = false;
  99. }
  100. this._hideWidgets();
  101. }
  102. _onEditorMouseUp(mouseEvent) {
  103. this._isMouseDown = false;
  104. }
  105. _onEditorMouseMove(mouseEvent) {
  106. var _a, _b, _c, _d, _e;
  107. let targetType = mouseEvent.target.type;
  108. if (this._isMouseDown && this._hoverClicked) {
  109. return;
  110. }
  111. if (this._isHoverSticky && targetType === 9 /* CONTENT_WIDGET */ && mouseEvent.target.detail === ModesContentHoverWidget.ID) {
  112. // mouse moved on top of content hover widget
  113. return;
  114. }
  115. if (this._isHoverSticky && !((_b = (_a = mouseEvent.event.browserEvent.view) === null || _a === void 0 ? void 0 : _a.getSelection()) === null || _b === void 0 ? void 0 : _b.isCollapsed)) {
  116. // selected text within content hover widget
  117. return;
  118. }
  119. if (!this._isHoverSticky && targetType === 9 /* CONTENT_WIDGET */ && mouseEvent.target.detail === ModesContentHoverWidget.ID
  120. && ((_c = this._contentWidget) === null || _c === void 0 ? void 0 : _c.isColorPickerVisible())) {
  121. // though the hover is not sticky, the color picker needs to.
  122. return;
  123. }
  124. if (this._isHoverSticky && targetType === 12 /* OVERLAY_WIDGET */ && mouseEvent.target.detail === ModesGlyphHoverWidget.ID) {
  125. // mouse moved on top of overlay hover widget
  126. return;
  127. }
  128. if (!this._isHoverEnabled) {
  129. this._hideWidgets();
  130. return;
  131. }
  132. const contentWidget = this._getOrCreateContentWidget();
  133. if (contentWidget.maybeShowAt(mouseEvent)) {
  134. (_d = this._glyphWidget) === null || _d === void 0 ? void 0 : _d.hide();
  135. return;
  136. }
  137. if (targetType === 2 /* GUTTER_GLYPH_MARGIN */ && mouseEvent.target.position) {
  138. (_e = this._contentWidget) === null || _e === void 0 ? void 0 : _e.hide();
  139. if (!this._glyphWidget) {
  140. this._glyphWidget = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService);
  141. }
  142. this._glyphWidget.startShowingAt(mouseEvent.target.position.lineNumber);
  143. return;
  144. }
  145. this._hideWidgets();
  146. }
  147. _onKeyDown(e) {
  148. if (e.keyCode !== 5 /* Ctrl */ && e.keyCode !== 6 /* Alt */ && e.keyCode !== 57 /* Meta */ && e.keyCode !== 4 /* Shift */) {
  149. // Do not hide hover when a modifier key is pressed
  150. this._hideWidgets();
  151. }
  152. }
  153. _hideWidgets() {
  154. var _a, _b, _c;
  155. if ((this._isMouseDown && this._hoverClicked && ((_a = this._contentWidget) === null || _a === void 0 ? void 0 : _a.isColorPickerVisible()))) {
  156. return;
  157. }
  158. this._hoverClicked = false;
  159. (_b = this._glyphWidget) === null || _b === void 0 ? void 0 : _b.hide();
  160. (_c = this._contentWidget) === null || _c === void 0 ? void 0 : _c.hide();
  161. }
  162. _getOrCreateContentWidget() {
  163. if (!this._contentWidget) {
  164. this._contentWidget = this._instantiationService.createInstance(ModesContentHoverWidget, this._editor, this._hoverVisibleKey);
  165. }
  166. return this._contentWidget;
  167. }
  168. isColorPickerVisible() {
  169. var _a;
  170. return ((_a = this._contentWidget) === null || _a === void 0 ? void 0 : _a.isColorPickerVisible()) || false;
  171. }
  172. showContentHover(range, mode, focus) {
  173. this._getOrCreateContentWidget().startShowingAtRange(range, mode, focus);
  174. }
  175. dispose() {
  176. var _a, _b;
  177. this._unhookEvents();
  178. this._toUnhook.dispose();
  179. this._didChangeConfigurationHandler.dispose();
  180. (_a = this._glyphWidget) === null || _a === void 0 ? void 0 : _a.dispose();
  181. (_b = this._contentWidget) === null || _b === void 0 ? void 0 : _b.dispose();
  182. }
  183. };
  184. ModesHoverController.ID = 'editor.contrib.hover';
  185. ModesHoverController = __decorate([
  186. __param(1, IInstantiationService),
  187. __param(2, IOpenerService),
  188. __param(3, IModeService),
  189. __param(4, IContextKeyService)
  190. ], ModesHoverController);
  191. export { ModesHoverController };
  192. class ShowHoverAction extends EditorAction {
  193. constructor() {
  194. super({
  195. id: 'editor.action.showHover',
  196. label: nls.localize({
  197. key: 'showHover',
  198. comment: [
  199. 'Label for action that will trigger the showing of a hover in the editor.',
  200. 'This allows for users to show the hover without using the mouse.'
  201. ]
  202. }, "Show Hover"),
  203. alias: 'Show Hover',
  204. precondition: undefined,
  205. kbOpts: {
  206. kbExpr: EditorContextKeys.editorTextFocus,
  207. primary: KeyChord(2048 /* CtrlCmd */ | 41 /* KeyK */, 2048 /* CtrlCmd */ | 39 /* KeyI */),
  208. weight: 100 /* EditorContrib */
  209. }
  210. });
  211. }
  212. run(accessor, editor) {
  213. if (!editor.hasModel()) {
  214. return;
  215. }
  216. let controller = ModesHoverController.get(editor);
  217. if (!controller) {
  218. return;
  219. }
  220. const position = editor.getPosition();
  221. const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
  222. const focus = editor.getOption(2 /* accessibilitySupport */) === 2 /* Enabled */;
  223. controller.showContentHover(range, 1 /* Immediate */, focus);
  224. }
  225. }
  226. class ShowDefinitionPreviewHoverAction extends EditorAction {
  227. constructor() {
  228. super({
  229. id: 'editor.action.showDefinitionPreviewHover',
  230. label: nls.localize({
  231. key: 'showDefinitionPreviewHover',
  232. comment: [
  233. 'Label for action that will trigger the showing of definition preview hover in the editor.',
  234. 'This allows for users to show the definition preview hover without using the mouse.'
  235. ]
  236. }, "Show Definition Preview Hover"),
  237. alias: 'Show Definition Preview Hover',
  238. precondition: undefined
  239. });
  240. }
  241. run(accessor, editor) {
  242. let controller = ModesHoverController.get(editor);
  243. if (!controller) {
  244. return;
  245. }
  246. const position = editor.getPosition();
  247. if (!position) {
  248. return;
  249. }
  250. const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
  251. const goto = GotoDefinitionAtPositionEditorContribution.get(editor);
  252. const promise = goto.startFindDefinitionFromCursor(position);
  253. promise.then(() => {
  254. controller.showContentHover(range, 1 /* Immediate */, true);
  255. });
  256. }
  257. }
  258. registerEditorContribution(ModesHoverController.ID, ModesHoverController);
  259. registerEditorAction(ShowHoverAction);
  260. registerEditorAction(ShowDefinitionPreviewHoverAction);
  261. // theming
  262. registerThemingParticipant((theme, collector) => {
  263. const editorHoverHighlightColor = theme.getColor(editorHoverHighlight);
  264. if (editorHoverHighlightColor) {
  265. collector.addRule(`.monaco-editor .hoverHighlight { background-color: ${editorHoverHighlightColor}; }`);
  266. }
  267. const hoverBackground = theme.getColor(editorHoverBackground);
  268. if (hoverBackground) {
  269. collector.addRule(`.monaco-editor .monaco-hover { background-color: ${hoverBackground}; }`);
  270. }
  271. const hoverBorder = theme.getColor(editorHoverBorder);
  272. if (hoverBorder) {
  273. collector.addRule(`.monaco-editor .monaco-hover { border: 1px solid ${hoverBorder}; }`);
  274. collector.addRule(`.monaco-editor .monaco-hover .hover-row:not(:first-child):not(:empty) { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
  275. collector.addRule(`.monaco-editor .monaco-hover hr { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
  276. collector.addRule(`.monaco-editor .monaco-hover hr { border-bottom: 0px solid ${hoverBorder.transparent(0.5)}; }`);
  277. }
  278. const link = theme.getColor(textLinkForeground);
  279. if (link) {
  280. collector.addRule(`.monaco-editor .monaco-hover a { color: ${link}; }`);
  281. }
  282. const linkHover = theme.getColor(textLinkActiveForeground);
  283. if (linkHover) {
  284. collector.addRule(`.monaco-editor .monaco-hover a:hover { color: ${linkHover}; }`);
  285. }
  286. const hoverForeground = theme.getColor(editorHoverForeground);
  287. if (hoverForeground) {
  288. collector.addRule(`.monaco-editor .monaco-hover { color: ${hoverForeground}; }`);
  289. }
  290. const actionsBackground = theme.getColor(editorHoverStatusBarBackground);
  291. if (actionsBackground) {
  292. collector.addRule(`.monaco-editor .monaco-hover .hover-row .actions { background-color: ${actionsBackground}; }`);
  293. }
  294. const codeBackground = theme.getColor(textCodeBlockBackground);
  295. if (codeBackground) {
  296. collector.addRule(`.monaco-editor .monaco-hover code { background-color: ${codeBackground}; }`);
  297. }
  298. });