feat: raw editor mode — plain textarea with frontmatter + wikilink autocomplete

Adds a third editor mode (alongside WYSIWYG and Diff) that shows the raw
markdown file in a monospaced textarea. Includes:

- useRawMode hook with derived state (no setState-in-effect) and onFlushPending
- RawEditorView: textarea with 500ms debounce, YAML error banner, wikilink
  autocomplete via [[  trigger, Cmd+S save
- BreadcrumbBar Code icon toggles raw mode; mutual exclusion with diff mode
- Command palette: "Toggle Raw Editor" (View group, requires active tab)
- useEditorModeExclusion hook extracted to keep Editor.tsx under complexity threshold
- buildViewCommands extracted from useCommandRegistry for same reason
- RawToggleButton and RawModeEditorSection components extracted for clean CC

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Test
2026-03-02 18:38:25 +01:00
parent f04dfdbd37
commit 185feb5a2c
14 changed files with 750 additions and 16 deletions

View File

@@ -156,6 +156,36 @@ describe('useCommandRegistry', () => {
expect(onTrashNote).toHaveBeenCalledWith('/vault/note/test.md')
})
it('has toggle-raw-editor command in View group', () => {
const { result } = renderHook(() => useCommandRegistry(makeConfig()))
const cmd = result.current.find(c => c.id === 'toggle-raw-editor')
expect(cmd).toBeDefined()
expect(cmd!.group).toBe('View')
})
it('disables toggle-raw-editor when no note is open', () => {
const { result } = renderHook(() => useCommandRegistry(makeConfig({ activeTabPath: null })))
const cmd = result.current.find(c => c.id === 'toggle-raw-editor')
expect(cmd!.enabled).toBe(false)
})
it('enables toggle-raw-editor when a note is open', () => {
const { result } = renderHook(() =>
useCommandRegistry(makeConfig({ activeTabPath: '/vault/note/test.md' })),
)
const cmd = result.current.find(c => c.id === 'toggle-raw-editor')
expect(cmd!.enabled).toBe(true)
})
it('calls onToggleRawEditor when toggle-raw-editor executes', () => {
const onToggleRawEditor = vi.fn()
const { result } = renderHook(() =>
useCommandRegistry(makeConfig({ activeTabPath: '/vault/note/test.md', onToggleRawEditor })),
)
result.current.find(c => c.id === 'toggle-raw-editor')!.execute()
expect(onToggleRawEditor).toHaveBeenCalledOnce()
})
it('disables commit when no modified files', () => {
const { result } = renderHook(() => useCommandRegistry(makeConfig({ modifiedCount: 0 })))
expect(result.current.find(c => c.id === 'commit-push')!.enabled).toBe(false)