/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 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; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; import * as dom from '../../../../base/browser/dom.js'; import { isNonEmptyArray } from '../../../../base/common/arrays.js'; import { createCancelablePromise, disposableTimeout } from '../../../../base/common/async.js'; import { onUnexpectedError } from '../../../../base/common/errors.js'; import { Disposable, DisposableStore, toDisposable } from '../../../../base/common/lifecycle.js'; import { basename } from '../../../../base/common/resources.js'; import { Range } from '../../../common/core/range.js'; import { IMarkerDecorationsService } from '../../../common/services/markerDecorations.js'; import { getCodeActions } from '../../codeAction/browser/codeAction.js'; import { QuickFixAction, QuickFixController } from '../../codeAction/browser/codeActionCommands.js'; import { CodeActionKind, CodeActionTriggerSource } from '../../codeAction/browser/types.js'; import { MarkerController, NextMarkerAction } from '../../gotoError/browser/gotoError.js'; import * as nls from '../../../../nls.js'; import { IMarkerData, MarkerSeverity } from '../../../../platform/markers/common/markers.js'; import { IOpenerService } from '../../../../platform/opener/common/opener.js'; import { Progress } from '../../../../platform/progress/common/progress.js'; import { textLinkActiveForeground, textLinkForeground } from '../../../../platform/theme/common/colorRegistry.js'; import { registerThemingParticipant } from '../../../../platform/theme/common/themeService.js'; import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js'; const $ = dom.$; export class MarkerHover { constructor(owner, range, marker) { this.owner = owner; this.range = range; this.marker = marker; } isValidForHoverAnchor(anchor) { return (anchor.type === 1 /* HoverAnchorType.Range */ && this.range.startColumn <= anchor.range.startColumn && this.range.endColumn >= anchor.range.endColumn); } } const markerCodeActionTrigger = { type: 1 /* CodeActionTriggerType.Invoke */, filter: { include: CodeActionKind.QuickFix }, triggerAction: CodeActionTriggerSource.QuickFixHover }; let MarkerHoverParticipant = class MarkerHoverParticipant { constructor(_editor, _markerDecorationsService, _openerService, _languageFeaturesService) { this._editor = _editor; this._markerDecorationsService = _markerDecorationsService; this._openerService = _openerService; this._languageFeaturesService = _languageFeaturesService; this.hoverOrdinal = 5; this.recentMarkerCodeActionsInfo = undefined; } computeSync(anchor, lineDecorations) { if (!this._editor.hasModel() || anchor.type !== 1 /* HoverAnchorType.Range */) { return []; } const model = this._editor.getModel(); const lineNumber = anchor.range.startLineNumber; const maxColumn = model.getLineMaxColumn(lineNumber); const result = []; for (const d of lineDecorations) { const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1; const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn; const marker = this._markerDecorationsService.getMarker(model.uri, d); if (!marker) { continue; } const range = new Range(anchor.range.startLineNumber, startColumn, anchor.range.startLineNumber, endColumn); result.push(new MarkerHover(this, range, marker)); } return result; } renderHoverParts(context, hoverParts) { if (!hoverParts.length) { return Disposable.None; } const disposables = new DisposableStore(); hoverParts.forEach(msg => context.fragment.appendChild(this.renderMarkerHover(msg, disposables))); const markerHoverForStatusbar = hoverParts.length === 1 ? hoverParts[0] : hoverParts.sort((a, b) => MarkerSeverity.compare(a.marker.severity, b.marker.severity))[0]; this.renderMarkerStatusbar(context, markerHoverForStatusbar, disposables); return disposables; } renderMarkerHover(markerHover, disposables) { const hoverElement = $('div.hover-row'); const markerElement = dom.append(hoverElement, $('div.marker.hover-contents')); const { source, message, code, relatedInformation } = markerHover.marker; this._editor.applyFontInfo(markerElement); const messageElement = dom.append(markerElement, $('span')); messageElement.style.whiteSpace = 'pre-wrap'; messageElement.innerText = message; if (source || code) { // Code has link if (code && typeof code !== 'string') { const sourceAndCodeElement = $('span'); if (source) { const sourceElement = dom.append(sourceAndCodeElement, $('span')); sourceElement.innerText = source; } const codeLink = dom.append(sourceAndCodeElement, $('a.code-link')); codeLink.setAttribute('href', code.target.toString()); disposables.add(dom.addDisposableListener(codeLink, 'click', (e) => { this._openerService.open(code.target, { allowCommands: true }); e.preventDefault(); e.stopPropagation(); })); const codeElement = dom.append(codeLink, $('span')); codeElement.innerText = code.value; const detailsElement = dom.append(markerElement, sourceAndCodeElement); detailsElement.style.opacity = '0.6'; detailsElement.style.paddingLeft = '6px'; } else { const detailsElement = dom.append(markerElement, $('span')); detailsElement.style.opacity = '0.6'; detailsElement.style.paddingLeft = '6px'; detailsElement.innerText = source && code ? `${source}(${code})` : source ? source : `(${code})`; } } if (isNonEmptyArray(relatedInformation)) { for (const { message, resource, startLineNumber, startColumn } of relatedInformation) { const relatedInfoContainer = dom.append(markerElement, $('div')); relatedInfoContainer.style.marginTop = '8px'; const a = dom.append(relatedInfoContainer, $('a')); a.innerText = `${basename(resource)}(${startLineNumber}, ${startColumn}): `; a.style.cursor = 'pointer'; disposables.add(dom.addDisposableListener(a, 'click', (e) => { e.stopPropagation(); e.preventDefault(); if (this._openerService) { this._openerService.open(resource, { fromUserGesture: true, editorOptions: { selection: { startLineNumber, startColumn } } }).catch(onUnexpectedError); } })); const messageElement = dom.append(relatedInfoContainer, $('span')); messageElement.innerText = message; this._editor.applyFontInfo(messageElement); } } return hoverElement; } renderMarkerStatusbar(context, markerHover, disposables) { if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) { context.statusBar.addAction({ label: nls.localize('view problem', "View Problem"), commandId: NextMarkerAction.ID, run: () => { var _a; context.hide(); (_a = MarkerController.get(this._editor)) === null || _a === void 0 ? void 0 : _a.showAtMarker(markerHover.marker); this._editor.focus(); } }); } if (!this._editor.getOption(83 /* EditorOption.readOnly */)) { const quickfixPlaceholderElement = context.statusBar.append($('div')); if (this.recentMarkerCodeActionsInfo) { if (IMarkerData.makeKey(this.recentMarkerCodeActionsInfo.marker) === IMarkerData.makeKey(markerHover.marker)) { if (!this.recentMarkerCodeActionsInfo.hasCodeActions) { quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available"); } } else { this.recentMarkerCodeActionsInfo = undefined; } } const updatePlaceholderDisposable = this.recentMarkerCodeActionsInfo && !this.recentMarkerCodeActionsInfo.hasCodeActions ? Disposable.None : disposables.add(disposableTimeout(() => quickfixPlaceholderElement.textContent = nls.localize('checkingForQuickFixes', "Checking for quick fixes..."), 200)); if (!quickfixPlaceholderElement.textContent) { // Have some content in here to avoid flickering quickfixPlaceholderElement.textContent = String.fromCharCode(0xA0); //   } const codeActionsPromise = this.getCodeActions(markerHover.marker); disposables.add(toDisposable(() => codeActionsPromise.cancel())); codeActionsPromise.then(actions => { updatePlaceholderDisposable.dispose(); this.recentMarkerCodeActionsInfo = { marker: markerHover.marker, hasCodeActions: actions.validActions.length > 0 }; if (!this.recentMarkerCodeActionsInfo.hasCodeActions) { actions.dispose(); quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available"); return; } quickfixPlaceholderElement.style.display = 'none'; let showing = false; disposables.add(toDisposable(() => { if (!showing) { actions.dispose(); } })); context.statusBar.addAction({ label: nls.localize('quick fixes', "Quick Fix..."), commandId: QuickFixAction.Id, run: (target) => { showing = true; const controller = QuickFixController.get(this._editor); const elementPosition = dom.getDomNodePagePosition(target); // Hide the hover pre-emptively, otherwise the editor can close the code actions // context menu as well when using keyboard navigation context.hide(); controller === null || controller === void 0 ? void 0 : controller.showCodeActions(markerCodeActionTrigger, actions, { x: elementPosition.left + 6, y: elementPosition.top + elementPosition.height + 6, width: elementPosition.width, height: elementPosition.height }); } }); }, onUnexpectedError); } } getCodeActions(marker) { return createCancelablePromise(cancellationToken => { return getCodeActions(this._languageFeaturesService.codeActionProvider, this._editor.getModel(), new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn), markerCodeActionTrigger, Progress.None, cancellationToken); }); } }; MarkerHoverParticipant = __decorate([ __param(1, IMarkerDecorationsService), __param(2, IOpenerService), __param(3, ILanguageFeaturesService) ], MarkerHoverParticipant); export { MarkerHoverParticipant }; registerThemingParticipant((theme, collector) => { const linkFg = theme.getColor(textLinkForeground); if (linkFg) { collector.addRule(`.monaco-hover .hover-contents a.code-link span { color: ${linkFg}; }`); } const activeLinkFg = theme.getColor(textLinkActiveForeground); if (activeLinkFg) { collector.addRule(`.monaco-hover .hover-contents a.code-link span:hover { color: ${activeLinkFg}; }`); } });