CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jupyterlab--codemirror

CodeMirror 6 editor provider for JupyterLab with comprehensive language support, themes, extensions, and collaborative editing capabilities

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

extension-system.mddocs/

Extension System

The extension system provides a comprehensive registry and configuration management for 25+ configurable extensions that customize editor behavior and appearance.

Capabilities

EditorExtensionRegistry

Main registry for managing editor extensions and their configurations.

/**
 * CodeMirror extensions registry
 * Manages 25+ configurable extensions for editor customization
 */
class EditorExtensionRegistry implements IEditorExtensionRegistry {
  constructor();
  
  /**
   * Base editor configuration (default config optionally modified by user)
   */
  baseConfiguration: Record<string, any>;
  
  /**
   * Default editor configuration as defined when extensions are registered
   */
  readonly defaultConfiguration: Record<string, any>;
  
  /**
   * Editor configuration JSON schema for validation
   */
  readonly settingsSchema: ReadonlyJSONObject;
  
  /**
   * Add a default editor extension
   */
  addExtension<T>(factory: IEditorExtensionFactory<T>): void;
  
  /**
   * Create a new extensions handler for an editor
   */
  createNew(options: IEditorHandlerOptions): IExtensionsHandler;
}

interface IEditorExtensionRegistry {
  readonly baseConfiguration: Record<string, any>;
  addExtension<T>(factory: IEditorExtensionFactory<T>): void;
  createNew(options: IEditorHandlerOptions): IExtensionsHandler;
}

Usage Examples:

import { EditorExtensionRegistry } from "@jupyterlab/codemirror";

// Create extension registry
const registry = new EditorExtensionRegistry();

// Add custom extension
registry.addExtension({
  name: 'myExtension',
  factory: (options) => ({
    instance: (value) => myCustomExtension(value),
    reconfigure: (value) => myExtension.reconfigure(value)
  }),
  default: true,
  schema: {
    type: 'boolean',
    description: 'Enable my custom extension'
  }
});

// Create extensions handler for editor
const handler = registry.createNew({
  baseConfiguration: { lineNumbers: true },
  config: { myExtension: true }
});

ExtensionsHandler

Manages individual editor configuration and extension lifecycle.

/**
 * Editor configuration handler
 * Stores editor configuration and manages extension reconfiguration
 */
class ExtensionsHandler implements IExtensionsHandler, IObservableDisposable {
  constructor(options?: IEditorHandlerOptions);
  
  /**
   * Signal triggered when editor configuration changes
   */
  readonly configChanged: ISignal<this, Record<string, any>>;
  
  /**
   * Signal emitted when object is disposed
   */
  readonly disposed: ISignal<this, void>;
  
  /**
   * Whether the object is disposed
   */
  readonly isDisposed: boolean;
  
  // Lifecycle
  dispose(): void;
  
  // Configuration management
  getOption(option: string): unknown;
  hasOption(option: string): boolean;
  setOption(option: string, value: unknown): void;
  setBaseOptions(options: Record<string, any>): void;
  setOptions(options: Record<string, any>): void;
  
  // Extension management
  reconfigureExtension<T>(view: EditorView, key: string, value: T): void;
  reconfigureExtensions(view: EditorView, configuration: Record<string, any>): void;
  injectExtension(view: EditorView, extension: Extension): void;
  getInitialExtensions(): Extension[];
}

interface IEditorHandlerOptions {
  baseConfiguration?: Record<string, any>;
  config?: Record<string, any>;
  defaultExtensions?: [string, IConfigurableExtension<any>][];
}

Usage Examples:

import { ExtensionsHandler } from "@jupyterlab/codemirror";
import { EditorView } from "@codemirror/view";

// Create handler with configuration
const handler = new ExtensionsHandler({
  baseConfiguration: {
    lineNumbers: true,
    tabSize: 4
  },
  config: {
    lineWrap: true,
    theme: 'dark'
  }
});

// Listen for configuration changes
handler.configChanged.connect((sender, changes) => {
  console.log('Configuration changed:', changes);
});

// Update single option
handler.setOption('fontSize', 14);

// Update multiple options
handler.setOptions({
  lineHeight: 1.5,
  fontFamily: 'Monaco'
});

// Get current option value
const lineNumbers = handler.getOption('lineNumbers'); // true

// Reconfigure extensions on editor view
const view = new EditorView({...});
handler.reconfigureExtensions(view, {
  lineNumbers: false,
  lineWrap: false
});

Default Extensions

The registry comes with 25+ built-in extensions for comprehensive editor customization.

/**
 * Get default editor extensions
 * Returns array of 25+ configurable extension factories
 */
static getDefaultExtensions(options?: {
  themes?: IEditorThemeRegistry;
  translator?: ITranslator | null;
}): ReadonlyArray<Readonly<IEditorExtensionFactory<any>>>;

Built-in Extensions:

  1. autoClosingBrackets - Automatically close brackets and quotes
  2. codeFolding - Code folding functionality
  3. cursorBlinkRate - Cursor blinking rate configuration
  4. highlightActiveLine - Highlight the current line
  5. highlightSpecialCharacters - Highlight special/invisible characters
  6. highlightTrailingWhitespace - Highlight trailing whitespace
  7. highlightWhitespace - Highlight all whitespace characters
  8. indentUnit - Indentation unit size
  9. keymap - Keyboard shortcuts and key bindings
  10. lineNumbers - Line number display
  11. lineWrap - Line wrapping behavior
  12. dropCursor - Drop cursor for drag and drop
  13. matchBrackets - Bracket matching
  14. rectangularSelection - Rectangular/block selection
  15. readOnly - Read-only mode
  16. rulers - Ruler lines at specified columns
  17. extendSelection - Selection extension behavior
  18. searchWithCM - Native CodeMirror search panel
  19. scrollPastEnd - Allow scrolling past document end
  20. smartIndent - Smart indentation
  21. tabFocusable - Tab key focus behavior
  22. tabSize - Tab size configuration
  23. tooltips - Tooltip support
  24. allowMultipleSelections - Multiple cursor support
  25. customStyles - Custom editor styling
  26. theme - Theme support (when theme registry provided)
  27. translation - Internationalization (when translator provided)

