Friday, 10 July 2026

Roject — Session Summary

CodePanel — a CodeMirror-based code editor panel with a central file-editor registry that routes files to the right panel by suffix.

What we built

FileEditorRegistry

A new src/editor/FileEditorRegistry.ts class that maps file suffixes to editor panel tags. It holds a default in-memory list and optionally loads a project-level override from workspace/editor/file-editors.json inside the open project.

Matching is pure suffix comparison — filename.endsWith('.' + suffix) — so special.html beats html when it appears earlier in the list. The project list is checked first entry-by-entry; only when no match is found there does it fall through to the defaults. Unknown extensions fire an onFileTypeUnknown event instead of opening anything.

src/editor/FileEditorRegistry.ts suffix matching project override

Editor routing changes

Editor.openDocument now loads the registry (once, lazily) before fetching file content. It resolves an editorTag and includes it in the DocumentOpenedEvent. If no tag is found it dispatches the new onFileTypeUnknown event and returns early without fetching the file.

HtmlEditorPanel was updated to ignore events where editorTag !== 'html-editor-panel'. TabContainer's dirty and saved listeners were simplified to match any panel by currentPath rather than hard-coding panelType === 'html-editor'.

src/editor/Editor.ts editorTag in DocumentOpenedEvent onFileTypeUnknown

CodePanel component

A new code-panel custom element backed by CodeMirror 5. Toolbar matches html-editor-panel: Pin, Undo, Redo, Save. Undo and Redo delegate directly to cm.undo() / cm.redo(); button enable-states are refreshed from cm.historySize() on every CM change event.

Language mode is resolved from the file extension (js/ts/json → javascript, css → css, xml/svg → xml, md → markdown, others → plain text). A custom cp-dark CodeMirror theme matches the editor's colour palette (background #0f1117, Material-style token colours).

The file tree was updated so all files are clickable (not just HTML); clicking an unsupported extension shows a 3-second red banner ("Can't open extension .xyz") at the top of the tree.

src/components/code-panel/code-panel.ts public/components/code-panel/code-panel.css CodeMirror 5 cp-dark theme

Key Decisions

Central JSON list, not editor self-registration

Editors could declare their own patterns at import time, but that makes overriding them require touching editor source. A central list stored as data (JSON) lets a project prepend custom mappings without modifying any editor code. The project file is optional; when absent, in-memory defaults apply.

Per-entry layered lookup, not full list replacement

When a project provides file-editors.json, only the suffixes it declares are overridden. Everything else falls through to the defaults. This means a project only needs to list custom formats, not restate all standard ones.

Plain suffix strings, no glob patterns

Glob matching requires a library or a non-trivial implementation. Stripping the leading *. and using endsWith('.' + suffix) is sufficient for all real cases (including compound extensions like special.html) and needs no dependency.

CodeMirror 5 as a UMD global, vendored locally

CodeMirror 6 requires a bundler or complex import maps to use without a build step. CM5 ships a single-file UMD build that works as a plain <script> tag, matching the existing pattern (markdown-it). The core and five language modes were downloaded from cdnjs and placed in public/vendor/, keeping the setup self-hosted and version-locked.

Structural Changes

src/editor/FileEditorRegistry.ts — new: suffix-to-editor registry with project override
src/editor/Editor.ts — added fileEditorRegistry, editorTag in event, onFileTypeUnknown
src/components/html-editor-panel/html-editor-panel.ts — filters onDocumentOpened by editorTag
src/components/file-tree-panel/file-tree-panel.ts — all files clickable, _showTypeError for unknown extensions
public/components/file-tree-panel/file-tree-panel.css — all files get hover/active styles, added .ftp-type-error
src/components/code-panel/code-panel.ts — new: CodeMirror 5 editor panel
public/components/code-panel/code-panel.css — new: panel layout + cp-dark CM theme
public/vendor/codemirror.min.js — new (CM5 core)
public/vendor/codemirror.min.css — new (CM5 base CSS)
public/vendor/cm-mode-xml.min.js — new
public/vendor/cm-mode-javascript.min.js — new
public/vendor/cm-mode-css.min.js — new
public/vendor/cm-mode-htmlmixed.min.js — new
public/vendor/cm-mode-markdown.min.js — new
public/editor.html — added CM vendor scripts, code-panel CSS and module script
src/components/tab-container/tab-container.ts — added Code Editor to menu, panel-agnostic dirty tracking
src/components/editor-shell/editor-shell.ts — awaits code-panel definition