Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add setting to enable reflow for the cursor line #5213

Open
jtbandes opened this issue Nov 15, 2024 · 7 comments
Open

Add setting to enable reflow for the cursor line #5213

jtbandes opened this issue Nov 15, 2024 · 7 comments
Labels
type/enhancement Features or improvements to existing features

Comments

@jtbandes
Copy link

jtbandes commented Nov 15, 2024

I'm trying to use xterm.js to make a log viewer (read-only, no keyboard input from the user).

I've used @xterm/addon-fit to handle resizing, and automatic line wrapping seems to work nicely. However, the very last line, i.e. the "current" line, is only wrapped based on the original width when the line is written, and doesn't re-wrap when the terminal is resized. When the terminal is sized down, it seems to delete some characters, and when the terminal is sized back up, those characters are permanently gone and it leaves a blank space on the right.

Note that I haven't included a \r\n on the last line, because I don't want a blank line to be displayed at the bottom of the terminal.

How can I make this last line automatically wrap when the terminal is resized?

Screen.Recording.2024-11-15.at.12.20.55.PM.mov

Details

  • Browser and browser version: Chrome 130.0.6723.117
  • OS version: macOS 15.1
  • xterm.js version: 5.5.0

Steps to reproduce

https://codesandbox.io/p/sandbox/xtermjs-test-7xvd9v

import "./styles.css";
import "@xterm/xterm/css/xterm.css";
import { Terminal } from "@xterm/xterm";
import { FitAddon } from "@xterm/addon-fit";

const container = document.getElementById("app");

const terminal = new Terminal({
  cursorStyle: "bar",
  allowProposedApi: true,
});

const fitAddon = new FitAddon();
terminal.loadAddon(fitAddon);

terminal.open(container);

for (let i = 0; i < 100; i++) {
  if (i > 0) {
    terminal.write("\r\n");
  }
  terminal.write(
    `line ${i}: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua`
  );
}

const resizeObserver = new ResizeObserver((_entries) => {
  fitAddon.fit();
});
resizeObserver.observe(container);
@jerch
Copy link
Member

jerch commented Nov 20, 2024

For a in-browser log viewer I suggest not to rely on the terminals scrollbuffer and its reflow caps, as thats heavily customized for shells (where the last line is the shell prompt, which is handled differently). Also the scrollbuffer is not editable itself.

Its better here to create a full-fledged log viewer app operating on the alternate buffer (similar to vim etc). With that you have full control over what is shown in terminal and implement your navigation independently of terminal semantics. All you need for this to work is:

  • your own data buffer
  • wcwidth to calc soft line breaks
  • create views into your buffer based on terminal size and wcwidth calcs
  • track view position and implement keyboard nav for page up/down etc.
  • bonus: register a resize handler at the terminal to update your data views accordingly

@Tyriar
Copy link
Member

Tyriar commented Nov 20, 2024

This is by design because of the customized for shells point from @jerch, we "reflow" all lines except the cursor line and expect the shell running in the terminal to do it for the line with the cursor:

// If these lines contain the cursor don't touch them, the program will handle fixing up wrapped
// lines with the cursor
if (bufferAbsoluteY >= y && bufferAbsoluteY < i) {
y += wrappedLines.length - 1;
continue;
}

@jerch do you think there should be a setting to just always reflow?

@jerch
Copy link
Member

jerch commented Nov 20, 2024

@jerch do you think there should be a setting to just always reflow?

Yes, I think that would be a good addition. We already had several discussions about that, all in all it seems there is no one-fits-all solution here until shells stop trying to reflow their prompt on their own (bash had there several forth and back changes, without that full reflow would just work as intended).

@Tyriar Tyriar changed the title Last/current line doesn't re-wrap when terminal is resized Add setting to enable reflow for the cursor line Nov 20, 2024
@Tyriar Tyriar added the type/enhancement Features or improvements to existing features label Nov 20, 2024
@jtbandes
Copy link
Author

Its better here to create a full-fledged log viewer app operating on the alternate buffer

Interesting idea, thanks for the tips. I may be making some wrong assumptions because I'm not as familiar with this stuff. But one of the attractive things about using the normal buffer is that I do actually want xtermjs to handle the scrollback and text selection. It's very nice to just get for free all the text wrapping, scrolling, and text selection features. It sounds like to use an alternate buffer to make a log viewer I would have to implement all this myself, at which point I might as well not use xterm.js :)

@jtbandes
Copy link
Author

jtbandes commented Nov 21, 2024

I was able to work around this reflow issue by manually erasing and re-writing the last line on resize:

https://codesandbox.io/p/sandbox/xtermjs-test-forked-sgk8mx

terminal.onResize(() => {
  if (!lastLine) {
    return;
  }
  let linesToErase = 0;
  const buffer = terminal.buffer.active;
  let y = buffer.baseY + buffer.cursorY;
  while (buffer.getLine(y)?.isWrapped === true) {
    linesToErase++;
    y--;
  }
  for (; linesToErase > 0; --linesToErase) {
    // Erase current line, move cursor up one line
    terminal.write("\x1b[2K\x1b[1A\r");
  }
  terminal.write(lastLine);
});

This now results in blank space at the bottom when lines are un-wrapped, as the blank spaces left in the buffer are not deleted. I'm not sure if there's a way to work around that.

Screen.Recording.2024-11-21.at.12.22.18.PM.mov

@jerch
Copy link
Member

jerch commented Nov 21, 2024

I was able to work around this reflow issue by manually erasing and re-writing the last line on resize:

Haha lol - well, thats what basically some shells do with their prompt line (which causes the headache in the first place).

@jtbandes
Copy link
Author

Yeah… I would love to delete this code if I can!

It still has a bug with leaving some junk in the scrollback if the line was wrapped so much it overflowed the whole screen…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/enhancement Features or improvements to existing features
Projects
None yet
Development

No branches or pull requests

3 participants