Usage Examples:

import { EditorExtensionRegistry } from "@jupyterlab/codemirror";

// Get default extensions
const extensions = EditorExtensionRegistry.getDefaultExtensions();

// Get extensions with theme and translation support
const extensionsWithThemes = EditorExtensionRegistry.getDefaultExtensions({
  themes: themeRegistry,
  translator: app.translator
});

// Create registry with default extensions
const registry = new EditorExtensionRegistry();
extensions.forEach(extension => registry.addExtension(extension));

Extension Factory Interface

Interface for creating configurable extensions.

/**
 * Editor extension factory interface
 */
interface IEditorExtensionFactory<T> {
  /**
   * Extension unique identifier
   */
  readonly name: string;
  
  /**
   * Extension factory function
   */
  readonly factory: (options: IEditorExtensionFactory.IOptions) => IConfigurableExtension<T> | null;
  
  /**
   * Extension default value
   */
  readonly default?: T;
  
  /**
   * JSON schema for configurable option
   */
  readonly schema?: ReadonlyJSONObject;
}

interface IEditorExtensionFactory.IOptions {
  inline: boolean;
  model: CodeEditor.IModel;
}

/**
 * Dynamically configurable editor extension
 */
interface IConfigurableExtension<T> {
  /**
   * Create an editor extension for the provided value
   */
  instance(value: T): Extension;
  
  /**
   * Reconfigure an editor extension with new value
   */
  reconfigure(value: T): StateEffect<T> | null;
}

Extension Creation Utilities

Helper functions for creating different types of extensions.

/**
 * Creates a dynamically configurable editor extension
 */
static createConfigurableExtension<T>(
  builder: (value: T) => Extension
): IConfigurableExtension<T>;

/**
 * Creates a configurable extension returning one of two extensions
 * based on a boolean value
 */
static createConditionalExtension(
  truthy: Extension, 
  falsy?: Extension
): IConfigurableExtension<boolean>;

/**
 * Creates an immutable extension (cannot be reconfigured)
 */
static createImmutableExtension(
  extension: Extension
): IConfigurableExtension<undefined>;

Usage Examples:

import { EditorExtensionRegistry } from "@jupyterlab/codemirror";
import { lineNumbers } from "@codemirror/view";
import { keymap } from "@codemirror/view";
import { defaultKeymap } from "@codemirror/commands";

// Create configurable extension
const configurableLineNumbers = EditorExtensionRegistry.createConfigurableExtension<boolean>(
  (show) => show ? lineNumbers() : []
);

// Create conditional extension
const conditionalKeymap = EditorExtensionRegistry.createConditionalExtension(
  keymap.of(defaultKeymap),
  []  // No keymap when false
);

// Create immutable extension
const immutableTheme = EditorExtensionRegistry.createImmutableExtension(
  EditorView.theme({
    '.cm-editor': { fontSize: '14px' }
  })
);

// Add to registry
registry.addExtension({
  name: 'myLineNumbers',
  factory: () => configurableLineNumbers,
  default: true
});

Advanced Configuration

Complex configuration scenarios and extension interactions.

// Create handler with complex configuration
const handler = new ExtensionsHandler({
  baseConfiguration: {
    // Base settings applied to all editors
    tabSize: 4,
    indentUnit: '  ',
    lineNumbers: true
  },
  config: {
    // Specific settings for this editor
    theme: 'jupyterlab',
    lineWrap: true,
    rulers: [80, 120]
  },
  defaultExtensions: [
    // Custom extensions specific to this handler
    ['myCustomExtension', myCustomExtensionFactory.factory()]
  ]
});

// Dynamic reconfiguration based on context
handler.configChanged.connect((sender, changes) => {
  if ('theme' in changes) {
    // React to theme changes
    updateEditorStyling(changes.theme);
  }
  
  if ('language' in changes) {
    // Update language-specific extensions
    handler.setOptions({
      pythonBuiltin: changes.language === 'python',
      jsxHighlighting: changes.language === 'jsx'
    });
  }
});

// Conditional extension loading
if (isCollaborativeMode) {
  handler.setOptions({
    yBinding: true,
    collaborativeCursors: true,
    conflictResolution: 'merge'
  });
}

Types

interface IExtensionsHandler extends IDisposable {
  readonly configChanged: ISignal<this, Record<string, any>>;
  
  getOption(option: string): unknown;
  hasOption(option: string): boolean;
  setOption(option: string, value: unknown): void;
  setBaseOptions(options: Record<string, any>): void;
  setOptions(options: Record<string, any>): void;
  reconfigureExtension<T>(view: EditorView, key: string, value: T): void;
  reconfigureExtensions(view: EditorView, configuration: Record<string, any>): void;
  injectExtension(view: EditorView, extension: Extension): void;
  getInitialExtensions(): Extension[];
}

interface IEditorHandlerOptions {
  baseConfiguration?: Record<string, any>;
  config?: Record<string, any>;
  defaultExtensions?: [string, IConfigurableExtension<any>][];
}

docs

editor-commands.md

editor-core.md

editor-factory.md

extension-system.md

index.md

language-support.md

mime-type-service.md

search-replace.md

special-extensions.md

theme-system.md

tile.json