From 812702aa9afbfe8de7672520852a6066341a4dc0 Mon Sep 17 00:00:00 2001
From: Clawd <ai@clawd.bot>
Date: Sat, 28 Feb 2026 13:51:38 -0800
Subject: Add CodeMirror 6 for markdown editing

- Install CodeMirror 6 with markdown language support
- Add MarkdownEditor component with:
  - Syntax highlighting for markdown
  - Line numbers
  - Active line highlighting
  - History (undo/redo)
  - One Dark theme
  - Code block language highlighting
- Keep react-markdown for preview mode
- Add CSS for CodeMirror integration
---
 renderer/src/components/DocumentPane.tsx | 100 +++++++++++++++++++++++++++++--
 1 file changed, 94 insertions(+), 6 deletions(-)

(limited to 'renderer/src/components/DocumentPane.tsx')

diff --git a/renderer/src/components/DocumentPane.tsx b/renderer/src/components/DocumentPane.tsx
index 95d7d03..cf777b1 100644
--- a/renderer/src/components/DocumentPane.tsx
+++ b/renderer/src/components/DocumentPane.tsx
@@ -1,6 +1,12 @@
-import React, { useState } from "react";
+import React, { useState, useRef, useEffect } from "react";
 import ReactMarkdown from "react-markdown";
 import remarkGfm from "remark-gfm";
+import { EditorState } from "@codemirror/state";
+import { EditorView, keymap, lineNumbers, highlightActiveLine } from "@codemirror/view";
+import { markdown } from "@codemirror/lang-markdown";
+import { languages } from "@codemirror/language-data";
+import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
+import { oneDark } from "@codemirror/theme-one-dark";
 import type { Phase } from "../types";
 
 interface DocumentPaneProps {
@@ -11,6 +17,90 @@ interface DocumentPaneProps {
   showOnboarding?: boolean;
 }
 
+function MarkdownEditor({
+  content,
+  onChange,
+  disabled,
+}: {
+  content: string;
+  onChange: (content: string) => void;
+  disabled: boolean;
+}) {
+  const editorRef = useRef<HTMLDivElement>(null);
+  const viewRef = useRef<EditorView | null>(null);
+
+  useEffect(() => {
+    if (!editorRef.current) return;
+
+    const updateListener = EditorView.updateListener.of((update) => {
+      if (update.docChanged) {
+        onChange(update.state.doc.toString());
+      }
+    });
+
+    const state = EditorState.create({
+      doc: content,
+      extensions: [
+        lineNumbers(),
+        highlightActiveLine(),
+        history(),
+        keymap.of([...defaultKeymap, ...historyKeymap]),
+        markdown({ codeLanguages: languages }),
+        oneDark,
+        updateListener,
+        EditorView.editable.of(!disabled),
+        EditorView.theme({
+          "&": {
+            height: "100%",
+            fontSize: "14px",
+          },
+          ".cm-scroller": {
+            overflow: "auto",
+            fontFamily: '"SF Mono", Monaco, "Cascadia Code", monospace',
+          },
+          ".cm-content": {
+            padding: "16px 0",
+          },
+          ".cm-line": {
+            padding: "0 16px",
+          },
+        }),
+      ],
+    });
+
+    const view = new EditorView({
+      state,
+      parent: editorRef.current,
+    });
+
+    viewRef.current = view;
+
+    return () => {
+      view.destroy();
+      viewRef.current = null;
+    };
+  }, [disabled]);
+
+  // Update content when it changes externally
+  useEffect(() => {
+    const view = viewRef.current;
+    if (!view) return;
+
+    const currentContent = view.state.doc.toString();
+    if (content !== currentContent) {
+      view.dispatch({
+        changes: {
+          from: 0,
+          to: currentContent.length,
+          insert: content,
+        },
+      });
+    }
+  }, [content]);
+
+  return <div ref={editorRef} className="codemirror-editor" />;
+}
+
 export function DocumentPane({
   content,
   onChange,
@@ -115,12 +205,10 @@ export function DocumentPane({
       </div>
 
       {isEditing ? (
-        <textarea
-          className="document-content editing"
-          value={content}
-          onChange={(e) => onChange(e.target.value)}
+        <MarkdownEditor
+          content={content}
+          onChange={onChange}
           disabled={disabled}
-          placeholder={`${filename} will appear here...`}
         />
       ) : (
         <div
-- 
cgit v1.2.3

