2d7d0ca26227ceaf4797ca371b7d4285bc32fe98772cdfffd40756c1781d5e00e2ba93fa87692a8a248ed65248004c742ac5e982b5e22e38bc94a3b24d1fa5 15 KB

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