UNPKG

@krassowski/jupyterlab-lsp

Version:

Language Server Protocol integration for JupyterLab

287 lines 9.74 kB
import { CodeMirrorEditor, CodeMirrorEditorFactory, CodeMirrorMimeTypeService } from '@jupyterlab/codemirror'; import { Context, TextModelFactory } from '@jupyterlab/docregistry'; import { FileEditorFactory } from '@jupyterlab/fileeditor'; import { NotebookModel, NotebookModelFactory } from '@jupyterlab/notebook'; import { ServiceManager } from '@jupyterlab/services'; import { Mock, NBTestUtils } from '@jupyterlab/testutils'; import { Signal } from '@lumino/signaling'; import { FileEditorAdapter } from '../adapters/file_editor/file_editor'; import { NotebookAdapter } from '../adapters/notebook/notebook'; import { LSPConnection } from '../connection'; import { DocumentConnectionManager } from '../connection_manager'; import { FeatureManager } from '../index'; import { LanguageServerManager } from '../manager'; import { CodeMirrorVirtualEditor } from '../virtual/codemirror_editor'; import { BrowserConsole } from '../virtual/console'; import { VirtualDocument } from '../virtual/document'; import { VirtualEditorManager } from '../virtual/editor'; var createNotebookPanel = NBTestUtils.createNotebookPanel; const DEFAULT_SERVER_ID = 'pylsp'; export class MockLanguageServerManager extends LanguageServerManager { async fetchSessions() { this._sessions = new Map(); this._sessions.set(DEFAULT_SERVER_ID, { spec: { languages: ['python'] } }); this._sessionsChanged.emit(void 0); } } export class MockSettings { constructor(settings) { this.settings = settings; this.changed = new Signal(this); } get composite() { return this.settings; } set(setting, value) { this.settings[setting] = value; } } export class MockExtension { constructor() { this.app = null; this.feature_manager = new FeatureManager(); this.editor_type_manager = new VirtualEditorManager(); this.language_server_manager = new MockLanguageServerManager({ console: new BrowserConsole() }); this.connection_manager = new DocumentConnectionManager({ language_server_manager: this.language_server_manager, console: new BrowserConsole() }); this.editor_type_manager.registerEditorType({ implementation: CodeMirrorVirtualEditor, name: 'CodeMirrorEditor', supports: CodeMirrorEditor }); this.foreign_code_extractors = {}; this.code_overrides = {}; this.console = new BrowserConsole(); this.user_console = null; } } export class TestEnvironment { constructor(options) { this.document_options = Object.assign(Object.assign({}, this.get_defaults()), (options || {})); this.extension = new MockExtension(); this.init(); } init() { this.widget = this.create_widget(); let adapter_type = this.get_adapter_type(); this.adapter = new adapter_type(this.extension, this.widget); this.virtual_editor = this.create_virtual_editor(); // override the virtual editor with a mock/test one this.adapter.virtual_editor = this.virtual_editor; this.adapter.initialized .then(() => { // override it again after initialization // TODO: rewrite tests to async to only override after initialization this.adapter.virtual_editor = this.virtual_editor; }) .catch(console.error); } create_virtual_editor() { return new CodeMirrorVirtualEditor({ adapter: this.adapter, virtual_document: new VirtualDocument(this.document_options) }); } dispose() { this.adapter.dispose(); } } function FeatureSupport(Base) { return class FeatureTestEnvironment extends Base { init() { this._connections = new Map(); super.init(); } get status_message() { return this.adapter.status_message; } init_integration(options) { let connection = this.create_dummy_connection(); let document = options.document ? options.document : this.virtual_editor.virtual_document; let editor_adapter = this.adapter.connect_adapter(document, connection, [ { id: options.id, name: options.id, editorIntegrationFactory: new Map([ ['CodeMirrorEditor', options.constructor] ]), settings: options.settings } ]); this.virtual_editor.virtual_document = document; document.changed.connect(async () => { await editor_adapter.updateAfterChange(); }); let feature = editor_adapter.features.get(options.id); this._connections.set(feature, connection); return feature; } dispose_feature(feature) { let connection = this._connections.get(feature); connection.close(); feature.is_registered = false; } create_dummy_connection() { return new LSPConnection({ languageId: this.document_options.language, serverUri: 'ws://localhost:8080', rootUri: 'file:///unit-test', serverIdentifier: DEFAULT_SERVER_ID, console: new BrowserConsole(), capabilities: {} }); } dispose() { super.dispose(); for (let connection of this._connections.values()) { connection.close(); } } }; } export class FileEditorTestEnvironment extends TestEnvironment { get_adapter_type() { return FileEditorAdapter; } get_defaults() { return { language: 'python', path: 'dummy.py', file_extension: 'py', has_lsp_supported_file: true, standalone: true, foreign_code_extractors: {}, overrides_registry: {}, console: new BrowserConsole() }; } get ce_editor() { return this.widget.content.editor; } create_widget() { let factory = new FileEditorFactory({ editorServices: { factoryService: new CodeMirrorEditorFactory(), mimeTypeService: new CodeMirrorMimeTypeService() }, factoryOptions: { name: 'Editor', fileTypes: ['*'] } }); const context = new Context({ manager: new Mock.ServiceManagerMock(), factory: new TextModelFactory(), path: this.document_options.path }); return factory.createNew(context); } dispose() { super.dispose(); this.ce_editor.dispose(); } } export class NotebookTestEnvironment extends TestEnvironment { get_adapter_type() { return NotebookAdapter; } get notebook() { return this.widget.content; } get_defaults() { return { language: 'python', path: 'notebook.ipynb', file_extension: 'py', overrides_registry: {}, foreign_code_extractors: {}, has_lsp_supported_file: false, standalone: true, console: new BrowserConsole() }; } create_widget() { let context = new Context({ manager: new ServiceManager({ standby: 'never' }), factory: new NotebookModelFactory({}), path: this.document_options.path }); return createNotebookPanel(context); } } export class FileEditorFeatureTestEnvironment extends FeatureSupport(FileEditorTestEnvironment) { } export class NotebookFeatureTestEnvironment extends FeatureSupport(NotebookTestEnvironment) { } export function code_cell(source, metadata = { trusted: false }) { return { cell_type: 'code', source: source, metadata: metadata, execution_count: null, outputs: [] }; } export function set_notebook_content(notebook, cells, metadata = python_notebook_metadata) { let test_notebook = { cells: cells, metadata: metadata }; notebook.model = new NotebookModel(); notebook.model.fromJSON(test_notebook); } export const python_notebook_metadata = { kernelspec: { display_name: 'Python [default]', language: 'python', name: 'python3' }, language_info: { codemirror_mode: { name: 'ipython', version: 3 }, file_extension: '.py', mimetype: 'text/x-python', name: 'python', nbconvert_exporter: 'python', pygments_lexer: 'ipython3', version: '3.5.2' }, orig_nbformat: 4.1 }; export function showAllCells(notebook) { notebook.show(); // iterate over every cell to activate the editors for (let i = 0; i < notebook.model.cells.length; i++) { notebook.activeCellIndex = i; notebook.activeCell.show(); } } export function getCellsJSON(notebook) { let cells = []; for (let i = 0; i < notebook.model.cells.length; i++) { cells.push(notebook.model.cells.get(i)); } return cells.map(cell => cell.toJSON()); } export async function synchronize_content(environment, adapter) { await environment.adapter.update_documents(); try { await adapter.updateAfterChange(); } catch (e) { console.warn(e); } } //# sourceMappingURL=testutils.js.map