Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Added

- **Hybrid Markdown editing** ([#460](https://github.com/raiseCatError/notMyShell/issues/460)). **F3** in a Markdown document (or `H` from the read-only views) shows it *rendered* — headings, emphasis, links, lists, tables, quotes, code — except for the block your caret (or selection) is in, which shows its exact Markdown source and is fully editable. Move on and it renders again. It is another presentation of the same buffer: every key is the editor's (letters always type; snippets, list/table helpers, undo/redo, hunk review, recovery drafts and Save As all work as in the source editor), the caret lives in source positions, and switching views never changes the text. The smallest safe block is revealed — the whole list for a nested item, the whole table, the whole fence — and a selection shows every block it touches as source. The view is anchored to a source line, so revealing a block does not move what is above it. F3 again returns to the source editor; in the split view (F2) F3 switches the text pane between source and hybrid. Limits: Markdown files only (not HTML); images appear as `[image: alt]`; Up/Down move by source line; pointer input is not handled.
- **Problems: offline static diagnostics** ([#466](https://github.com/raiseCatError/notMyShell/issues/466)). In a Markdown, HTML or CSS document, **F1 then `e`** (the snippet palette's *Problems…* in HTML files; **F1** in a CSS file; **`P`** in the read-only views and the split's preview pane) lists what is wrong: ✖ errors, ▲ warnings, ℹ notes and `?` things that cannot be checked. Markdown: links to files that do not exist, `#fragments` with no heading or id, missing images, images without alt text, undefined `[text][ref]` references and footnotes, unused footnotes, repeated headings. HTML: missing images, stylesheets and scripts, `<img>` without `alt`, form controls without a label, duplicate ids, unresolved `#fragments`, unclosed or unexpected tags. CSS: missing `url()` assets and unbalanced braces. Type to search, Tab filters (all, problems, errors), Enter jumps to the exact text and selects it (Back returns), Del dismisses one, Ctrl+R checks again. Checking starts when you first open Problems, follows the text (typing, undo, snippets, restored drafts, a merge) after a short pause, drops results for text that has since changed, and counts show in the editor's status row. Everything is offline: external URLs are counted, never fetched; no script, style or command is run; files are only looked at (never read except another Markdown file's headings, 256 KiB at most) and only inside the document's project (a path that leaves it, by `..` or a symlink, is reported as not checked); nothing is written. Browser-console diagnostics are a later, separate step.
- **Footnote renumbering** ([#463](https://github.com/raiseCatError/notMyShell/issues/463)). *Renumber footnotes* in the snippet palette (F1, then `/` in a Markdown file) numbers the footnotes 1, 2, 3… in the order they are first referenced and updates each definition to match, as one undo step. Named footnotes (`[^note]`), escaped references, code spans and fenced code are left alone; a definition nobody references keeps its number unless a renumbered footnote needs it.
- **Split view for Markdown and HTML documents** ([#461](https://github.com/raiseCatError/notMyShell/issues/461)). **F2** (or `s` in the read-only views) in the document workspace shows the editor beside NMSh's own preview of the *same* buffer: the text on the left, the rendered document on the right, updated as you type, without saving. The preview follows the caret to its block (`l` in the preview pane turns that off), **Ctrl+O** moves between the panes, `x` swaps the sides and `<` `>` change their widths (30–70%). Only the text pane is editable; keys typed while the preview has the focus never reach the text. The preview pane has its own find (`/`) and heading prompt (`#`). Below 100 columns only the focused pane is shown at full width, and widening the terminal brings the split back. Esc leaves for the read-only source view with your unsaved text kept; F2 again returns to editing. The browser-quality preview is not used in the split; the pane is NMSh's renderer. Mouse input in the split is not handled yet.
- **Heading navigation** ([#462](https://github.com/raiseCatError/notMyShell/issues/462), first slice). In a Markdown or HTML document, **`#`** in the viewer or workspace opens a heading prompt: type to narrow, Up/Down choose, Enter jumps (source or rendered view, any width) and **Backspace** goes back to where you were. In the editor, F1 then `h` (or *Go to heading…* in the snippet palette) lists the headings with their depth; `j` / *Back* returns to the caret position you left, even after edits. `/view README.md#install` opens the file at that heading. Anchors follow GitHub's rules (lower-case, punctuation dropped, `-1`, `-2` for repeats; raw HTML headings listed without an anchor); Jekyll/Kramdown ids are different and are not implemented (see the [architecture note](docs/architecture/document-source-map.md)). Underneath, every parsed Markdown block now knows its source lines and every rendered row its block's line, the shared map the coming split view and hybrid editing build on.
Expand Down
13 changes: 13 additions & 0 deletions docs/design/document-workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ Limits: code fences are recognised by a line scan (indented code blocks and fenc

**Verified by** `tests/markdownEdit.test.ts` (each helper: empty and multi-line selections, nested and mixed lists, quotes, fences, Unicode, very long lines, one undo step, restored drafts) and `tests/markdownEditorKeys.test.ts` (keys, menu at 30–120 columns, non-Markdown files unchanged, CRLF saved as CRLF). Physical Ghostty/Zed: NOT RUN.

## Problems (static diagnostics)

`src/markdown/diagnostics.ts` (engine), `src/viewer/problems.ts` (runner) and the *problems* dialog of `EditorPanel.ts` ([#466](https://github.com/raiseCatError/notMyShell/issues/466)). Reuses `parseBlockLines` (code blocks are skipped through the block spans), `headingsFromLines` and `resolveFragment`; no second parser, no language server.

- **Severities:** `error` (certainly broken: a file that is not there, an undefined reference/footnote/id), `warning` (likely: a missing alt text, an unclosed tag, a fragment other generators might satisfy — a document with raw `id=`/`{#…}` ids gets warnings instead of errors), `info` (a repeated heading), `unverified` (not checked, not claimed wrong: absolute and `~` paths, a path outside the project, a templated attribute, a relative file in a document with no folder yet). External URLs (`http`, `mailto`, `//`, any other scheme) are only counted. `javascript:`, `vbscript:`, `file:` and non-image `data:` links are reported as never followed.
- **Positions:** every finding has a 0-based line and, when it names exact text (a link destination, an attribute value, an id), UTF-16 columns; Enter selects that text. Without a span the caret goes to the start of the line and nothing pretends otherwise.
- **Filesystem:** only through `LocalFs`, created per run for the document's folder with the project root (`documentRoot`: the git project within a dozen levels, else the folder). A path is lexically resolved, then `realpath`ed, and must stay inside the real root; for a missing path the deepest existing ancestor is checked, so a symlinked directory cannot be used to probe outside. Only `lstat` and one bounded read of another Markdown file (headings only). At most 400 distinct paths per run; at most 500 findings; HTML over 1.5 MB is skipped and marked truncated; messages never name a path the document did not itself write.
- **Currency:** checking is off until Problems is first opened. Then `ProblemsRunner` observes the buffer: each change bumps a revision and schedules a run (500 ms); a run snapshots the lines, aborts any run in flight, and its result is dropped if the revision moved. Opening Problems, Ctrl+R, a save and a Save As re-check (files the document names may have changed; no watchers). The runner is disposed with the editor, on reload and on exit, so no timer or observer outlives the document.
- **Surface:** the dialog lists findings by severity then line with counts and the number of external links not checked; Tab cycles all / problems / errors, typing filters on the message, Del dismisses (until the next report), Esc leaves. In source and preview a jump also scrolls the read-only view to the line; hybrid and the split follow the caret.
- **Independent review (opus subagent, security focus) and what changed:** (1–3) a dangling symlink, or a symlink to a folder this user cannot read, was told apart from other links outside the root (it leaked whether the outside target exists) and `readText` could be raced into following a link or blocking on a FIFO — the path is now walked component by component from the root, each link resolved (even dangling ones, via `readlink`) and confined before the walk continues, and the read opens with `O_NOFOLLOW|O_NONBLOCK`, `fstat`s a regular file and re-checks the real path; (4) heading checks in another file read it once per path and count against a bound; (5) quadratic regexes on hostile lines (80k characters took 17–38 s) — every quantifier is bounded, lines over 20,000 characters are scanned only that far and say so, and CSS is read by a linear scanner; (6) readers of reload, plain Save As-and-close now release the runner; (7) a failing checker no longer throws into the editor; (8–10) false positives and negatives: HTML comments and code spans across lines, TOML front matter, definitions on the next line or in quotes, escaped destinations, `url()` in CSS comments and strings, `url(#id)` checked against ids in HTML, `<base href>`, ids inside `<template>`, the first of duplicate attributes, an undefined `[text][ref]` (CommonMark shows it as text) is only information; the outer link of a badge, nested brackets, inline `<img>` and `@import` are now checked; (11–12) the `image-alt` span is the image's own text and a value spanning lines is not an exact span; (13) the list focus stays on a row when a new report is shorter.
- **Not provided:** a gutter marker in the text, checks of other languages, CSS property validation, link fragments inside another HTML file, following redirects or fetching anything, quick fixes, and the browser console (a separate, gated slice).
- **Verified by** `tests/diagnostics.test.ts` (each check, hostile paths and symlinks, the filesystem checker, no-folder documents, Unicode and stray CR, HTML and CSS, false-positive stress, bounds) and `tests/problems.test.ts` (runner staleness and disposal, the surface, filters, dismiss, refresh, widths/NO_COLOR/Safe Glyphs, and every mode: source, preview, hybrid, split, edit).

## Hybrid view

`DocumentMode` gains `'hybrid'` (#460), implemented in `src/viewer/HybridView.ts` over the shared source map (`docs/architecture/document-source-map.md`). It is a presentation of the one `TextBuffer`; there is no second editor and no second document.
Expand Down
2 changes: 2 additions & 0 deletions docs/development/v024-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ The paused issues #460–#469 are the milestone (the maintainer superseded the e
8. **#460: hybrid Markdown editing** — branch `feature/v024-hybrid` (from `dev` after #489–#496 merged). Done: hybrid mode, items from the source map, active-block raw editing, anchored viewport, split text-pane toggle, tests, independent review (see its section). **#460 remaining:** images in place, visual-line movement, pointer input, tables as a grid, HTML. **#461** still lacks pointer input, preview→caret sync, vertical orientation and the Chromium preview; **#463** footnote renumbering; **#466**, **#462** (details/Mermaid/math), **#464/#465/#467** not started.
9. **#463: footnote renumbering** — branch `feature/v024-footnotes`, from `dev`. Done (tests in `footnotes.test.ts`). **#463 acceptance:** every implemented item is covered by automated tests; the only open requirement is the physical Ghostty/Zed pass (NOT RUN), so the issue stays open.

10. **#466: offline static diagnostics** — branch `feature/v024-diagnostics`, from `dev`. Done: engine, runner, Problems surface in all modes, tests, independent review (see its section in the design doc). **#466 remaining:** the optional browser console for trusted previews (separate gated slice, nothing started), a gutter marker, further languages. **#462 next:** `<details>` disclosure, then Mermaid and math (separate slices).

## Environment notes

Scratch and test runs: `t7run`; focused tests via `/Volumes/T7Tmp/ai-dev/runtests.mjs` (see the testing-gotchas memory). `npm ci` was needed in a fresh worktree (the main checkout's `node_modules` is stale).
6 changes: 6 additions & 0 deletions docs/testing/v024-editor-physical-qa.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ Automated tests cover the logic headlessly. Everything below is **NOT RUN** unti
- [ ] Mermaid and math entries say they are source text; nothing in the preview claims to render them.
- [ ] The palette rows and footer fit 30, 50, 80 and 120 columns; NO_COLOR and Safe Glyphs stay legible.

## Problems (#466)
- [ ] F1 then `e` in a Markdown file with a broken link, a missing image and a bad `#fragment`: the list shows them; Enter selects the exact text; Back returns. `P` in the read-only views and in the split's preview pane.
- [ ] An HTML file (palette → Problems) and a CSS file (F1); the status row counts; fixing a finding removes it after a moment; undo brings it back.
- [ ] A symlink out of the project and `/etc/passwd`-style paths are reported as not checked; an external URL is never fetched (watch the network).
- [ ] 30, 50, 80 and 120 columns; NO_COLOR; Safe Glyphs (E/W/i/?).

## Hybrid view (#460)
- [ ] Open a Markdown file, F3 (is F3 delivered by the terminal and by Zed?): headings, bold, links, lists, tables, quotes and fences render; the block under the caret shows its source; moving with the arrows swaps blocks without the screen jumping.
- [ ] Type in every kind of block; select across blocks with Shift+Down (both show source); undo/redo; insert a snippet and Tab through it.
Expand Down
Loading
Loading