CodeMirror 6 editor provider for JupyterLab with comprehensive language support, themes, extensions, and collaborative editing capabilities
npx @tessl/cli install tessl/npm-jupyterlab--codemirror@4.4.0JupyterLab CodeMirror is the default implementation of the JupyterLab code editor interface using CodeMirror 6. It provides a comprehensive editor provider that integrates modern text editing capabilities with JupyterLab's architecture, featuring syntax highlighting for 100+ programming languages, autocomplete functionality, search capabilities, collaborative editing through Y.js integration, customizable themes and styling, ruler extensions for layout guides, and language-specific features.
npm install @jupyterlab/codemirrorimport {
CodeMirrorEditor,
CodeMirrorEditorFactory,
EditorExtensionRegistry,
EditorLanguageRegistry,
EditorThemeRegistry
} from "@jupyterlab/codemirror";For CommonJS:
const {
CodeMirrorEditor,
CodeMirrorEditorFactory,
EditorExtensionRegistry,
EditorLanguageRegistry
} = require("@jupyterlab/codemirror");import { CodeMirrorEditorFactory } from "@jupyterlab/codemirror";
import { CodeEditor } from "@jupyterlab/codeeditor";
// Create editor factory
const factory = new CodeMirrorEditorFactory();
// Create a document editor
const model = new CodeEditor.Model();
const editor = factory.newDocumentEditor({
model,
host: document.createElement('div')
});
// Set content and configure
model.sharedModel.setSource("console.log('Hello, World!');");
model.mimeType = "text/javascript";
// Focus the editor
editor.focus();JupyterLab CodeMirror is built around several key components:
CodeMirrorEditor class implementing the full CodeEditor.IEditor interfaceCodeMirrorEditorFactory for creating inline and document editors with different configurationsMain editor implementation providing all text editing functionality including cursor management, selection handling, and text operations.
class CodeMirrorEditor implements CodeEditor.IEditor {
constructor(options: CodeMirrorEditor.IOptions);
readonly edgeRequested: Signal<this, CodeEditor.EdgeLocation>;
readonly host: HTMLElement;
readonly editor: EditorView;
readonly doc: Text;
readonly model: CodeEditor.IModel;
readonly uuid: string;
readonly lineCount: number;
readonly selectionStyle: CodeEditor.ISelectionStyle;
focus(): void;
hasFocus(): boolean;
blur(): void;
resizeToFit(): void;
refresh(): void;
addKeydownHandler(handler: CodeEditor.KeydownHandler): IDisposable;
setSize(size: CodeEditor.IDimension | null): void;
getCursorPosition(): CodeEditor.IPosition;
setCursorPosition(position: CodeEditor.IPosition, options?: object): void;
getSelections(): CodeEditor.ITextSelection[];
setSelections(selections: CodeEditor.IRange[]): void;
getOption<K extends keyof CodeEditor.IConfig>(option: K): CodeEditor.IConfig[K];
setOption<K extends keyof CodeEditor.IConfig>(option: K, value: CodeEditor.IConfig[K]): void;
setOptions(options: Partial<CodeEditor.IConfig>): void;
getLine(index: number): string | undefined;
getOffsetAt(position: CodeEditor.IPosition): number;
getPositionAt(offset: number): CodeEditor.IPosition | undefined;
getCoordinateForPosition(position: CodeEditor.IPosition): CodeEditor.ICoordinate;
getPositionForCoordinate(coordinate: CodeEditor.ICoordinate): CodeEditor.IPosition | null;
}
interface CodeMirrorEditor.IOptions extends CodeEditor.IOptions {
extensionsRegistry?: IEditorExtensionRegistry;
languages?: IEditorLanguageRegistry;
}Factory service for creating CodeMirror editors with different configurations for inline and document use cases.
class CodeMirrorEditorFactory implements IEditorFactoryService {
constructor(options?: IEditorFactoryOptions);
readonly newInlineEditor: (options: CodeEditor.IOptions) => CodeMirrorEditor;
readonly newDocumentEditor: (options: CodeEditor.IOptions) => CodeMirrorEditor;
protected readonly extensions: IEditorExtensionRegistry;
protected readonly languages: IEditorLanguageRegistry;
protected readonly translator: ITranslator;
protected readonly inlineCodeMirrorConfig: Record<string, any>;
protected readonly documentCodeMirrorConfig: Record<string, any>;
protected newEditor(options: CodeEditor.IOptions & IEditorExtensionFactory.IOptions): CodeMirrorEditor;
}
interface IEditorFactoryOptions {
extensions?: IEditorExtensionRegistry;
languages?: IEditorLanguageRegistry;
translator?: ITranslator;
}Comprehensive extension registry with 25+ configurable extensions for customizing editor behavior and appearance.
class EditorExtensionRegistry implements IEditorExtensionRegistry {
constructor(options?: { themes?: IEditorThemeRegistry; translator?: ITranslator });
readonly baseConfiguration: Record<string, any>;
readonly defaultConfiguration: Record<string, any>;
readonly settingsSchema: ReadonlyJSONObject;
addExtension<T>(factory: IEditorExtensionFactory<T>): void;
createNew(options: IEditorExtensionFactory.IOptions & { config?: Record<string, any> }): IExtensionsHandler;
}
class ExtensionsHandler implements IExtensionsHandler {
constructor(options?: IEditorHandlerOptions);
readonly configChanged: ISignal<this, Record<string, any>>;
readonly disposed: ISignal<this, void>;
readonly isDisposed: boolean;
dispose(): void;
getOption(option: string): unknown;
hasOption(option: string): boolean;
setOption(option: string, value: unknown): void;
setOptions(options: Record<string, any>): void;
setBaseOptions(options: Record<string, any>): void;
getInitialExtensions(): Extension[];
injectExtension(view: EditorView, extension: Extension): void;
reconfigureExtension<T>(view: EditorView, key: string, value: T): void;
reconfigureExtensions(view: EditorView, configuration: Record<string, any>): void;
}Language registry supporting 100+ programming languages with syntax highlighting, autocomplete, and language-specific features.
class EditorLanguageRegistry implements IEditorLanguageRegistry {
constructor();
addLanguage(language: IEditorLanguage): void;
getLanguage(language: string | IEditorLanguage): Promise<IEditorLanguage | null>;
findBest(language: string | IEditorLanguage, fallback?: boolean): IEditorLanguage | null;
findByMIME(mime: string | readonly string[]): IEditorLanguage | null;
findByName(name: string): IEditorLanguage | null;
findByExtension(ext: string | readonly string[]): IEditorLanguage | null;
findByFileName(name: string): IEditorLanguage | null;
getLanguages(): IEditorLanguage[];
highlight(code: string, language: IEditorLanguage | null, el: HTMLElement): Promise<void>;
}
interface IEditorLanguage {
readonly name: string;
readonly displayName?: string;
readonly alias?: readonly string[];
readonly mime: string | readonly string[];
readonly extensions?: readonly string[];
readonly filename?: RegExp;
readonly support?: LanguageSupport;
readonly load?: () => Promise<LanguageSupport>;
}Theme registry with JupyterLab integration supporting custom themes and CSS variable-based styling.
class EditorThemeRegistry implements IEditorThemeRegistry {
constructor();
readonly themes: IEditorTheme[];
defaultTheme(): Extension;
addTheme(theme: IEditorTheme): void;
getTheme(name: string): Extension;
}
interface IEditorTheme {
readonly name: string;
readonly displayName?: string;
readonly theme: Extension;
}
const jupyterTheme: Extension;
const jupyterEditorTheme: EditorView.theme;
const jupyterHighlightStyle: HighlightStyle;Advanced search provider with regex support, match highlighting, and comprehensive find/replace functionality.
abstract class EditorSearchProvider<T extends CodeEditor.IModel = CodeEditor.IModel>
implements IBaseSearchProvider {
readonly currentMatchIndex: number | null;
readonly isActive: boolean;
readonly matchesCount: number;
readonly stateChanged: ISignal<IBaseSearchProvider, void>;
startQuery(query: RegExp | null, filters?: IFilters): Promise<void>;
endQuery(): Promise<void>;
highlightNext(loop?: boolean, options?: IHighlightAdjacentMatchOptions): Promise<ISearchMatch | undefined>;
highlightPrevious(loop?: boolean, options?: IHighlightAdjacentMatchOptions): Promise<ISearchMatch | undefined>;
replaceCurrentMatch(newText: string, loop?: boolean, options?: IReplaceOptions): Promise<boolean>;
replaceAllMatches(newText: string, options?: IReplaceOptions): Promise<boolean>;
}
class CodeMirrorSearchHighlighter {
constructor(editor: CodeMirrorEditor | null);
readonly currentIndex: number | null;
matches: ISearchMatch[];
protectSelection: boolean;
}Custom command functions for editor interactions, keyboard shortcuts, and special behaviors.
namespace StateCommands {
function indentMoreOrInsertTab(target: CommandTarget): boolean;
function completerOrInsertNewLine(target: CommandTarget): boolean;
function insertBlankLineOnRun(target: CommandTarget): boolean;
function simplifySelectionAndMaybeSwitchToCommandMode(target: CommandTarget): boolean;
function dedentIfNotLaunchingTooltip(target: CommandTarget): boolean;
}
interface CommandTarget {
dom: HTMLElement;
state: EditorState;
dispatch: (transaction: Transaction) => void;
}Specialized extensions for advanced functionality including collaborative editing, rulers, custom styling, and Python highlighting.
// Y.js collaborative editing
function ybinding(options: { ytext: Text; undoManager?: UndoManager }): Extension;
// Ruler display
function rulers(positions: number[]): Extension;
// Custom styling
function customTheme(config: CustomTheme): Extension;
// Python built-in highlighting
function pythonBuiltin(langPython: Language): ViewPlugin;
// IPython math parsing
function parseMathIPython(latexParser?: Parser): MarkdownConfig;
interface CustomTheme {
fontFamily: string | null;
fontSize: number | null;
lineHeight: number | null;
}Service for resolving MIME types based on file extensions and language metadata.
class CodeMirrorMimeTypeService implements IEditorMimeTypeService {
constructor(languages: IEditorLanguageRegistry);
getMimeTypeByLanguage(info: nbformat.ILanguageInfoMetadata): string;
getMimeTypeByFilePath(path: string): string;
}// Extension system
interface IConfigurableExtension<T> {
instance(value: T): Extension;
reconfigure(value: T): StateEffect<T> | null;
}
interface IExtensionsHandler extends IDisposable {
readonly configChanged: ISignal<this, Record<string, any>>;
readonly disposed: ISignal<this, void>;
readonly isDisposed: boolean;
dispose(): void;
getOption(option: string): unknown;
hasOption(option: string): boolean;
setOption(option: string, value: unknown): void;
setOptions(options: Record<string, any>): void;
setBaseOptions(options: Record<string, any>): void;
getInitialExtensions(): Extension[];
injectExtension(view: EditorView, extension: Extension): void;
reconfigureExtension<T>(view: EditorView, key: string, value: T): void;
reconfigureExtensions(view: EditorView, configuration: Record<string, any>): void;
}
interface IEditorExtensionFactory<T = undefined> {
readonly name: string;
readonly factory: (options: IEditorExtensionFactory.IOptions) => IConfigurableExtension<T> | null;
readonly default?: T;
readonly schema?: ReadonlyJSONObject;
}
namespace IEditorExtensionFactory {
export interface IOptions {
inline: boolean;
model: CodeEditor.IModel;
}
}
interface IEditorHandlerOptions {
baseConfiguration?: Record<string, any>;
config?: Record<string, any>;
defaultExtensions?: [string, IConfigurableExtension<any>][];
}
// Custom styles
interface CustomTheme {
fontFamily: string | null;
fontSize: number | null;
lineHeight: number | null;
}
// Search types
type SearchStartAnchor = 'auto' | 'selection' | 'selection-start' | 'previous-match' | 'start';
interface IHighlightMatchOptions {
scroll?: boolean;
select?: boolean;
}
interface IHighlightAdjacentMatchOptions extends IHighlightMatchOptions {
from?: SearchStartAnchor;
}
interface IReplaceOptions {
preserveSelections?: boolean;
}
// Y.js types
interface ID {
client: number;
clock: number;
}
interface Position {
type: ID | null;
tname: string | null;
item: ID | null;
assoc: number;
}
interface Range {
yanchor: Position;
yhead: Position;
}const IEditorExtensionRegistry: Token<IEditorExtensionRegistry>;
const IEditorLanguageRegistry: Token<IEditorLanguageRegistry>;
const IEditorThemeRegistry: Token<IEditorThemeRegistry>;