UNPKG

@krassowski/jupyterlab-lsp

Version:

Language Server Protocol integration for JupyterLab

140 lines 5.9 kB
// Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. import { Completer } from '@jupyterlab/completer'; import { Signal } from '@lumino/signaling'; export class LSPCompletionRenderer extends Completer.Renderer { constructor(options) { super(); this.options = options; this.ITEM_PLACEHOLDER_CLASS = 'lsp-detail-placeholder'; this.EXTRA_INFO_CLASS = 'jp-Completer-typeExtended'; this.activeChanged = new Signal(this); this.itemShown = new Signal(this); this.elementToItem = new WeakMap(); this.wasActivated = new WeakMap(); this.visibilityObserver = new IntersectionObserver(entries => { entries.forEach(entry => { if (!entry.isIntersecting) { return; } let li = entry.target; let item = this.elementToItem.get(li); this.itemShown.emit({ item: item, element: li }); }); }, { threshold: 0.25 }); // note: there should be no need to unobserve deleted elements as per: // https://stackoverflow.com/a/51106262/6646912 this.activityObserver = new MutationObserver(mutations => { mutations.forEach(mutation => { let li = mutation.target; if (!(li instanceof HTMLLIElement)) { return; } let inactive = !this.wasActivated.get(li); if (li.classList.contains('jp-mod-active')) { if (inactive) { this.wasActivated.set(li, true); let item = this.elementToItem.get(li); this.activeChanged.emit({ item: item, element: li }); } } else { this.wasActivated.set(li, false); } }); }); } getExtraInfo(item) { var _a, _b, _c, _d, _e, _f; const labelExtra = this.options.integrator.settings.composite.labelExtra; switch (labelExtra) { case 'detail': return (item === null || item === void 0 ? void 0 : item.detail) || ''; case 'type': return (_b = (_a = item === null || item === void 0 ? void 0 : item.type) === null || _a === void 0 ? void 0 : _a.toLowerCase) === null || _b === void 0 ? void 0 : _b.call(_a); case 'source': return (_c = item === null || item === void 0 ? void 0 : item.source) === null || _c === void 0 ? void 0 : _c.name; case 'auto': return [ (item === null || item === void 0 ? void 0 : item.detail) || '', (_e = (_d = item === null || item === void 0 ? void 0 : item.type) === null || _d === void 0 ? void 0 : _d.toLowerCase) === null || _e === void 0 ? void 0 : _e.call(_d), (_f = item === null || item === void 0 ? void 0 : item.source) === null || _f === void 0 ? void 0 : _f.name ].filter(x => !!x)[0]; default: this.options.console.warn('labelExtra does not match any of the expected values', labelExtra); return ''; } } updateExtraInfo(item, li) { const extraText = this.getExtraInfo(item); if (extraText) { const extraElement = li.getElementsByClassName(this.EXTRA_INFO_CLASS)[0]; extraElement.textContent = extraText; } } createCompletionItemNode(item, orderedTypes) { const li = super.createCompletionItemNode(item, orderedTypes); // make sure that an instance reference, and not an object copy is being used; const lsp_item = item.self; // only monitor nodes that have item.self as others are not our completion items if (lsp_item) { lsp_item.element = li; this.elementToItem.set(li, lsp_item); this.activityObserver.observe(li, { attributes: true, attributeFilter: ['class'] }); this.visibilityObserver.observe(li); // TODO: build custom li from ground up this.updateExtraInfo(lsp_item, li); } else { this.updateExtraInfo(item, li); } return li; } createDocumentationNode(item) { // note: not worth trying to `fetchDocumentation()` as this is not // invoked if documentation is empty (as of jlab 3.2) if (item.isDocumentationMarkdown && this.options.markdownRenderer) { let documentation = item.documentation; this.options.markdownRenderer .renderModel({ data: { 'text/markdown': documentation }, trusted: false, metadata: {}, setData(options) { // empty } }) .then(() => { if (this.options.markdownRenderer && this.options.latexTypesetter && documentation && documentation.includes('$')) { this.options.latexTypesetter.typeset(this.options.markdownRenderer.node); } }) .catch(this.options.console.warn); return this.options.markdownRenderer.node; } else { let node = document.createElement('pre'); if (item.documentation) { node.textContent = item.documentation; } return node; } } } //# sourceMappingURL=renderer.js.map