Skip to content

Break one line, not two, when Return lands on a blank line - #12

Open
rodgco wants to merge 2 commits into
omacom-io:masterfrom
rodgco:fix/return-on-blank-line
Open

Break one line, not two, when Return lands on a blank line#12
rodgco wants to merge 2 commits into
omacom-io:masterfrom
rodgco:fix/return-on-blank-line

Conversation

@rodgco

@rodgco rodgco commented Aug 16, 2026

Copy link
Copy Markdown

Fixes #11.

smartReturn ends a paragraph with two breaks, which is right for a paragraph: a new one stands apart from the one above it by a blank line, so Return at the end of two correctly gives two\n\n. A line that is already blank has no paragraph to stand apart from, so that second break was a gap nobody asked for — every Return on a blank line grew the space in twos, and an empty document opened with two blank lines rather than one.

The fallback now inserts a single break when there is nothing but whitespace on either side of the caret on its line. The list-item and code-fence branches above it already inserted one break each and are untouched.

Test

breaksLinesOnReturn drives a real window with the keyboard, covering both the bug and the branches that must not move:

Start (caret) Return Result
one\n\ntwo (on the blank line) ×1 one\n\n\ntwo
one\n\ntwo (on the blank line) ×2 one\n\n\n\ntwo
one\n\ntwo (end of two) ×1 one\n\ntwo\n\n
`` (empty document) ×1 \n
one\n \ntwo (between the spaces) ×1 one\n \n \ntwo
- item ×1, then ×2 - item\n- , then - item\n\n
inside a ``` fence ×1, then ×2 one break each

make && ./tst_omawrite in build-tests: 13 passed, 0 failed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TyQRJCyR76uk7XaNAB8jMC

rodgco and others added 2 commits August 16, 2026 11:03
smartReturn ends a paragraph with two breaks because a new paragraph in
this editor stands apart from the one above it by a blank line. A line
that is already blank has no paragraph to stand apart from, so that
second break was a gap nobody asked for: every Return on a blank line
grew the space in twos, an empty document included.

Fall back to a single break when there is nothing but whitespace on
either side of the caret on its line. The list and code fence branches
above already inserted one break each and are untouched.

Fixes omacom-io#11

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TyQRJCyR76uk7XaNAB8jMC
The new branch reads the line around cursorPosition, but a selection is deleted before the break goes in, and dragged right to left it leaves the caret at the far end of it. Selecting "\ntw" in "one\n\ntwo" backwards therefore inserted one break where the identical selection made left to right inserted two: the caret's line was blank, but the line the break landed on was not.

Read the prefix from the start of the selection and the remainder from its end, so the test describes the line that survives it either way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@omarchybot

Copy link
Copy Markdown
Collaborator

Return followed by Backspace on a blank line now eats a paragraph break. In one\n\ntwo with the caret on the blank line at 4, Return correctly gives one\n\n\ntwo with the caret at 5 — but deleteParagraphBreakBehindCursor then sees text.slice(3, 5) === "\n\n" and removes both, leaving one\ntwo. One press to add the line, one press to take it back, and the separator that was there before you touched anything is gone. On master that pair round-tripped exactly, because the two-break Return left a \n\n that was entirely its own; an empty document shows the same shape, where two Returns give \n\n and one Backspace clears the document.

The helper collapses two breaks whenever they sit behind the caret, so with this change it can undo more than the Return that produced them. Telling the two apart wants both ends of the pair: a paragraph break is what Return inserts only when the line before the pair is not blank, and only when the caret's own line does not continue past it.

var pairStart = cursorPosition - 2;
var previous = text.slice(text.lastIndexOf("\n", pairStart - 1) + 1, pairStart);
if (/^\s*$/.test(previous) || text.slice(cursorPosition, cursorPosition + 1) === "\n")
    return false;

That is verified, not sketched — with it, Return then Backspace on the blank line returns to one\n\ntwo, two Returns and two Backspaces do too, an empty document goes \n\n then \n, and Backspace at the head of two in one\n\ntwo still joins the paragraphs to onetwo. I have not pushed it: it is behaviour in a function this PR does not touch, and where Backspace should stop is the maintainer's call rather than mine.

I did push df2f992, for the other thing. The new branch reads the line around cursorPosition, but replaceSelectionWith deletes the selection first, and a selection dragged right to left leaves the caret at its far end — so selecting \ntw in one\n\ntwo backwards inserted one break where the identical selection made left to right inserted two. It now reads the prefix from the start of the selection and the remainder from its end, so the answer no longer depends on which way you dragged. Your five documented cases have no selection and are unchanged.

Everything above was checked by driving the real key handler in a window on a throwaway VM. The suite is 13 passing on bin/test.

This was referenced Aug 20, 2026
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.

Return on a blank line inserts two line breaks instead of one

2 participants