Skip to content

Enable terminal reflow and join continuation lines in Normal mode#19863

Closed
mattn wants to merge 11 commits intovim:masterfrom
mattn:enable-terminal-reflow
Closed

Enable terminal reflow and join continuation lines in Normal mode#19863
mattn wants to merge 11 commits intovim:masterfrom
mattn:enable-terminal-reflow

Conversation

@mattn
Copy link
Copy Markdown
Member

@mattn mattn commented Mar 30, 2026

Enable vterm_screen_enable_reflow() so that long lines in a terminal window reflow (re-wrap) when the terminal is resized. This function has been available in libvterm since patch 9.0.0774 (6a12d26) but was never called from Vim.

Additionally, when switching to Terminal-Normal mode, soft-wrapped (continuation) lines are now joined into single buffer lines using libvterm's VTermLineInfo continuation flag. This means:

  • Long lines (e.g. file paths) can be yanked without embedded newlines
  • :set number no longer wastes vertical space on wrapped fragments
  • Buffer content in Terminal-Normal mode represents logical lines

Fixes #2865

2026-03-30.214047.mp4

This PR was created with the assistance of Claude Code.

Enable vterm_screen_enable_reflow() so that long lines in a terminal
window reflow (re-wrap) when the terminal is resized, instead of being
truncated or leaving stale wrapped fragments.

Fixes vim#2865
When switching to Terminal-Normal mode, use libvterm's VTermLineInfo
continuation flag to join soft-wrapped lines into single buffer lines.
This allows users to yank long lines (e.g. file paths) without embedded
newlines, and makes :set number less wasteful of vertical space.

Cursor position in Terminal-Normal mode is adjusted to account for the
joined continuation lines.
@mattn mattn changed the title Enable terminal reflow on resize Enable terminal reflow and join continuation lines in Normal mode Mar 30, 2026
The shell prompt varies across platforms (e.g. "sh-3.2$ " on macOS),
so the reflowed line may not always be on row 2. Search all rows
instead.
@Cimbali
Copy link
Copy Markdown
Contributor

Cimbali commented Mar 30, 2026

This is nice but still missing the bit that also unwraps lines that have been scrolled out of the current viewport:

image

I am now at line 30 so line 18 reflowed nicely, but line 1 that wasn’t on-screen as the switch happened (already pushed into the scrollback buffer) is broken.

Also join continuation lines that are pushed into the scrollback buffer
(lines scrolled off the top of the terminal screen), not just lines in
the snapshot. This uses a new vterm_screen_sb_pushline_continuation()
accessor that exposes the continuation flag of the line being pushed via
the sb_pushline callback.

Fix reflow tests to search all terminal rows instead of hardcoding
row numbers, since shell prompts vary across platforms (e.g. macOS).
Fix Test_term_getpos to account for joined continuation lines.
@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 30, 2026

@Cimbali Thanks for testing! I just pushed a new commit that also joins continuation lines in the scrollback buffer (lines pushed off the top of the screen). This adds a vterm_screen_sb_pushline_continuation() accessor to libvterm so that handle_pushline can detect and join continuation lines when they're scrolled out of the viewport. Please try again with the latest commit.

@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 30, 2026

I'll be looking for corner case bugs for a while, so it might not work for a short time. but I'll fix this soon.

mattn added 6 commits March 30, 2026 22:30
In state.c's scroll(), the lineinfo array is memmoved BEFORE the
scrollrect callback fires, so by the time sb_pushline_from_row() runs,
lineinfo[0] already holds the old row 1's info.  Fix this by saving
the continuation flag after each scroll for use on the NEXT push:
after a scroll-by-1, lineinfo[0] tells whether the next row to be
pushed will be a continuation.

For resize pushlines, use new_lineinfo directly since it is built by
the reflow process with correct continuation flags.
Wait for the job to become "dead" before reading exitval.  Without
this, the test can read exitval as 0 if the python process hasn't
fully exited yet.  Also fix the same issue in Test_terminal_duplicate_eof_arg.
Use 'printf '%s' ...' instead of 'printf '...'' to avoid relying on
the shell's printf handling of UTF-8 characters directly in the format
string, which may not work on FreeBSD.
Use 'echo -n' instead of 'printf '%s'' with single-quoted multibyte
text.  On macOS, /bin/sh (zsh) can break single quotes at multi-byte
character boundaries.
Outputting CJK characters via shell commands is unreliable across
platforms (macOS zsh, FreeBSD sh).  The ASCII reflow tests and the
normal-mode reflow test provide sufficient coverage.
@mattn mattn force-pushed the enable-terminal-reflow branch from febdb03 to 94f0775 Compare March 30, 2026 15:04
On slower CI systems (FreeBSD), a single TermWait() may not be enough
for printf output to appear.  Use WaitForAssert() to wait for the
expected output before checking the wrap or switching mode.
@chrisbra
Copy link
Copy Markdown
Member

