@krassowski/jupyterlab-lsp
Version:
Language Server Protocol integration for JupyterLab
150 lines • 5.59 kB
JavaScript
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
// (Parts of the FreeTooltip code are copy-paste from Tooltip, ideally this would be PRed be merged)
import { HoverBox } from '@jupyterlab/apputils';
import { MimeModel } from '@jupyterlab/rendermime';
import { Tooltip } from '@jupyterlab/tooltip';
import { Widget } from '@lumino/widgets';
import { PositionConverter } from '../converter';
const MIN_HEIGHT = 20;
const MAX_HEIGHT = 250;
const CLASS_NAME = 'lsp-tooltip';
/**
* Tooltip which can be placed at any character, not only at the current position (derived from getCursorPosition)
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
export class FreeTooltip extends Tooltip {
constructor(options) {
super(options);
this.options = options;
this._setGeometry();
// TODO: remove once https://github.com/jupyterlab/jupyterlab/pull/11010 is merged & released
const model = new MimeModel({ data: options.bundle });
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const content = this._content;
content
.renderModel(model)
.then(() => this._setGeometry())
.catch(console.warn);
}
handleEvent(event) {
if (this.isHidden || this.isDisposed) {
return;
}
const { node } = this;
const target = event.target;
switch (event.type) {
case 'keydown': {
const keyCode = event.keyCode;
// ESC or Backspace cancel anyways
if (node.contains(target) ||
(!this.options.hideOnKeyPress && keyCode != 27 && keyCode != 8)) {
return;
}
this.dispose();
break;
}
default:
super.handleEvent(event);
break;
}
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
_setGeometry() {
// Find the start of the current token for hover box placement.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const editor = this._editor;
const cursor = this.options.position == null
? editor.getCursorPosition()
: this.options.position;
const end = editor.getOffsetAt(cursor);
const line = editor.getLine(cursor.line);
if (!line) {
return;
}
let position;
switch (this.options.alignment) {
case 'start': {
const tokens = line.substring(0, end).split(/\W+/);
const last = tokens[tokens.length - 1];
const start = last ? end - last.length : end;
position = editor.getPositionAt(start);
break;
}
case 'end': {
const tokens = line.substring(0, end).split(/\W+/);
const last = tokens[tokens.length - 1];
const start = last ? end - last.length : end;
position = editor.getPositionAt(start);
break;
}
default: {
position = cursor;
break;
}
}
if (!position) {
return;
}
const anchor = editor.getCoordinateForPosition(position);
const style = window.getComputedStyle(this.node);
const paddingLeft = parseInt(style.paddingLeft, 10) || 0;
// Calculate the geometry of the tooltip.
HoverBox.setGeometry({
anchor,
host: editor.host,
maxHeight: MAX_HEIGHT,
minHeight: MIN_HEIGHT,
node: this.node,
offset: { horizontal: -1 * paddingLeft },
privilege: this.options.privilege || 'below',
style: style
});
}
}
export class EditorTooltipManager {
constructor(rendermime_registry) {
this.rendermime_registry = rendermime_registry;
this.currentTooltip = null;
}
create(options) {
this.remove();
this.currentOptions = options;
let { markup, position, adapter } = options;
let widget = adapter.widget;
const bundle = markup.kind === 'plaintext'
? { 'text/plain': markup.value }
: { 'text/markdown': markup.value };
const tooltip = new FreeTooltip(Object.assign(Object.assign({}, (options.tooltip || {})), { anchor: widget.content, bundle: bundle, editor: options.ce_editor, rendermime: this.rendermime_registry, position: PositionConverter.cm_to_ce(position) }));
tooltip.addClass(CLASS_NAME);
if (options.className) {
tooltip.addClass(options.className);
}
Widget.attach(tooltip, document.body);
this.currentTooltip = tooltip;
return tooltip;
}
get position() {
return this.currentOptions.position;
}
isShown(id) {
var _a;
if (id && this.currentOptions && ((_a = this.currentOptions) === null || _a === void 0 ? void 0 : _a.id) !== id) {
return false;
}
return (this.currentTooltip !== null &&
!this.currentTooltip.isDisposed &&
this.currentTooltip.isVisible);
}
remove() {
if (this.currentTooltip !== null) {
this.currentTooltip.dispose();
this.currentTooltip = null;
}
}
}
//# sourceMappingURL=free_tooltip.js.map