@krassowski/jupyterlab-lsp
Version:
Language Server Protocol integration for JupyterLab
144 lines (120 loc) • 4.51 kB
text/typescript
import { CodeEditor } from '@jupyterlab/codeeditor';
import { CodeMirrorEditor } from '@jupyterlab/codemirror';
import { IDocumentWidget } from '@jupyterlab/docregistry';
import { FileEditor } from '@jupyterlab/fileeditor';
import { ICommandContext } from '../../command_manager';
import { PositionConverter } from '../../converter';
import { LSPExtension } from '../../index';
import { IRootPosition, IVirtualPosition } from '../../positioning';
import { VirtualDocument } from '../../virtual/document';
import { IVirtualEditor } from '../../virtual/editor';
import { WidgetAdapter } from '../adapter';
import IEditor = CodeEditor.IEditor;
export class FileEditorAdapter extends WidgetAdapter<
IDocumentWidget<FileEditor>
> {
editor: FileEditor;
virtual_editor: IVirtualEditor<IEditor>;
get document_path() {
return this.widget.context.path;
}
get mime_type() {
const codeMirrorMimeType = this.editor.model.mimeType;
const contentsModel = this.editor.context.contentsModel;
// when MIME type is not known it defaults to 'text/plain',
// so if it is different we can accept it as it is
if (codeMirrorMimeType != 'text/plain') {
return codeMirrorMimeType;
} else if (contentsModel) {
// a script that does not have a MIME type known by the editor
// (no syntax highlight mode), can still be known by the document
// registry (and this is arguably easier to extend), so let's check it
// just in case; this is also how the "Klingon" language for testing
// gets registered, so we need it for tests too.
let fileType =
this.extension.app.docRegistry.getFileTypeForModel(contentsModel);
return fileType.mimeTypes[0];
} else {
// "text/plain" this is
return codeMirrorMimeType;
}
}
get language_file_extension(): string {
let parts = this.document_path.split('.');
return parts[parts.length - 1];
}
get ce_editor(): CodeMirrorEditor {
return this.editor.editor as CodeMirrorEditor;
}
get activeEditor(): CodeEditor.IEditor {
return this.editor.editor;
}
constructor(
extension: LSPExtension,
editor_widget: IDocumentWidget<FileEditor>
) {
super(extension, editor_widget);
this.editor = editor_widget.content;
this.initialized = new Promise<void>((resolve, reject) => {
this.init_once_ready().then(resolve).catch(reject);
});
}
protected async init_once_ready() {
if (!this.editor.context.isReady) {
await this.editor.context.ready;
}
this.init_virtual();
this.console.log('file ready for connection:', this.path);
// connect the document, but do not open it as the adapter will handle this
// after registering all features
this.connect_document(this.virtual_editor.virtual_document, false).catch(
this.console.warn
);
this.editor.model.mimeTypeChanged.connect(this.reload_connection, this);
}
get_editor_index(ce_editor: CodeEditor.IEditor): number {
return 0;
}
get_editor_wrapper(ce_editor: CodeEditor.IEditor): HTMLElement {
return this.wrapper_element;
}
get wrapper_element(): HTMLElement {
return this.widget.node;
}
get path() {
return this.widget.context.path;
}
context_from_active_document(): ICommandContext | null {
// short circuit if disposed
if (!this.virtual_editor || !this.get_context) {
return null;
}
let editor = this.widget.content.editor;
let ce_cursor = editor.getCursorPosition();
let root_position = PositionConverter.ce_to_cm(ce_cursor) as IRootPosition;
return this.get_context(root_position);
}
get_editor_index_at(position: IVirtualPosition): number {
return 0;
}
get editors(): CodeEditor.IEditor[] {
return [this.editor.editor];
}
create_virtual_document(): VirtualDocument {
// TODO: for now the magics and extractors are not used in FileEditor,
// although it would make sense to pass extractors (e.g. for CSS in HTML,
// or SQL in Python files) in the future. However, these would need to be
// a different registry (as we would not want to extract kernel-specific
// constructs like magics)
return new VirtualDocument({
language: this.language,
file_extension: this.language_file_extension,
path: this.document_path,
overrides_registry: {},
foreign_code_extractors: {},
standalone: true,
has_lsp_supported_file: true,
console: this.console
});
}
}