123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- /*---------------------------------------------------------------------------------------------
- * 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 { isSafari } from '../../../base/browser/browser.js';
- import * as dom from '../../../base/browser/dom.js';
- import { DomScrollableElement } from '../../../base/browser/ui/scrollbar/scrollableElement.js';
- import { Codicon } from '../../../base/common/codicons.js';
- import { Emitter } from '../../../base/common/event.js';
- import { MarkdownString } from '../../../base/common/htmlContent.js';
- import { DisposableStore } from '../../../base/common/lifecycle.js';
- import { MarkdownRenderer } from '../../browser/core/markdownRenderer.js';
- import { EDITOR_FONT_DEFAULTS } from '../../common/config/editorOptions.js';
- import { ResizableHTMLElement } from './resizable.js';
- import * as nls from '../../../nls.js';
- import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
- export function canExpandCompletionItem(item) {
- return !!item && Boolean(item.completion.documentation || item.completion.detail && item.completion.detail !== item.completion.label);
- }
- let SuggestDetailsWidget = class SuggestDetailsWidget {
- constructor(_editor, instaService) {
- this._editor = _editor;
- this._onDidClose = new Emitter();
- this.onDidClose = this._onDidClose.event;
- this._onDidChangeContents = new Emitter();
- this.onDidChangeContents = this._onDidChangeContents.event;
- this._disposables = new DisposableStore();
- this._renderDisposeable = new DisposableStore();
- this._borderWidth = 1;
- this._size = new dom.Dimension(330, 0);
- this.domNode = dom.$('.suggest-details');
- this.domNode.classList.add('no-docs');
- this._markdownRenderer = instaService.createInstance(MarkdownRenderer, { editor: _editor });
- this._body = dom.$('.body');
- this._scrollbar = new DomScrollableElement(this._body, {});
- dom.append(this.domNode, this._scrollbar.getDomNode());
- this._disposables.add(this._scrollbar);
- this._header = dom.append(this._body, dom.$('.header'));
- this._close = dom.append(this._header, dom.$('span' + Codicon.close.cssSelector));
- this._close.title = nls.localize('details.close', "Close");
- this._type = dom.append(this._header, dom.$('p.type'));
- this._docs = dom.append(this._body, dom.$('p.docs'));
- this._configureFont();
- this._disposables.add(this._editor.onDidChangeConfiguration(e => {
- if (e.hasChanged(43 /* fontInfo */)) {
- this._configureFont();
- }
- }));
- }
- dispose() {
- this._disposables.dispose();
- this._renderDisposeable.dispose();
- }
- _configureFont() {
- const options = this._editor.getOptions();
- const fontInfo = options.get(43 /* fontInfo */);
- const fontFamily = fontInfo.getMassagedFontFamily(isSafari ? EDITOR_FONT_DEFAULTS.fontFamily : null);
- const fontSize = options.get(106 /* suggestFontSize */) || fontInfo.fontSize;
- const lineHeight = options.get(107 /* suggestLineHeight */) || fontInfo.lineHeight;
- const fontWeight = fontInfo.fontWeight;
- const fontSizePx = `${fontSize}px`;
- const lineHeightPx = `${lineHeight}px`;
- this.domNode.style.fontSize = fontSizePx;
- this.domNode.style.lineHeight = `${lineHeight / fontSize}`;
- this.domNode.style.fontWeight = fontWeight;
- this.domNode.style.fontFeatureSettings = fontInfo.fontFeatureSettings;
- this._type.style.fontFamily = fontFamily;
- this._close.style.height = lineHeightPx;
- this._close.style.width = lineHeightPx;
- }
- getLayoutInfo() {
- const lineHeight = this._editor.getOption(107 /* suggestLineHeight */) || this._editor.getOption(43 /* fontInfo */).lineHeight;
- const borderWidth = this._borderWidth;
- const borderHeight = borderWidth * 2;
- return {
- lineHeight,
- borderWidth,
- borderHeight,
- verticalPadding: 22,
- horizontalPadding: 14
- };
- }
- renderLoading() {
- this._type.textContent = nls.localize('loading', "Loading...");
- this._docs.textContent = '';
- this.domNode.classList.remove('no-docs', 'no-type');
- this.layout(this.size.width, this.getLayoutInfo().lineHeight * 2);
- this._onDidChangeContents.fire(this);
- }
- renderItem(item, explainMode) {
- var _a, _b;
- this._renderDisposeable.clear();
- let { detail, documentation } = item.completion;
- if (explainMode) {
- let md = '';
- md += `score: ${item.score[0]}\n`;
- md += `prefix: ${(_a = item.word) !== null && _a !== void 0 ? _a : '(no prefix)'}\n`;
- md += `word: ${item.completion.filterText ? item.completion.filterText + ' (filterText)' : item.textLabel}\n`;
- md += `distance: ${item.distance} (localityBonus-setting)\n`;
- md += `index: ${item.idx}, based on ${item.completion.sortText && `sortText: "${item.completion.sortText}"` || 'label'}\n`;
- md += `commit_chars: ${(_b = item.completion.commitCharacters) === null || _b === void 0 ? void 0 : _b.join('')}\n`;
- documentation = new MarkdownString().appendCodeblock('empty', md);
- detail = `Provider: ${item.provider._debugDisplayName}`;
- }
- if (!explainMode && !canExpandCompletionItem(item)) {
- this.clearContents();
- return;
- }
- this.domNode.classList.remove('no-docs', 'no-type');
- // --- details
- if (detail) {
- const cappedDetail = detail.length > 100000 ? `${detail.substr(0, 100000)}…` : detail;
- this._type.textContent = cappedDetail;
- this._type.title = cappedDetail;
- dom.show(this._type);
- this._type.classList.toggle('auto-wrap', !/\r?\n^\s+/gmi.test(cappedDetail));
- }
- else {
- dom.clearNode(this._type);
- this._type.title = '';
- dom.hide(this._type);
- this.domNode.classList.add('no-type');
- }
- // --- documentation
- dom.clearNode(this._docs);
- if (typeof documentation === 'string') {
- this._docs.classList.remove('markdown-docs');
- this._docs.textContent = documentation;
- }
- else if (documentation) {
- this._docs.classList.add('markdown-docs');
- dom.clearNode(this._docs);
- const renderedContents = this._markdownRenderer.render(documentation);
- this._docs.appendChild(renderedContents.element);
- this._renderDisposeable.add(renderedContents);
- this._renderDisposeable.add(this._markdownRenderer.onDidRenderAsync(() => {
- this.layout(this._size.width, this._type.clientHeight + this._docs.clientHeight);
- this._onDidChangeContents.fire(this);
- }));
- }
- this.domNode.style.userSelect = 'text';
- this.domNode.tabIndex = -1;
- this._close.onmousedown = e => {
- e.preventDefault();
- e.stopPropagation();
- };
- this._close.onclick = e => {
- e.preventDefault();
- e.stopPropagation();
- this._onDidClose.fire();
- };
- this._body.scrollTop = 0;
- this.layout(this._size.width, this._type.clientHeight + this._docs.clientHeight);
- this._onDidChangeContents.fire(this);
- }
- clearContents() {
- this.domNode.classList.add('no-docs');
- this._type.textContent = '';
- this._docs.textContent = '';
- }
- get size() {
- return this._size;
- }
- layout(width, height) {
- const newSize = new dom.Dimension(width, height);
- if (!dom.Dimension.equals(newSize, this._size)) {
- this._size = newSize;
- dom.size(this.domNode, width, height);
- }
- this._scrollbar.scanDomNode();
- }
- scrollDown(much = 8) {
- this._body.scrollTop += much;
- }
- scrollUp(much = 8) {
- this._body.scrollTop -= much;
- }
- scrollTop() {
- this._body.scrollTop = 0;
- }
- scrollBottom() {
- this._body.scrollTop = this._body.scrollHeight;
- }
- pageDown() {
- this.scrollDown(80);
- }
- pageUp() {
- this.scrollUp(80);
- }
- set borderWidth(width) {
- this._borderWidth = width;
- }
- get borderWidth() {
- return this._borderWidth;
- }
- };
- SuggestDetailsWidget = __decorate([
- __param(1, IInstantiationService)
- ], SuggestDetailsWidget);
- export { SuggestDetailsWidget };
- export class SuggestDetailsOverlay {
- constructor(widget, _editor) {
- this.widget = widget;
- this._editor = _editor;
- this._disposables = new DisposableStore();
- this._added = false;
- this._preferAlignAtTop = true;
- this._resizable = new ResizableHTMLElement();
- this._resizable.domNode.classList.add('suggest-details-container');
- this._resizable.domNode.appendChild(widget.domNode);
- this._resizable.enableSashes(false, true, true, false);
- let topLeftNow;
- let sizeNow;
- let deltaTop = 0;
- let deltaLeft = 0;
- this._disposables.add(this._resizable.onDidWillResize(() => {
- topLeftNow = this._topLeft;
- sizeNow = this._resizable.size;
- }));
- this._disposables.add(this._resizable.onDidResize(e => {
- if (topLeftNow && sizeNow) {
- this.widget.layout(e.dimension.width, e.dimension.height);
- let updateTopLeft = false;
- if (e.west) {
- deltaLeft = sizeNow.width - e.dimension.width;
- updateTopLeft = true;
- }
- if (e.north) {
- deltaTop = sizeNow.height - e.dimension.height;
- updateTopLeft = true;
- }
- if (updateTopLeft) {
- this._applyTopLeft({
- top: topLeftNow.top + deltaTop,
- left: topLeftNow.left + deltaLeft,
- });
- }
- }
- if (e.done) {
- topLeftNow = undefined;
- sizeNow = undefined;
- deltaTop = 0;
- deltaLeft = 0;
- this._userSize = e.dimension;
- }
- }));
- this._disposables.add(this.widget.onDidChangeContents(() => {
- var _a;
- if (this._anchorBox) {
- this._placeAtAnchor(this._anchorBox, (_a = this._userSize) !== null && _a !== void 0 ? _a : this.widget.size, this._preferAlignAtTop);
- }
- }));
- }
- dispose() {
- this._resizable.dispose();
- this._disposables.dispose();
- this.hide();
- }
- getId() {
- return 'suggest.details';
- }
- getDomNode() {
- return this._resizable.domNode;
- }
- getPosition() {
- return null;
- }
- show() {
- if (!this._added) {
- this._editor.addOverlayWidget(this);
- this.getDomNode().style.position = 'fixed';
- this._added = true;
- }
- }
- hide(sessionEnded = false) {
- this._resizable.clearSashHoverState();
- if (this._added) {
- this._editor.removeOverlayWidget(this);
- this._added = false;
- this._anchorBox = undefined;
- this._topLeft = undefined;
- }
- if (sessionEnded) {
- this._userSize = undefined;
- this.widget.clearContents();
- }
- }
- placeAtAnchor(anchor, preferAlignAtTop) {
- var _a;
- const anchorBox = anchor.getBoundingClientRect();
- this._anchorBox = anchorBox;
- this._preferAlignAtTop = preferAlignAtTop;
- this._placeAtAnchor(this._anchorBox, (_a = this._userSize) !== null && _a !== void 0 ? _a : this.widget.size, preferAlignAtTop);
- }
- _placeAtAnchor(anchorBox, size, preferAlignAtTop) {
- var _a;
- const bodyBox = dom.getClientArea(document.body);
- const info = this.widget.getLayoutInfo();
- const defaultMinSize = new dom.Dimension(220, 2 * info.lineHeight);
- const defaultTop = anchorBox.top;
- // EAST
- const eastPlacement = (function () {
- const width = bodyBox.width - (anchorBox.left + anchorBox.width + info.borderWidth + info.horizontalPadding);
- const left = -info.borderWidth + anchorBox.left + anchorBox.width;
- const maxSizeTop = new dom.Dimension(width, bodyBox.height - anchorBox.top - info.borderHeight - info.verticalPadding);
- const maxSizeBottom = maxSizeTop.with(undefined, anchorBox.top + anchorBox.height - info.borderHeight - info.verticalPadding);
- return { top: defaultTop, left, fit: width - size.width, maxSizeTop, maxSizeBottom, minSize: defaultMinSize.with(Math.min(width, defaultMinSize.width)) };
- })();
- // WEST
- const westPlacement = (function () {
- const width = anchorBox.left - info.borderWidth - info.horizontalPadding;
- const left = Math.max(info.horizontalPadding, anchorBox.left - size.width - info.borderWidth);
- const maxSizeTop = new dom.Dimension(width, bodyBox.height - anchorBox.top - info.borderHeight - info.verticalPadding);
- const maxSizeBottom = maxSizeTop.with(undefined, anchorBox.top + anchorBox.height - info.borderHeight - info.verticalPadding);
- return { top: defaultTop, left, fit: width - size.width, maxSizeTop, maxSizeBottom, minSize: defaultMinSize.with(Math.min(width, defaultMinSize.width)) };
- })();
- // SOUTH
- const southPacement = (function () {
- const left = anchorBox.left;
- const top = -info.borderWidth + anchorBox.top + anchorBox.height;
- const maxSizeBottom = new dom.Dimension(anchorBox.width - info.borderHeight, bodyBox.height - anchorBox.top - anchorBox.height - info.verticalPadding);
- return { top, left, fit: maxSizeBottom.height - size.height, maxSizeBottom, maxSizeTop: maxSizeBottom, minSize: defaultMinSize.with(maxSizeBottom.width) };
- })();
- // take first placement that fits or the first with "least bad" fit
- const placements = [eastPlacement, westPlacement, southPacement];
- const placement = (_a = placements.find(p => p.fit >= 0)) !== null && _a !== void 0 ? _a : placements.sort((a, b) => b.fit - a.fit)[0];
- // top/bottom placement
- const bottom = anchorBox.top + anchorBox.height - info.borderHeight;
- let alignAtTop;
- let height = size.height;
- const maxHeight = Math.max(placement.maxSizeTop.height, placement.maxSizeBottom.height);
- if (height > maxHeight) {
- height = maxHeight;
- }
- let maxSize;
- if (preferAlignAtTop) {
- if (height <= placement.maxSizeTop.height) {
- alignAtTop = true;
- maxSize = placement.maxSizeTop;
- }
- else {
- alignAtTop = false;
- maxSize = placement.maxSizeBottom;
- }
- }
- else {
- if (height <= placement.maxSizeBottom.height) {
- alignAtTop = false;
- maxSize = placement.maxSizeBottom;
- }
- else {
- alignAtTop = true;
- maxSize = placement.maxSizeTop;
- }
- }
- this._applyTopLeft({ left: placement.left, top: alignAtTop ? placement.top : bottom - height });
- this.getDomNode().style.position = 'fixed';
- this._resizable.enableSashes(!alignAtTop, placement === eastPlacement, alignAtTop, placement !== eastPlacement);
- this._resizable.minSize = placement.minSize;
- this._resizable.maxSize = maxSize;
- this._resizable.layout(height, Math.min(maxSize.width, size.width));
- this.widget.layout(this._resizable.size.width, this._resizable.size.height);
- }
- _applyTopLeft(topLeft) {
- this._topLeft = topLeft;
- this.getDomNode().style.left = `${this._topLeft.left}px`;
- this.getDomNode().style.top = `${this._topLeft.top}px`;
- }
- }
|