LCOV - code coverage report
Current view: top level - dashql-app/src/session/editor - codemirror.tsx Coverage Total Hit
Test: DashQL 915828b Lines: 100.0 % 53 53
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as React from 'react';
       2              : import * as themes from './themes/index.js';
       3              : 
       4              : import { EditorState, Extension } from '@codemirror/state';
       5              : import { defaultKeymap, history, historyKeymap } from "@codemirror/commands"
       6              : import { search, searchKeymap } from '@codemirror/search';
       7              : import { EditorView, drawSelection, keymap, lineNumbers } from '@codemirror/view';
       8              : import { DashQLExtensions, DashQLReadonlyExtensions } from './dashql_extension.js';
       9              : 
      10              : import { useLogger } from '../../platform/logger/logger_provider.js';
      11              : 
      12              : import './codemirror.css';
      13              : 
      14              : export interface CodeMirrorProps {
      15              :     /// Root of the DOM where the editor is mounted
      16              :     root?: ShadowRoot | Document;
      17              :     /// Override styles for the container div (e.g. height: 'auto' for auto-expand)
      18              :     style?: React.CSSProperties;
      19              :     /// Additional extensions appended after the default set
      20              :     extraExtensions?: Extension[];
      21              :     /// Full editor-specific extension set to use instead of defaults. Shared search is still appended.
      22              :     extensions?: Extension[];
      23              :     /// Document used when constructing the EditorState. Later changes are owned by the caller.
      24              :     initialDoc?: string;
      25              : }
      26              : 
      27            1 : export const CodeMirrorSearchExtensions: Extension[] = [
      28            1 :     search({ top: true }),
      29            1 :     keymap.of(searchKeymap),
      30            1 : ];
      31              : 
      32            1 : export function createCodeMirrorExtensions(): Extension[] {
      33              :     // See: https://github.com/codemirror/basic-setup/blob/main/src/codemirror.ts
      34              :     // We might want to add other plugins later.
      35            1 :     const keymapExtension = keymap.of([
      36            1 :         ...defaultKeymap,
      37            1 :         ...historyKeymap
      38            1 :     ]);
      39              :     const extensions: Extension[] = [
      40            1 :         themes.xcode,
      41            1 :         lineNumbers(),
      42            1 :         drawSelection(),
      43            1 :         history(),
      44            1 :         ...DashQLExtensions,
      45            1 :         ...CodeMirrorSearchExtensions,
      46            1 :         keymapExtension
      47              :     ];
      48            1 :     return extensions;
      49            1 : }
      50              : 
      51            1 : export function createReadonlyCodeMirrorExtensions(): Extension[] {
      52            1 :     return [
      53            1 :         themes.xcode,
      54            1 :         lineNumbers(),
      55            1 :         drawSelection(),
      56            1 :         EditorState.readOnly.of(true),
      57            1 :         ...DashQLReadonlyExtensions,
      58            1 :         ...CodeMirrorSearchExtensions,
      59            1 :     ];
      60            1 : }
      61              : 
      62            1 : export const CodeMirror = React.forwardRef<EditorView, CodeMirrorProps>((props: CodeMirrorProps, ref) => {
      63            1 :     const logger = useLogger();
      64              : 
      65            1 :     const [node, setNode] = React.useState<HTMLDivElement | null>(null);
      66              : 
      67            1 :     React.useEffect(() => {
      68              :         // Not mounted yet?
      69              :         // Then do nothing.
      70            1 :         if (node == null) {
      71            1 :             return () => { };
      72              :         }
      73            1 :         logger.debug("Creating a new codemirror view", {}, "codemirror");
      74              : 
      75              :         // The DOM node has changed, create a new view
      76            1 :         const extensions = props.extensions == null
      77            1 :             ? [...createCodeMirrorExtensions(), ...(props.extraExtensions ?? [])]
      78            1 :             : [...props.extensions, ...CodeMirrorSearchExtensions];
      79            1 :         const view = new EditorView({
      80            1 :             state: EditorState.create({ doc: props.initialDoc, extensions }),
      81            1 :             parent: node,
      82            1 :             root: props.root,
      83            1 :         });
      84              : 
      85              :         // Forward the ref
      86            1 :         if (typeof ref === 'function') {
      87            1 :             ref(view);
      88            1 :         } else if (ref) {
      89            1 :             ref.current = view;
      90              :         }
      91              : 
      92              :         // Destroy the view when unmounting
      93            1 :         return () => {
      94            1 :             view.destroy();
      95            1 :         };
      96            1 :     }, [node, ref]);
      97              : 
      98              : 
      99            1 :     return <div style={{ width: '100%', height: '100%', ...props.style }} ref={setNode}></div>;
     100            1 : });
        

Generated by: LCOV version 2.0-1