ddcdcaba48de11f09f91b328bfdafe8d8139e359d63aed22b6f3dd45d2e601ec61e5dfc5622a8f66d0dc0424e59b83a30c5cac63218a698143873048a9dbcc 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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 { asArray } from '../../../../base/common/arrays.js';
  16. import { AsyncIterableObject } from '../../../../base/common/async.js';
  17. import { isEmptyMarkdownString, MarkdownString } from '../../../../base/common/htmlContent.js';
  18. import { DisposableStore } from '../../../../base/common/lifecycle.js';
  19. import { MarkdownRenderer } from '../../markdownRenderer/browser/markdownRenderer.js';
  20. import { Position } from '../../../common/core/position.js';
  21. import { Range } from '../../../common/core/range.js';
  22. import { ILanguageService } from '../../../common/languages/language.js';
  23. import { getHover } from './getHover.js';
  24. import * as nls from '../../../../nls.js';
  25. import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
  26. import { IOpenerService } from '../../../../platform/opener/common/opener.js';
  27. import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
  28. const $ = dom.$;
  29. export class MarkdownHover {
  30. constructor(owner, range, contents, ordinal) {
  31. this.owner = owner;
  32. this.range = range;
  33. this.contents = contents;
  34. this.ordinal = ordinal;
  35. }
  36. isValidForHoverAnchor(anchor) {
  37. return (anchor.type === 1 /* HoverAnchorType.Range */
  38. && this.range.startColumn <= anchor.range.startColumn
  39. && this.range.endColumn >= anchor.range.endColumn);
  40. }
  41. }
  42. let MarkdownHoverParticipant = class MarkdownHoverParticipant {
  43. constructor(_editor, _languageService, _openerService, _configurationService, _languageFeaturesService) {
  44. this._editor = _editor;
  45. this._languageService = _languageService;
  46. this._openerService = _openerService;
  47. this._configurationService = _configurationService;
  48. this._languageFeaturesService = _languageFeaturesService;
  49. this.hoverOrdinal = 2;
  50. }
  51. createLoadingMessage(anchor) {
  52. return new MarkdownHover(this, anchor.range, [new MarkdownString().appendText(nls.localize('modesContentHover.loading', "Loading..."))], 2000);
  53. }
  54. computeSync(anchor, lineDecorations) {
  55. if (!this._editor.hasModel() || anchor.type !== 1 /* HoverAnchorType.Range */) {
  56. return [];
  57. }
  58. const model = this._editor.getModel();
  59. const lineNumber = anchor.range.startLineNumber;
  60. const maxColumn = model.getLineMaxColumn(lineNumber);
  61. const result = [];
  62. let index = 1000;
  63. const lineLength = model.getLineLength(lineNumber);
  64. const languageId = model.getLanguageIdAtPosition(anchor.range.startLineNumber, anchor.range.startColumn);
  65. const maxTokenizationLineLength = this._configurationService.getValue('editor.maxTokenizationLineLength', {
  66. overrideIdentifier: languageId
  67. });
  68. if (typeof maxTokenizationLineLength === 'number' && lineLength >= maxTokenizationLineLength) {
  69. result.push(new MarkdownHover(this, anchor.range, [{
  70. value: nls.localize('too many characters', "Tokenization is skipped for long lines for performance reasons. This can be configured via `editor.maxTokenizationLineLength`.")
  71. }], index++));
  72. }
  73. for (const d of lineDecorations) {
  74. const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
  75. const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
  76. const hoverMessage = d.options.hoverMessage;
  77. if (!hoverMessage || isEmptyMarkdownString(hoverMessage)) {
  78. continue;
  79. }
  80. const range = new Range(anchor.range.startLineNumber, startColumn, anchor.range.startLineNumber, endColumn);
  81. result.push(new MarkdownHover(this, range, asArray(hoverMessage), index++));
  82. }
  83. return result;
  84. }
  85. computeAsync(anchor, lineDecorations, token) {
  86. if (!this._editor.hasModel() || anchor.type !== 1 /* HoverAnchorType.Range */) {
  87. return AsyncIterableObject.EMPTY;
  88. }
  89. const model = this._editor.getModel();
  90. if (!this._languageFeaturesService.hoverProvider.has(model)) {
  91. return AsyncIterableObject.EMPTY;
  92. }
  93. const position = new Position(anchor.range.startLineNumber, anchor.range.startColumn);
  94. return getHover(this._languageFeaturesService.hoverProvider, model, position, token)
  95. .filter(item => !isEmptyMarkdownString(item.hover.contents))
  96. .map(item => {
  97. const rng = item.hover.range ? Range.lift(item.hover.range) : anchor.range;
  98. return new MarkdownHover(this, rng, item.hover.contents, item.ordinal);
  99. });
  100. }
  101. renderHoverParts(context, hoverParts) {
  102. return renderMarkdownHovers(context, hoverParts, this._editor, this._languageService, this._openerService);
  103. }
  104. };
  105. MarkdownHoverParticipant = __decorate([
  106. __param(1, ILanguageService),
  107. __param(2, IOpenerService),
  108. __param(3, IConfigurationService),
  109. __param(4, ILanguageFeaturesService)
  110. ], MarkdownHoverParticipant);
  111. export { MarkdownHoverParticipant };
  112. export function renderMarkdownHovers(context, hoverParts, editor, languageService, openerService) {
  113. // Sort hover parts to keep them stable since they might come in async, out-of-order
  114. hoverParts.sort((a, b) => a.ordinal - b.ordinal);
  115. const disposables = new DisposableStore();
  116. for (const hoverPart of hoverParts) {
  117. for (const contents of hoverPart.contents) {
  118. if (isEmptyMarkdownString(contents)) {
  119. continue;
  120. }
  121. const markdownHoverElement = $('div.hover-row.markdown-hover');
  122. const hoverContentsElement = dom.append(markdownHoverElement, $('div.hover-contents'));
  123. const renderer = disposables.add(new MarkdownRenderer({ editor }, languageService, openerService));
  124. disposables.add(renderer.onDidRenderAsync(() => {
  125. hoverContentsElement.className = 'hover-contents code-hover-contents';
  126. context.onContentsChanged();
  127. }));
  128. const renderedContents = disposables.add(renderer.render(contents));
  129. hoverContentsElement.appendChild(renderedContents.element);
  130. context.fragment.appendChild(markdownHoverElement);
  131. }
  132. }
  133. return disposables;
  134. }