diff --git a/src/threecode/minline.nim b/src/threecode/minline.nim index 9464108..291d28c 100755 --- a/src/threecode/minline.nim +++ b/src/threecode/minline.nim @@ -1533,10 +1533,20 @@ proc handleEscape*(ed: var LineEditor, c1: int): bool = if stars > 0: ed.write repeat('*', stars) else: + # Normalize line endings: `\r\n` -> `\n`, bare `\r` -> + # `\n`. A bare CR is itself a valid line separator (classic + # Mac, some terminals/clipboards), so stripping every `\r` + # would collapse a CR-separated paste into one line. var clean = newStringOfCap(paste.len) + var prev = '\0' for ch in paste: - if ch == '\r': discard - else: clean.add ch + if ch == '\r': + if prev != '\n': clean.add '\n' + elif ch == '\n': + if prev != '\r': clean.add '\n' + else: + clean.add ch + prev = ch ed.insertText(clean) return false if c3 == 51 and c4 == 59: diff --git a/tests/core/test_minline.nim b/tests/core/test_minline.nim index b2e2de7..32bb2d4 100644 --- a/tests/core/test_minline.nim +++ b/tests/core/test_minline.nim @@ -740,6 +740,29 @@ suite "minline editor: bracketed paste": check d.run(ed, prompt = "> ") == "line1\nline2" check ed.echoRows == 2 + test "paste with CRLF line endings keeps one break per line": + var ed = initEditor() + let d = newDriver() + d.push @[27, 91, 50, 48, 48, 126] + d.pushString "line1\r\nline2\r\nline3" + d.push @[27, 91, 50, 48, 49, 126] + d.push Enter + check d.run(ed, prompt = "> ") == "line1\nline2\nline3" + check ed.echoRows == 3 + + test "paste with bare-CR line endings keeps breaks (not collapsed)": + # Regression: a bracketed paste whose content uses bare CR (0x0D) as + # the line separator — classic Mac, some terminals/clipboards — used + # to collapse to one line because the clean step stripped every CR. + var ed = initEditor() + let d = newDriver() + d.push @[27, 91, 50, 48, 48, 126] + d.pushString "line1\rline2\rline3" + d.push @[27, 91, 50, 48, 49, 126] + d.push Enter + check d.run(ed, prompt = "> ") == "line1\nline2\nline3" + check ed.echoRows == 3 + test "hidechars: bracketed paste captures key, screen shows only `*`s": # Regression for the Ghostty-on-macOS auth-failure report. Pasting an # api key in hidden mode must: