@jupyter-lsp/jupyterlab-lsp
Version:
Language Server Protocol integration for JupyterLab
185 lines • 5.86 kB
JavaScript
import { PageConfig } from '@jupyterlab/coreutils';
import mergeWith from 'lodash.mergewith';
const RE_PATH_ANCHOR = /^file:\/\/([^\/]+|\/[a-zA-Z](?::|%3A))/;
export async function sleep(timeout) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, timeout);
});
}
/**
* CodeMirror-proof implementation of event.getModifierState()
*/
export function getModifierState(event, modifierKey) {
// Note: Safari does not support getModifierState on MouseEvent, see:
// https://github.com/krassowski/jupyterlab-go-to-definition/issues/3
// thus AltGraph and others are not supported on Safari
// Full list of modifier keys and mappings to physical keys on different OSes:
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/getModifierState
// the key approach is needed for CodeMirror events which do not set
// *key (e.g. ctrlKey) correctly
const key = event.key || null;
let value = false;
switch (modifierKey) {
case 'Shift':
value = event.shiftKey || key == 'Shift';
break;
case 'Alt':
value = event.altKey || key == 'Alt';
break;
case 'AltGraph':
value = key == 'AltGraph';
break;
case 'Control':
value = event.ctrlKey || key == 'Control';
break;
case 'Meta':
value = event.metaKey || key == 'Meta';
break;
case 'Accel':
value =
event.metaKey || key == 'Meta' || event.ctrlKey || key == 'Control';
break;
}
if (event.getModifierState !== undefined) {
return value || event.getModifierState(modifierKey);
}
return value;
}
export class DefaultMap extends Map {
constructor(defaultFactory, entries) {
super(entries);
this.defaultFactory = defaultFactory;
}
get(k) {
return this.getOrCreate(k);
}
getOrCreate(k, ...args) {
if (this.has(k)) {
return super.get(k);
}
else {
let v = this.defaultFactory(k, ...args);
this.set(k, v);
return v;
}
}
}
function serverRootUri() {
return PageConfig.getOption('rootUri');
}
/**
* compare two URIs, discounting:
* - drive capitalization
* - uri encoding
* TODO: probably use vscode-uri
*/
export function urisEqual(a, b) {
const winPaths = isWinPath(a) && isWinPath(b);
if (winPaths) {
a = normalizeWinPath(a);
b = normalizeWinPath(b);
}
return a === b || decodeURI(a) === decodeURI(b);
}
/**
* grossly detect whether a URI represents a file on a windows drive
*/
export function isWinPath(uri) {
return uri.match(RE_PATH_ANCHOR);
}
/**
* lowercase the drive component of a URI
*/
export function normalizeWinPath(uri) {
// Pyright encodes colon on Windows, see:
// https://github.com/jupyter-lsp/jupyterlab-lsp/pull/587#issuecomment-844225253
return uri.replace(RE_PATH_ANCHOR, it => it.replace('%3A', ':').toLowerCase());
}
export function uriToContentsPath(child, parent) {
parent = parent || serverRootUri();
if (parent == null) {
return null;
}
const winPaths = isWinPath(parent) && isWinPath(child);
if (winPaths) {
parent = normalizeWinPath(parent);
child = normalizeWinPath(child);
}
if (child.startsWith(parent)) {
// 'decodeURIComponent' is needed over 'decodeURI' for '@' in TS/JS paths
return decodeURIComponent(child.replace(parent, ''));
}
return null;
}
/**
* The docs for many language servers show settings in the
* VSCode format, e.g.: "pyls.plugins.pyflakes.enabled"
*
* VSCode converts that dot notation to JSON behind the scenes,
* as the language servers themselves don't accept that syntax.
*/
export const expandPath = (path, value) => {
const obj = {};
let curr = obj;
path.forEach((prop, i) => {
curr[prop] = {};
if (i === path.length - 1) {
curr[prop] = value;
}
else {
curr = curr[prop];
}
});
return obj;
};
export const expandDottedPaths = (obj) => {
const settings = [];
for (let key in obj) {
const parsed = expandPath(key.split('.'), obj[key]);
settings.push(parsed);
}
return mergeWith({}, ...settings);
};
export function collapseToDotted(obj) {
const result = {};
const conflicts = {};
const collapse = (obj, root = '') => {
for (let [key, value] of Object.entries(obj)) {
const prefix = root ? root + '.' + key : key;
if (value != null &&
typeof value === 'object' &&
!Array.isArray(value) &&
Object.keys(value).length !== 0) {
collapse(value, prefix);
}
else {
if (result.hasOwnProperty(prefix) && result[prefix] !== value) {
if (!conflicts.hasOwnProperty(prefix)) {
conflicts[prefix] = [];
conflicts[prefix].push(result[prefix]);
}
if (!conflicts[prefix].includes(value)) {
conflicts[prefix].push(value);
}
}
result[prefix] = value;
}
}
};
collapse(obj);
return {
result: result,
conflicts: conflicts
};
}
export function escapeMarkdown(text) {
// note: keeping backticks for highlighting of code sections
text = text.replace(/([\\#*_[\]])/g, '\\$1');
// escape HTML
const span = document.createElement('span');
span.textContent = text;
return span.innerHTML.replace(/\n/g, '<br>').replace(/ {2}/g, '\u00A0\u00A0');
}
//# sourceMappingURL=utils.js.map