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
2 changes: 1 addition & 1 deletion docs/todo/save-light-touch.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Working notes for Light Touch behavior in `src/renderer/src/store/editor.js`.
- Baseline advances to the last saved payload when tracked via `pendingSavedMarkdown` (manual/auto saves to existing paths).

## Known tradeoffs (accepted for now)
- Aggressive normalization: intentional multiple blank lines can be collapsed when nearby edits occur.
- ~~Aggressive normalization: intentional multiple blank lines can be collapsed when nearby edits occur.~~ (FIXED: merge now preserves original blank line counts)
- Line-oriented LCS can misalign within fenced code, tables, or reordered lists because block types are ignored.

## Test coverage to add
Expand Down
58 changes: 41 additions & 17 deletions src/renderer/src/store/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -1602,18 +1602,28 @@ const mergeWithOriginal = (regenerated, original) => {
let prevRegen = -1

for (const { orig: oi, regen: rj } of matches) {
// Anything inserted between previous regen match and this regen match
const inserted = regenLines.slice(prevRegen + 1, rj)
if (inserted.length) {
const onlyBlank = inserted.every((l) => normalizeLine(l) === '')
const origGap = oi - prevOrig - 1 // lines between previous orig match and this one
// If original lines were adjacent (no gap), drop purely blank insertions
if (!(onlyBlank && origGap === 0)) {
// If no orig gap, strip blank lines that piggyback on edits
const toInsert = origGap === 0 ? inserted.filter((l) => normalizeLine(l) !== '') : inserted
if (toInsert.length) {
resultLines.push(...toInsert)
}
// Lines from original in the gap (blank lines we want to preserve)
const origGapLines = origLines.slice(prevOrig + 1, oi)
// Lines from regenerated in the gap (may include new content)
const regenGapLines = regenLines.slice(prevRegen + 1, rj)

if (origGapLines.length > 0) {
// Original had lines in this gap
const newContent = regenGapLines.filter((l) => normalizeLine(l) !== '')

if (newContent.length > 0) {
// New content is being inserted - use Muya's spacing since structure changed
resultLines.push(...regenGapLines)
} else {
// No new content - preserve original gap lines exactly (keeps double blanks)
resultLines.push(...origGapLines)
}
} else if (regenGapLines.length > 0) {
// Original had no gap but regen does - this is purely new content
// Strip blank-only insertions to avoid adding unwanted spacing
const onlyBlank = regenGapLines.every((l) => normalizeLine(l) === '')
if (!onlyBlank) {
resultLines.push(...regenGapLines.filter((l) => normalizeLine(l) !== ''))
}
}

Expand All @@ -1623,12 +1633,26 @@ const mergeWithOriginal = (regenerated, original) => {
prevRegen = rj
}

// Handle tail insertions after the last match
if (prevRegen < regenLines.length - 1) {
const tail = regenLines.slice(prevRegen + 1)
const onlyBlank = tail.every((l) => normalizeLine(l) === '')
// Handle tail after the last match
const origTail = origLines.slice(prevOrig + 1)
const regenTail = regenLines.slice(prevRegen + 1)

if (origTail.length > 0) {
// Original had lines after last match
const newContent = regenTail.filter((l) => normalizeLine(l) !== '')

if (newContent.length > 0) {
// New content at end - use Muya's spacing since structure changed
resultLines.push(...regenTail)
} else {
// No new content - preserve original tail exactly
resultLines.push(...origTail)
}
} else if (regenTail.length > 0) {
// Only regen has tail lines - add non-blank content only
const onlyBlank = regenTail.every((l) => normalizeLine(l) === '')
if (!onlyBlank) {
resultLines.push(...tail.filter((l) => normalizeLine(l) !== ''))
resultLines.push(...regenTail.filter((l) => normalizeLine(l) !== ''))
}
// If only blank, rely on original trailing newlines preservation below
}
Expand Down
Loading