2edd35aab3c9bcb64ab1d8eeddf613b012f790f5ba2f3909a9cd77e16a2f4334982820409439316af160df2968845c7806bd143fd830ef997ac7375c518030 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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 * as dom from '../../../../base/browser/dom.js';
  15. import { MarkdownString } from '../../../../base/common/htmlContent.js';
  16. import { DisposableStore } from '../../../../base/common/lifecycle.js';
  17. import { MarkdownRenderer } from '../../markdownRenderer/browser/markdownRenderer.js';
  18. import { Range } from '../../../common/core/range.js';
  19. import { ILanguageService } from '../../../common/languages/language.js';
  20. import { HoverForeignElementAnchor } from '../../hover/browser/hoverTypes.js';
  21. import { GhostTextController, ShowNextInlineSuggestionAction, ShowPreviousInlineSuggestionAction } from './ghostTextController.js';
  22. import * as nls from '../../../../nls.js';
  23. import { IAccessibilityService } from '../../../../platform/accessibility/common/accessibility.js';
  24. import { IMenuService, MenuId, MenuItemAction } from '../../../../platform/actions/common/actions.js';
  25. import { ICommandService } from '../../../../platform/commands/common/commands.js';
  26. import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
  27. import { IOpenerService } from '../../../../platform/opener/common/opener.js';
  28. import { inlineSuggestCommitId } from './consts.js';
  29. export class InlineCompletionsHover {
  30. constructor(owner, range, controller) {
  31. this.owner = owner;
  32. this.range = range;
  33. this.controller = controller;
  34. }
  35. isValidForHoverAnchor(anchor) {
  36. return (anchor.type === 1 /* HoverAnchorType.Range */
  37. && this.range.startColumn <= anchor.range.startColumn
  38. && this.range.endColumn >= anchor.range.endColumn);
  39. }
  40. hasMultipleSuggestions() {
  41. return this.controller.hasMultipleInlineCompletions();
  42. }
  43. get commands() {
  44. var _a, _b, _c;
  45. return ((_c = (_b = (_a = this.controller.activeModel) === null || _a === void 0 ? void 0 : _a.activeInlineCompletionsModel) === null || _b === void 0 ? void 0 : _b.completionSession.value) === null || _c === void 0 ? void 0 : _c.commands) || [];
  46. }
  47. }
  48. let InlineCompletionsHoverParticipant = class InlineCompletionsHoverParticipant {
  49. constructor(_editor, _commandService, _menuService, _contextKeyService, _languageService, _openerService, accessibilityService) {
  50. this._editor = _editor;
  51. this._commandService = _commandService;
  52. this._menuService = _menuService;
  53. this._contextKeyService = _contextKeyService;
  54. this._languageService = _languageService;
  55. this._openerService = _openerService;
  56. this.accessibilityService = accessibilityService;
  57. this.hoverOrdinal = 3;
  58. }
  59. suggestHoverAnchor(mouseEvent) {
  60. const controller = GhostTextController.get(this._editor);
  61. if (!controller) {
  62. return null;
  63. }
  64. const target = mouseEvent.target;
  65. if (target.type === 8 /* MouseTargetType.CONTENT_VIEW_ZONE */) {
  66. // handle the case where the mouse is over the view zone
  67. const viewZoneData = target.detail;
  68. if (controller.shouldShowHoverAtViewZone(viewZoneData.viewZoneId)) {
  69. return new HoverForeignElementAnchor(1000, this, Range.fromPositions(viewZoneData.positionBefore || viewZoneData.position, viewZoneData.positionBefore || viewZoneData.position));
  70. }
  71. }
  72. if (target.type === 7 /* MouseTargetType.CONTENT_EMPTY */) {
  73. // handle the case where the mouse is over the empty portion of a line following ghost text
  74. if (controller.shouldShowHoverAt(target.range)) {
  75. return new HoverForeignElementAnchor(1000, this, target.range);
  76. }
  77. }
  78. if (target.type === 6 /* MouseTargetType.CONTENT_TEXT */) {
  79. // handle the case where the mouse is directly over ghost text
  80. const mightBeForeignElement = target.detail.mightBeForeignElement;
  81. if (mightBeForeignElement && controller.shouldShowHoverAt(target.range)) {
  82. return new HoverForeignElementAnchor(1000, this, target.range);
  83. }
  84. }
  85. return null;
  86. }
  87. computeSync(anchor, lineDecorations) {
  88. const controller = GhostTextController.get(this._editor);
  89. if (controller && controller.shouldShowHoverAt(anchor.range)) {
  90. return [new InlineCompletionsHover(this, anchor.range, controller)];
  91. }
  92. return [];
  93. }
  94. renderHoverParts(context, hoverParts) {
  95. const disposableStore = new DisposableStore();
  96. const part = hoverParts[0];
  97. if (this.accessibilityService.isScreenReaderOptimized()) {
  98. this.renderScreenReaderText(context, part, disposableStore);
  99. }
  100. // TODO@hediet: deprecate MenuId.InlineCompletionsActions
  101. const menu = disposableStore.add(this._menuService.createMenu(MenuId.InlineCompletionsActions, this._contextKeyService));
  102. const previousAction = context.statusBar.addAction({
  103. label: nls.localize('showNextInlineSuggestion', "Next"),
  104. commandId: ShowNextInlineSuggestionAction.ID,
  105. run: () => this._commandService.executeCommand(ShowNextInlineSuggestionAction.ID)
  106. });
  107. const nextAction = context.statusBar.addAction({
  108. label: nls.localize('showPreviousInlineSuggestion', "Previous"),
  109. commandId: ShowPreviousInlineSuggestionAction.ID,
  110. run: () => this._commandService.executeCommand(ShowPreviousInlineSuggestionAction.ID)
  111. });
  112. context.statusBar.addAction({
  113. label: nls.localize('acceptInlineSuggestion', "Accept"),
  114. commandId: inlineSuggestCommitId,
  115. run: () => this._commandService.executeCommand(inlineSuggestCommitId)
  116. });
  117. const actions = [previousAction, nextAction];
  118. for (const action of actions) {
  119. action.setEnabled(false);
  120. }
  121. part.hasMultipleSuggestions().then(hasMore => {
  122. for (const action of actions) {
  123. action.setEnabled(hasMore);
  124. }
  125. });
  126. for (const command of part.commands) {
  127. context.statusBar.addAction({
  128. label: command.title,
  129. commandId: command.id,
  130. run: () => this._commandService.executeCommand(command.id, ...(command.arguments || []))
  131. });
  132. }
  133. for (const [_, group] of menu.getActions()) {
  134. for (const action of group) {
  135. if (action instanceof MenuItemAction) {
  136. context.statusBar.addAction({
  137. label: action.label,
  138. commandId: action.item.id,
  139. run: () => this._commandService.executeCommand(action.item.id)
  140. });
  141. }
  142. }
  143. }
  144. return disposableStore;
  145. }
  146. renderScreenReaderText(context, part, disposableStore) {
  147. var _a, _b;
  148. const $ = dom.$;
  149. const markdownHoverElement = $('div.hover-row.markdown-hover');
  150. const hoverContentsElement = dom.append(markdownHoverElement, $('div.hover-contents'));
  151. const renderer = disposableStore.add(new MarkdownRenderer({ editor: this._editor }, this._languageService, this._openerService));
  152. const render = (code) => {
  153. disposableStore.add(renderer.onDidRenderAsync(() => {
  154. hoverContentsElement.className = 'hover-contents code-hover-contents';
  155. context.onContentsChanged();
  156. }));
  157. const inlineSuggestionAvailable = nls.localize('inlineSuggestionFollows', "Suggestion:");
  158. const renderedContents = disposableStore.add(renderer.render(new MarkdownString().appendText(inlineSuggestionAvailable).appendCodeblock('text', code)));
  159. hoverContentsElement.replaceChildren(renderedContents.element);
  160. };
  161. const ghostText = (_b = (_a = part.controller.activeModel) === null || _a === void 0 ? void 0 : _a.inlineCompletionsModel) === null || _b === void 0 ? void 0 : _b.ghostText;
  162. if (ghostText) {
  163. const lineText = this._editor.getModel().getLineContent(ghostText.lineNumber);
  164. render(ghostText.renderForScreenReader(lineText));
  165. }
  166. context.fragment.appendChild(markdownHoverElement);
  167. }
  168. };
  169. InlineCompletionsHoverParticipant = __decorate([
  170. __param(1, ICommandService),
  171. __param(2, IMenuService),
  172. __param(3, IContextKeyService),
  173. __param(4, ILanguageService),
  174. __param(5, IOpenerService),
  175. __param(6, IAccessibilityService)
  176. ], InlineCompletionsHoverParticipant);
  177. export { InlineCompletionsHoverParticipant };