Skip to content

fix(capture): match multi-line "Insert after" on the inline path (#468)#1370

Merged
chhoumann merged 1 commit into
masterfrom
chhoumann/468-multiline-insert-after-match
Jun 16, 2026
Merged

fix(capture): match multi-line "Insert after" on the inline path (#468)#1370
chhoumann merged 1 commit into
masterfrom
chhoumann/468-multiline-insert-after-match

Conversation

@chhoumann

@chhoumann chhoumann commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Closes #468.

TL;DR

Issue #468 ("Multiline match for Insert After") asked for an Insert-after target spanning multiple lines to match. The default (block) placement already does this — it was fixed by #1333 (it expands \n escapes and matches a multi-line block via findMultiLineRange). This PR closes the one remaining gap: the inline insertion path reproduced the exact #468 symptom (and worse).

The bug (inline insert-after + multi-line target)

With Inline insertion toggled on and a \n target (e.g. **Today**\n***), the inline branch resolved the target without expanding escapes (captureChoiceFormatter.ts — the block path right below it does expand). So:

  • the single-line guard (hasInlineTargetLinebreak, which checks for a real newline) never fired;
  • fileContent.indexOf("**Today**\n***") searched for the literal backslash-n → never present → silent never-match (Create line if not found off), or a garbage line containing a literal \n written into the note (Create line if not found on);
  • meanwhile the settings preview expands \n, so the UI showed a valid multi-line block while runtime silently failed — precisely "rendered multi-line in the preview… the match is never successful."

Fix

  1. Engine — the inline branch now expandFormatTemplateEscapes(after) before searching, symmetric with the block path. A \n target becomes a real newline and trips the existing single-line guard.
  2. Honest abort — that guard now throws ChoiceAbortError (parity with the block path's not-found abort) instead of reportError() + returning unchanged content. The old path let the engine write the (unchanged) file and show a "Captured to X" success notice alongside the error — contradictory. Now the capture aborts cleanly with one clear message and nothing is written.
  3. Builder warning — when inline mode has a target that resolves to more than one line, a warning appears under the Inline toggle. It's computed with the same FormatDisplayFormatter the live preview uses (not a raw regex), so it doesn't false-warn on an escaped \\n and doesn't miss a token/global-var that expands to a newline.
  4. Docs — note that Inline insertion is single-line by design (multi-line \n anchors are for the default placement).

Inline insertion is single-line by definition (it inserts mid-line, immediately after the matched substring), so this is an honest error, not a regression — there is no sensible "insert after a multi-line anchor, on the same line." Escapes are now consistent across both insert-after paths: \n means newline; a literal backslash is \\.

Tests

  • New src/formatters/captureChoiceFormatter-468-inline-multiline.test.ts — 7 tests. The two core ones are RED without the engine fix (the create-on case writes the literal-\n garbage; the no-create case throws "not found"). Boundary controls pin the escape semantics: an escaped \\ stays a literal backslash and still inserts; a C:\notes-style target aborts (because \n is a newline by QuickAdd convention); a global-var that expands to a newline aborts (guard runs after expansion).
  • Updated the one frontmatter test that asserted the old log-and-continue behavior.
  • Full suite: 2435 passing, 0 failing; tsc, esbuild, svelte-check, eslint all clean.

Verified end-to-end

In an isolated Obsidian vault (provision:e2e-vault + obsidian:e2e):

Review

Ultracode design review (3 lenses) + 2 adversarial Codex reviewers (Skeptic + Architect). Their main actionable point — the builder warning's raw-regex drifting from the runtime semantic — is addressed in (3) above. The "literal-backslash reinterpretation" they flagged is the intentional, now-tested consistent semantic (the block path has treated \n as a newline since #1333; no escape pattern can distinguish **Today**\n*** from C:\notes, so matching the block behavior is the correct choice).

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Inline insertion now properly rejects multi-line targets with a clear error message instead of silently failing.
  • Documentation

    • Clarified that inline insertion mode requires single-line targets; multi-line anchors must use default placement instead.
  • Tests

    • Added comprehensive test coverage for multi-line target validation in inline insertion mode.

…d of silently missing (#468)

Issue #468 asked for multi-line "Insert after" matching. The default
(block) path was already fixed in #1333; the inline insert-after path was
the remaining gap. It skipped escape expansion, so a multi-line `\n`
target silently never matched (Create line if not found off) or wrote a
literal backslash-n into the note (Create line if not found on) — while
the settings preview expanded `\n` and made the target look valid.

- Expand `\n` escapes on the inline target before searching, symmetric
  with the block path, so a multi-line target trips the existing
  single-line guard.
- That guard now throws ChoiceAbortError (parity with the block path's
  not-found abort) instead of logging and returning unchanged content,
  which previously produced a contradictory "Captured" success notice.
- Warn in the Capture builder when inline mode has a target that resolves
  to more than one line, computed with the same FormatDisplayFormatter the
  live preview uses (no raw-regex drift on escaped `\\n` or token/global
  expansions).
- Tests: new captureChoiceFormatter-468-inline-multiline.test.ts (RED
  without the fix) plus a backslash-semantics boundary control; update the
  one frontmatter test that asserted the old log-and-continue behavior.
- Docs: note that Inline insertion is single-line by design.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying quickadd with  Cloudflare Pages  Cloudflare Pages

Latest commit: 97228d1
Status: ✅  Deploy successful!
Preview URL: https://e49a132a.quickadd.pages.dev
Branch Preview URL: https://chhoumann-468-multiline-inse.quickadd.pages.dev

View logs

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c6acbdd3-a4b4-41ee-9146-b8882863bc6e

📥 Commits

Reviewing files that changed from the base of the PR and between 7b61d91 and 97228d1.

📒 Files selected for processing (5)
  • docs/docs/Choices/CaptureChoice.md
  • src/formatters/captureChoiceFormatter-468-inline-multiline.test.ts
  • src/formatters/captureChoiceFormatter-frontmatter.test.ts
  • src/formatters/captureChoiceFormatter.ts
  • src/gui/ChoiceBuilder/components/InsertAfterFields.svelte

📝 Walkthrough

Walkthrough

Inline insert-after now rejects multi-line targets by throwing a ChoiceAbortError instead of silently failing. Format-template escapes are expanded before the single-line guard runs. The InsertAfterFields.svelte UI shows a reactive warning when the resolved target contains a newline. A new test suite covers issue #468 edge cases, an existing test is updated, and documentation is extended.

Changes

Inline insert-after multi-line guard (issue #468)

Layer / File(s) Summary
Formatter: escape expansion + ChoiceAbortError
src/formatters/captureChoiceFormatter.ts
Swaps reportError import for ChoiceAbortError; expands \n escapes on the inline target via expandFormatTemplateEscapes before the single-line guard; throws ChoiceAbortError with a descriptive message when the resolved target contains line breaks.
UI reactive multi-line warning
src/gui/ChoiceBuilder/components/InsertAfterFields.svelte
Imports FormatDisplayFormatter, adds inlineTargetHasLinebreak state, and uses an async $effect to detect resolved newlines in the inline target; renders a conditional warning block in the template.
Tests and documentation
src/formatters/captureChoiceFormatter-468-inline-multiline.test.ts, src/formatters/captureChoiceFormatter-frontmatter.test.ts, docs/docs/Choices/CaptureChoice.md
New Vitest suite for #468 covering abort on multi-line, createIfNotFound ordering, single-line control, escaped backslashes, Windows-path \n, and post-expansion token rejection. Existing frontmatter test updated to expect a rejected promise. Docs extended to describe single-line requirement for inline insertion.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • chhoumann/quickadd#1348: Directly modifies the same inline insert-after path in captureChoiceFormatter.ts, changing path selection when using the runtime formatter override.
  • chhoumann/quickadd#1063: Introduces the original inline insert-after handling and single-line enforcement that this PR further refines for the multi-line \n target case.
  • chhoumann/quickadd#1333: Also modifies how escaped \n values in insert-after targets are expanded and validated, overlapping with the escape-expansion logic added here.

Suggested labels

released

🐇 A rabbit hops through lines of code,
Where \n once caused a silent mode,
Now inline targets must stay flat and true,
A warning blooms in the Svelte UI view,
The formatter throws, the tests all cheer—
No more garbage writes, the path is clear! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(capture): match multi-line "Insert after" on the inline path (#468)' accurately describes the main change—enabling multi-line matching in inline insertion by expanding escape sequences, directly addressing issue #468.
Linked Issues check ✅ Passed The PR fully addresses the objective in issue #468 by expanding escape sequences on the inline path, enabling multi-line target matching consistent with the settings preview, and adding proper error handling and user warnings.
Out of Scope Changes check ✅ Passed All changes directly support fixing inline multi-line matching: escape expansion in the formatter, error handling via ChoiceAbortError, UI warning in InsertAfterFields, documentation clarification, and comprehensive test coverage.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chhoumann/468-multiline-insert-after-match

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chhoumann chhoumann merged commit 076d54b into master Jun 16, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE REQUEST] Multiline match for "Insert After"

1 participant