chrisbra commented Apr 7, 2026

How does this differ from #8365 ?

@mattn
Copy link
Copy Markdown
Member Author

mattn commented Apr 7, 2026

@chrisbra
I asked Claude Code about it. I haven’t verified whether the findings are correct.


PR #8365 vs PR #19863 Comparison

Both PRs fix the same issue #2865 — joining soft-wrapped (continuation) lines in the terminal buffer into single lines when switching to Normal mode.

Approach Differences

#8365 (Cimbali) #19863 (mattn)
Started June 2021 March 2026
libvterm changes New sb_pushline4 callback + premove callback (coordinated with upstream author leonerd) New vterm_screen_sb_pushline_continuation() accessor function
ABI compatibility Adds sb_pushline4 while keeping old sb_pushline (ABI-compatible) Calls vterm_screen_sb_pushline_continuation() from within existing sb_pushline callback
Reflow support None (explicitly states resize reflow is not handled) Enables vterm_screen_enable_reflow() (re-wraps on resize)
Files changed 13 files 6 files
Upstream coordination leonerd implemented in upstream libvterm (rev 843) in July 2024 No upstream coordination (custom extension)
Tests libvterm tests + Vim tests Vim tests only

#8365 Strengths and Weaknesses

Strengths:

  • Coordinated with upstream libvterm (leonerd), already merged as rev 843
  • premove callback provides accurate continuation info when lines scroll out of the viewport
  • Includes libvterm-level tests
  • scrollbackline_pos_in_buf() / bufline_pos_in_scrollback() provide bidirectional mapping so term_getline(), term_scrape(), term_get_attr() etc. work correctly with joined lines

Weaknesses:

  • PR spans 5 years with complex code (large changeset across 13 files)
  • Does not support reflow (re-wrapping on terminal resize)
  • Must skip tests on Windows because cmd.exe does not emit continuation marks

#19863 Strengths and Weaknesses

Strengths:

  • Simpler code (6 files, smaller changeset)
  • Supports reflow on resize via vterm_screen_enable_reflow()
  • Clean, modern implementation

Weaknesses:

  • No upstream libvterm coordination — adds a custom sb_pushline_continuation flag. Since Unwrap terminal buffer #8365 already has an official upstream API (sb_pushline4) implemented by leonerd, this custom extension will conflict when syncing with upstream libvterm in the future
  • Scrollback handling may be incomplete — Cimbali pointed out in comments that lines already scrolled out of the viewport were not being joined. A follow-up commit addressed this, but Unwrap terminal buffer #8365 more comprehensively fixes term_getline(), term_scrape(), term_get_attr() and other functions that need to account for the line number offset caused by joining
  • term_getline() and term_scrape() fixes may be missingUnwrap terminal buffer #8365 uses scrollback-to-buffer mapping functions throughout multiple call sites, while Enable terminal reflow and join continuation lines in Normal mode #19863's coverage of these edge cases appears more limited

Overall Assessment

From a practical standpoint, #19863 is attractive for its simplicity and reflow support. However, from an upstream compatibility standpoint, #8365 has a clear advantage since leonerd already implemented the sb_pushline4 API in upstream libvterm. The custom extension in #19863 will cause issues when syncing Vim's libvterm fork with upstream in the future.

Ideally, the best approach would be to use #8365's upstream-coordinated libvterm changes as the base and combine them with #19863's reflow enablement. chrisbra also asked in #19863 "How does this differ from #8365?", indicating that reconciliation between the two PRs is needed.

@chrisbra
Copy link
Copy Markdown
Member

chrisbra commented Apr 9, 2026

Okay, then let's go with #8365 approach if this is also in libvterm already.

@chrisbra chrisbra closed this in e29f33e Apr 10, 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.

Wrap lines in vim in an active terminal session

3 participants