UNPKG

@jupyterlab/lsp

Version:
545 lines (544 loc) 18.7 kB
import { IDisposable } from '@lumino/disposable'; import { IDocumentInfo } from '../ws-connection/types'; import { IPosition } from '../positioning'; import { CodeEditor } from '@jupyterlab/codeeditor'; import { ISignal } from '@lumino/signaling'; import { Document, ILSPCodeExtractorsManager } from '../tokens'; import { LanguageIdentifier } from '../lsp'; import { IEditorPosition, IRootPosition, ISourcePosition, IVirtualPosition } from '../positioning'; import { DefaultMap } from '../utils'; type IRange = CodeEditor.IRange; type language = string; interface IVirtualLine { /** * Inspections for which document should be skipped for this virtual line? */ skipInspect: Array<VirtualDocument.idPath>; /** * Where does the virtual line belongs to in the source document? */ sourceLine: number | null; /** * The editor holding this virtual line */ editor: Document.IEditor; } export type ForeignDocumentsMap = Map<IRange, Document.IVirtualDocumentBlock>; interface ISourceLine { /** * Line corresponding to the block in the entire foreign document */ virtualLine: number; /** * The CM editor associated with this virtual line. */ editor: Document.IEditor; /** * Line in the CM editor corresponding to the virtual line. */ editorLine: number; /** * Shift of the virtual line */ editorShift: CodeEditor.IPosition; /** * Everything which is not in the range of foreign documents belongs to the host. */ foreignDocumentsMap: ForeignDocumentsMap; } /** * Check if given position is within range. * Both start and end are inclusive. * @param position * @param range */ export declare function isWithinRange(position: CodeEditor.IPosition, range: CodeEditor.IRange): boolean; /** * A virtual implementation of IDocumentInfo */ export declare class VirtualDocumentInfo implements IDocumentInfo { /** * Creates an instance of VirtualDocumentInfo. * @param document - the virtual document need to * be wrapped. */ constructor(document: VirtualDocument); /** * Current version of the virtual document. */ version: number; /** * Get the text content of the virtual document. */ get text(): string; /** * Get the uri of the virtual document, if the document is not available, * it returns an empty string, users need to check for the length of returned * value before using it. */ get uri(): string; /** * Get the language identifier of the document. */ get languageId(): string; /** * The wrapped virtual document. */ private _document; } export declare namespace VirtualDocument { interface IOptions { /** * The language identifier of the document. */ language: LanguageIdentifier; /** * The foreign code extractor manager token. */ foreignCodeExtractors: ILSPCodeExtractorsManager; /** * Path to the document. */ path: string; /** * File extension of the document. */ fileExtension: string | undefined; /** * 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. */ hasLspSupportedFile: 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 of the current virtual document. */ 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 implements IDisposable { constructor(options: VirtualDocument.IOptions); /** * Convert from code editor position into code mirror position. */ static ceToCm(position: CodeEditor.IPosition): IPosition; /** * Number of blank lines appended to the virtual document between * each cell. */ blankLinesBetweenCells: number; /** * Line number of the last line in the real document. */ lastSourceLine: number; /** * Line number of the last line in the virtual document. */ lastVirtualLine: number; /** * the remote document uri, version and other server-related info */ documentInfo: IDocumentInfo; /** * Parent of the current virtual document. */ parent?: VirtualDocument | null; /** * The language identifier of the document. */ readonly language: string; /** * 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) */ readonly standalone: boolean; /** * Path to the document. */ readonly path: string; /** * File extension of the document. */ readonly fileExtension: string | undefined; /** * 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. */ readonly hasLspSupportedFile: boolean; /** * Map holding the children `VirtualDocument` . */ readonly foreignDocuments: Map<VirtualDocument.virtualId, VirtualDocument>; /** * The update manager object. */ readonly updateManager: UpdateManager; /** * Unique id of the virtual document. */ readonly instanceId: number; /** * Test whether the document is disposed. */ get isDisposed(): boolean; /** * Signal emitted when the foreign document is closed */ get foreignDocumentClosed(): ISignal<VirtualDocument, Document.IForeignContext>; /** * Signal emitted when the foreign document is opened */ get foreignDocumentOpened(): ISignal<VirtualDocument, Document.IForeignContext>; /** * Signal emitted when the foreign document is changed */ get changed(): ISignal<VirtualDocument, VirtualDocument>; /** * Id of the virtual document. */ get virtualId(): VirtualDocument.virtualId; /** * Return the ancestry to this document. */ get ancestry(): Array<VirtualDocument>; /** * Return the id path to the virtual document. */ get idPath(): VirtualDocument.idPath; /** * Get the uri of the virtual document. */ get uri(): VirtualDocument.uri; /** * Get the text value of the document */ get value(): string; /** * Get the last line in the virtual document */ get lastLine(): string; /** * Get the root document of current virtual document. */ get root(): VirtualDocument; /** * Dispose the virtual document. */ dispose(): void; /** * Clear the virtual document and all related stuffs */ clear(): void; /** * Get the virtual document from the cursor position of the source * document * @param position - position in source document */ documentAtSourcePosition(position: ISourcePosition): VirtualDocument; /** * Detect if the input source position is belong to the current * virtual document. * * @param sourcePosition - position in the source document */ isWithinForeign(sourcePosition: ISourcePosition): boolean; /** * Compute the position in root document from the position of * a child editor. * * @param editor - the active editor. * @param position - position in the active editor. */ transformFromEditorToRoot(editor: Document.IEditor, position: IEditorPosition): IRootPosition | null; /** * Compute the position in the virtual document from the position * if the source document. * * @param sourcePosition - position in source document */ virtualPositionAtDocument(sourcePosition: ISourcePosition): IVirtualPosition; /** * Append a code block to the end of the virtual document. * * @param block - block to be appended * @param editorShift - position shift in source * document * @param [virtualShift] - position shift in * virtual document. */ appendCodeBlock(block: Document.ICodeBlockOptions, editorShift?: CodeEditor.IPosition, virtualShift?: CodeEditor.IPosition): void; /** * Extract a code block into list of string in supported language and * a map of foreign document if any. * @param block - block to be appended * @param editorShift - position shift in source document */ prepareCodeBlock(block: Document.ICodeBlockOptions, editorShift?: CodeEditor.IPosition): { lines: string[]; foreignDocumentsMap: Map<CodeEditor.IRange, Document.IVirtualDocumentBlock>; }; /** * Extract the foreign code from input block by using the registered * extractors. * @param block - block to be appended * @param editorShift - position shift in source document */ extractForeignCode(block: Document.ICodeBlockOptions, editorShift: CodeEditor.IPosition): { cellCodeKept: string; foreignDocumentsMap: Map<CodeEditor.IRange, Document.IVirtualDocumentBlock>; }; /** * Close a foreign document and disconnect all associated signals */ closeForeign(document: VirtualDocument): void; /** * Close all foreign documents. */ closeAllForeignDocuments(): void; /** * Close all expired documents. */ closeExpiredDocuments(): void; /** * Transform the position of the source to the editor * position. * * @param pos - position in the source document * @return position in the editor. */ transformSourceToEditor(pos: ISourcePosition): IEditorPosition; /** * Transform the position in the virtual document to the * editor position. * 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. */ transformVirtualToEditor(virtualPosition: IVirtualPosition): IEditorPosition | null; /** * Transform the position in the virtual document to the source. * Can be null because some lines are added as padding/anchors * to the virtual document and those do not exist in the source document. */ transformVirtualToSource(position: IVirtualPosition): ISourcePosition | null; /** * Compute the position in root document from the position of * a virtual document. */ transformVirtualToRoot(position: IVirtualPosition): IRootPosition | null; /** * Get the corresponding editor of the virtual line. */ getEditorAtVirtualLine(pos: IVirtualPosition): Document.IEditor; /** * Get the corresponding editor of the source line */ getEditorAtSourceLine(pos: ISourcePosition): Document.IEditor; /** * Recursively emits changed signal from the document or any descendant foreign document. */ maybeEmitChanged(): 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 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 remainingLifetime(): number; protected set remainingLifetime(value: number); /** * Virtual lines keep all the lines present in the document AND extracted to the foreign document. */ protected virtualLines: Map<number, IVirtualLine>; protected sourceLines: Map<number, ISourceLine>; protected lineBlocks: Array<string>; protected unusedStandaloneDocuments: DefaultMap<language, Array<VirtualDocument>>; private _isDisposed; private _remainingLifetime; private _editorToSourceLine; private _editorToSourceLineNew; private _foreignCodeExtractors; private previousValue; private static instancesCount; private readonly options; /** * Get the foreign document that can be opened with the input extractor. */ private _chooseForeignDocument; /** * Create a foreign document from input language and file extension. * * @param language - the required language * @param standalone - the document type is supported natively by LSP? * @param fileExtension - File extension. */ private openForeign; /** * Forward the closed signal from the foreign document to the host document's * signal */ private forwardClosedSignal; /** * Forward the opened signal from the foreign document to the host document's * signal */ private forwardOpenedSignal; /** * Slot of the `updateBegan` signal. */ private _updateBeganSlot; /** * Slot of the `blockAdded` signal. */ private _blockAddedSlot; /** * Slot of the `updateFinished` signal. */ private _updateFinishedSlot; private _foreignDocumentClosed; private _foreignDocumentOpened; private _changed; } 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 idPath = string; /** * Instance identifier for standalone documents (snippets), or language identifier * for documents which should be interpreted as one when stretched across cells. */ type virtualId = string; /** * Identifier composed of the file path and id_path. */ type uri = string; } /** * Create foreign documents if available from input virtual documents. * @param virtualDocument - the virtual document to be collected * @return - Set of generated foreign documents */ export declare function collectDocuments(virtualDocument: VirtualDocument): Set<VirtualDocument>; export interface IBlockAddedInfo { /** * The virtual document. */ virtualDocument: VirtualDocument; /** * Option of the code block. */ block: Document.ICodeBlockOptions; } export declare class UpdateManager implements IDisposable { private virtualDocument; constructor(virtualDocument: VirtualDocument); /** * Promise resolved when the updating process finishes. */ get updateDone(): Promise<void>; /** * Test whether the document is disposed. */ get isDisposed(): boolean; /** * Signal emitted when a code block is added to the document. */ get blockAdded(): ISignal<UpdateManager, IBlockAddedInfo>; /** * Signal emitted by the editor that triggered the update, * providing the root document of the updated documents. */ get documentUpdated(): ISignal<UpdateManager, VirtualDocument>; /** * Signal emitted when the update is started */ get updateBegan(): ISignal<UpdateManager, Document.ICodeBlockOptions[]>; /** * Signal emitted when the update is finished */ get updateFinished(): ISignal<UpdateManager, Document.ICodeBlockOptions[]>; /** * Dispose the class */ dispose(): void; /** * 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 */ withUpdateLock(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. */ updateDocuments(blocks: Document.ICodeBlockOptions[]): Promise<void>; private _isDisposed; /** * Promise resolved when the updating process finishes. */ private _updateDone; /** * Virtual documents update guard. */ private _isUpdateInProgress; /** * Update lock to prevent multiple updates are applied at the same time. */ private _updateLock; private _blockAdded; private _documentUpdated; private _updateBegan; private _updateFinished; /** * Once all the foreign documents were refreshed, the unused documents (and their connections) * should be terminated if their lifetime has expired. */ private _onUpdated; /** * Check if the document can be updated. */ private _canUpdate; } export {};