Repository navigation
[#912 Slice 1] Extract editor-core.ts + consolidate preprocessMarkdown #919
Description
Important
Problem — The CodeMirror setup functions (baseExtensions, editableExtensions, loadLanguage, buildThemeExtension, buildSyntaxHighlightStyle, detectMode, externalUpdate) live inside editable-diff-view-core.ts, tightly coupled to the diff view. The new Preview editor needs these same functions but has nothing to do with diffs. Additionally, preprocessMarkdown is duplicated three times across the codebase with divergent implementations.
Approach — Extract the general-purpose CM6 setup functions into editor-core.ts in session-ui. Consolidate preprocessMarkdown into markdown-utils.ts. Also export a shared RENDERABLE_EXTENSIONS constant from markdown-utils.ts for use by all preview-related slices. Both extractions are pure moves — no signature changes, no behavior changes. The diff view imports from the new modules and its call sites remain unchanged.
Scope — in: function extraction, import rewiring, preprocessMarkdown consolidation, RENDERABLE_EXTENSIONS constant · out: any UI change, any new component, any behavior change
Acceptance Criteria
-
editor-core.tsexportsbaseExtensions,editableExtensions,loadLanguage,buildThemeExtension,buildSyntaxHighlightStyle,detectMode, and theexternalUpdateannotation — all with their existing signatures -
baseExtensions(opts: { theme: Extension, language?: LanguageSupport | null }): Extension[]— signature preserved exactly -
editableExtensionsand its co-locatedexternalUpdateannotation both move toeditor-core.ts(the annotation is referenced insideeditableExtensions's update listener filter) -
detectMode(): "light" | "dark"is extracted (it reads the theme from CSS and is needed by any consumer ofbuildThemeExtension) -
editable-diff-view-core.tsimports fromeditor-core.ts— its own exports and behavior are unchanged -
markdown-utils.tsexports a singlepreprocessMarkdownimplementation — the canonical version with newlines and trim:`$$\n${body.trim()}\n$$` -
markdown-utils.tsexportsRENDERABLE_EXTENSIONS— the single source of truth for file type filtering:{ markdown: [".md", ".markdown"], images: [".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".ico", ".bmp"], pdf: [".pdf"] }and a helperisRenderable(filename: string): boolean -
session-preview-tab.tsxandsession-review-file-preview-v2.tsxboth importpreprocessMarkdownfrom the shared module - The test in
markdown_preview.test.tsimports from the shared module and its assertions are updated to match the canonical implementation (the test currently defines its own copy WITHOUT newlines; 4 assertions need updating to expect the\nwrapping) - Files Changed tab behavior is completely unchanged (existing tests pass)
Testing Decisions
Run the existing test suite (pnpm --filter amicode test) — all tests must pass. Update markdown_preview.test.ts to: (1) delete its local preprocessMarkdown definition, (2) import from markdown-utils.ts, (3) update the 4 math-block assertions to expect the canonical $$\n...\n$$ format with trim. No new test files needed — this is a pure extraction. Add a unit test for isRenderable() covering each extension category and rejection of non-renderable extensions.
Key Decisions
Signatures preserved exactly. baseExtensions(opts: { theme: Extension, language?: LanguageSupport | null }), buildThemeExtension(mode: "light" | "dark"), loadLanguage(ext: string), detectMode(): "light" | "dark" — no wrappers, no adapters. The diff view's call sites do not change at all.
externalUpdate moves with editableExtensions. The annotation is referenced inside the update listener filter in editableExtensions. They are co-located in editor-core.ts and both re-exported.
preprocessMarkdown canonical version uses newlines + trim. The source implementation (`$$\n${body.trim()}\n$$`) is correct for KaTeX display math rendering. The test's version and the review file's copy (both no-newlines, no-trim) are updated to use the canonical import. The test assertions must change to match.
RENDERABLE_EXTENSIONS lives in markdown-utils.ts. This constant is consumed by Slices 2, 3, and 5. Defining it once here avoids duplication and gives future slices a single import.
Constraints & Invariants
- Zero behavior change to the Files Changed tab — this is a pure extraction
- No new dependencies added to
session-ui - All three
preprocessMarkdowncall sites use the single shared export after this slice - The
externalUpdateannotation is available fromeditor-core.tsfor any future editor consumer
Prior Art
editable-diff-view-core.ts— the extraction source (functions at lines ~77, ~105, ~220, ~245, ~527;externalUpdateat line ~46)session-preview-tab.tsxline 36,session-review-file-preview-v2.tsxline 39,markdown_preview.test.tsline 17 — the threepreprocessMarkdowncopies
Source
Part of #912
Activity
jeonghun-jj-lee commentedon Sep 9, 2026
Superseded by #931 (Preview as sidebar companion). The Finder-based design is replaced by the reactive companion model — sidebar drives file selection, Preview is a pure viewer.
test: update markdown_preview assertions to canonical preprocessMarkd…
Preview as sidebar companion — extension-side changes (#931) (#936)