@krassowski/jupyterlab-lsp
Version:
Language Server Protocol integration for JupyterLab
277 lines (276 loc) • 11.5 kB
TypeScript
import { CodeEditor } from '@jupyterlab/codeeditor';
import { Signal } from '@lumino/signaling';
import { IDocumentInfo } from 'lsp-ws-connection';
import { IForeignCodeExtractor, IForeignCodeExtractorsRegistry } from '../extractors/types';
import { LanguageIdentifier } from '../lsp';
import { ICodeOverridesRegistry } from '../overrides/tokens';
import { IEditorPosition, ISourcePosition, IVirtualPosition } from '../positioning';
import { ILSPLogConsole } from '../tokens';
import { DefaultMap } from '../utils';
import IRange = CodeEditor.IRange;
declare type language = string;
interface IVirtualLine {
/**
* Inspections for which document should be skipped for this virtual line?
*/
skip_inspect: Array<VirtualDocument.id_path>;
/**
* Where does the virtual line belongs to in the source document?
*/
source_line: number | null;
editor: CodeEditor.IEditor;
}
export interface ICodeBlockOptions {
ce_editor: CodeEditor.IEditor;
value: string;
}
export interface IVirtualDocumentBlock {
/**
* Line corresponding to the block in the entire foreign document
*/
virtual_line: number;
virtual_document: VirtualDocument;
editor: CodeEditor.IEditor;
}
export declare type ForeignDocumentsMap = Map<IRange, IVirtualDocumentBlock>;
interface ISourceLine {
virtual_line: number;
editor: CodeEditor.IEditor;
editor_line: number;
editor_shift: CodeEditor.IPosition;
/**
* Everything which is not in the range of foreign documents belongs to the host.
*/
foreign_documents_map: ForeignDocumentsMap;
}
export interface IForeignContext {
foreign_document: VirtualDocument;
parent_host: VirtualDocument;
}
/**
* Check if given position is within range.
* Both start and end are inclusive.
* @param position
* @param range
*/
export declare function is_within_range(position: CodeEditor.IPosition, range: CodeEditor.IRange): boolean;
/**
* a virtual implementation of IDocumentInfo
*/
export declare class VirtualDocumentInfo implements IDocumentInfo {
private _document;
version: number;
constructor(document: VirtualDocument);
get text(): string;
get uri(): string;
get languageId(): string;
}
export declare namespace VirtualDocument {
interface IOptions {
language: LanguageIdentifier;
foreign_code_extractors: IForeignCodeExtractorsRegistry;
overrides_registry: ICodeOverridesRegistry;
path: string;
file_extension: string | undefined;
console: ILSPLogConsole;
/**
* Notebooks or any other aggregates of documents are not supported
* by the LSP specification, and we need to make appropriate
* adjustments for them, pretending they are simple files
* so that the LSP servers do not refuse to cooperate.
*/
has_lsp_supported_file: boolean;
/**
* Being standalone is relevant to foreign documents
* and defines whether following chunks of code in the same
* language should be appended to this document (false, not standalone)
* or should be considered separate documents (true, standalone)
*
*/
standalone?: boolean;
parent?: VirtualDocument;
}
}
/**
* A notebook can hold one or more virtual documents; there is always one,
* "root" document, corresponding to the language of the kernel. All other
* virtual documents are extracted out of the notebook, based on magics,
* or other syntax constructs, depending on the kernel language.
*
* Virtual documents represent the underlying code in a single language,
* which has been parsed excluding interactive kernel commands (magics)
* which could be misunderstood by the specific LSP server.
*
* VirtualDocument has no awareness of the notebook or editor it lives in,
* however it is able to transform its content back to the notebook space,
* as it keeps editor coordinates for each virtual line.
*
* The notebook/editor aware transformations are preferred to be placed in
* VirtualEditor descendants rather than here.
*
* No dependency on editor implementation (such as CodeMirrorEditor)
* is allowed for VirtualEditor.
*/
export declare class VirtualDocument {
language: string;
last_virtual_line: number;
foreign_document_closed: Signal<VirtualDocument, IForeignContext>;
foreign_document_opened: Signal<VirtualDocument, IForeignContext>;
readonly instance_id: number;
protected console: ILSPLogConsole;
standalone: boolean;
isDisposed: boolean;
/**
* the remote document uri, version and other server-related info
*/
document_info: IDocumentInfo;
/**
* Virtual lines keep all the lines present in the document AND extracted to the foreign document.
*/
virtual_lines: Map<number, IVirtualLine>;
protected source_lines: Map<number, ISourceLine>;
foreign_extractors: IForeignCodeExtractor[];
overrides_registry: ICodeOverridesRegistry;
protected foreign_extractors_registry: IForeignCodeExtractorsRegistry;
protected line_blocks: Array<string>;
protected unused_documents: Set<VirtualDocument>;
protected unused_standalone_documents: DefaultMap<language, Array<VirtualDocument>>;
private _remaining_lifetime;
private cell_magics_overrides;
private line_magics_overrides;
private static instances_count;
foreign_documents: Map<VirtualDocument.virtual_id, VirtualDocument>;
blank_lines_between_cells: number;
last_source_line: number;
private previous_value;
changed: Signal<VirtualDocument, VirtualDocument>;
path: string;
file_extension: string | undefined;
has_lsp_supported_file: boolean;
parent?: VirtualDocument | null;
private readonly options;
update_manager: UpdateManager;
constructor(options: VirtualDocument.IOptions);
dispose(): void;
/**
* When this counter goes down to 0, the document will be destroyed and the associated connection will be closed;
* This is meant to reduce the number of open connections when a a foreign code snippet was removed from the document.
*
* Note: top level virtual documents are currently immortal (unless killed by other means); it might be worth
* implementing culling of unused documents, but if and only if JupyterLab will also implement culling of
* idle kernels - otherwise the user experience could be a bit inconsistent, and we would need to invent our own rules.
*/
protected get remaining_lifetime(): number;
protected set remaining_lifetime(value: number);
clear(): void;
private forward_closed_signal;
private forward_opened_signal;
private open_foreign;
document_at_source_position(position: ISourcePosition): VirtualDocument;
is_within_foreign(source_position: ISourcePosition): boolean;
virtual_position_at_document(source_position: ISourcePosition): IVirtualPosition;
private choose_foreign_document;
extract_foreign_code(block: ICodeBlockOptions, editor_shift: CodeEditor.IPosition): {
cell_code_kept: string;
foreign_document_map: Map<CodeEditor.IRange, IVirtualDocumentBlock>;
};
decode_code_block(raw_code: string): string;
prepare_code_block(block: ICodeBlockOptions, editor_shift?: CodeEditor.IPosition): {
lines: string[];
foreign_document_map: Map<CodeEditor.IRange, IVirtualDocumentBlock>;
skip_inspect: string[][];
};
get foreign_document_maps(): ForeignDocumentsMap[];
append_code_block(block: ICodeBlockOptions, editor_shift?: CodeEditor.IPosition, virtual_shift?: CodeEditor.IPosition): void;
get value(): string;
get last_line(): string;
close_expired_documents(): void;
close_foreign(document: VirtualDocument): void;
close_all_foreign_documents(): void;
get virtual_id(): VirtualDocument.virtual_id;
get ancestry(): Array<VirtualDocument>;
get id_path(): VirtualDocument.id_path;
get uri(): VirtualDocument.uri;
transform_source_to_editor(pos: ISourcePosition): IEditorPosition;
/**
Can be null because some lines are added as padding/anchors
to the virtual document and those do not exist in the source document
and thus they are absent in the editor.
*/
transform_virtual_to_editor(virtual_position: IVirtualPosition): IEditorPosition | null;
/**
Can be null because some lines are added as padding/anchors
to the virtual document and those do not exist in the source document.
*/
transform_virtual_to_source(position: IVirtualPosition): ISourcePosition | null;
get root(): VirtualDocument;
get_editor_at_virtual_line(pos: IVirtualPosition): CodeEditor.IEditor;
get_editor_at_source_line(pos: ISourcePosition): CodeEditor.IEditor;
/**
* Recursively emits changed signal from the document or any descendant foreign document.
*/
maybe_emit_changed(): void;
}
export declare namespace VirtualDocument {
/**
* Identifier composed of `virtual_id`s of a nested structure of documents,
* used to aide assignment of the connection to the virtual document
* handling specific, nested language usage; it will be appended to the file name
* when creating a connection.
*/
type id_path = string;
/**
* Instance identifier for standalone documents (snippets), or language identifier
* for documents which should be interpreted as one when stretched across cells.
*/
type virtual_id = string;
/**
* Identifier composed of the file path and id_path.
*/
type uri = string;
}
export declare function collect_documents(virtual_document: VirtualDocument): Set<VirtualDocument>;
export interface IBlockAddedInfo {
virtual_document: VirtualDocument;
block: ICodeBlockOptions;
}
export declare class UpdateManager {
private virtual_document;
console: ILSPLogConsole;
/**
* Virtual documents update guard.
*/
private is_update_in_progress;
private update_lock;
protected isDisposed: boolean;
/**
* Signal emitted by the editor that triggered the update, providing the root document of the updated documents.
*/
private document_updated;
block_added: Signal<UpdateManager, IBlockAddedInfo>;
update_done: Promise<void>;
update_began: Signal<UpdateManager, ICodeBlockOptions[]>;
update_finished: Signal<UpdateManager, ICodeBlockOptions[]>;
constructor(virtual_document: VirtualDocument, console: ILSPLogConsole);
dispose(): void;
/**
* Once all the foreign documents were refreshed, the unused documents (and their connections)
* should be terminated if their lifetime has expired.
*/
private on_updated;
private can_update;
/**
* Execute provided callback within an update-locked context, which guarantees that:
* - the previous updates must have finished before the callback call, and
* - no update will happen when executing the callback
* @param fn - the callback to execute in update lock
*/
with_update_lock(fn: () => void): Promise<void>;
/**
* Update all the virtual documents, emit documents updated with root document if succeeded,
* and resolve a void promise. The promise does not contain the text value of the root document,
* as to avoid an easy trap of ignoring the changes in the virtual documents.
*/
update_documents(blocks: ICodeBlockOptions[]): Promise<void>;
}
export {};