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

registerMarker/registerDecoration in overviewRuler does not work if invoked immediately #5214

Closed
jtbandes opened this issue Nov 15, 2024 · 6 comments
Labels
type/question A question on how to use the library

Comments

@jtbandes
Copy link
Contributor

jtbandes commented Nov 15, 2024

When writing a large batch of lines after clearing the terminal, and using registerMarker+registerDecoration to render colors in the overview ruler, the decorations do not appear if all the lines are written at once. If a small delay is introduced with setTimeout, the decorations work properly.

Additionally, a small decoration sometimes remains at the very top of the overview ruler even after the terminal is cleared.

Screen.Recording.2024-11-15.at.12.36.07.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-forked-yxrd7j

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 button1 = document.getElementById("reload-button-1");
const button2 = document.getElementById("reload-button-2");

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

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

terminal.open(container);

const lines = new Array(100).fill().map((_, i) => {
  return `line ${i}: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua`;
});

async function render(delay) {
  terminal.clear();
  terminal.reset();

  let first = true;
  let i = 0;
  for (const line of lines) {
    if (Math.random() < 0.2) {
      if (delay) {
        await new Promise((resolve) => setTimeout(resolve, 1));
      }
      if (!first) {
        terminal.write("\r\n");
      }
      if (i % 5 === 0) {
        const marker = terminal.registerMarker();
        terminal.registerDecoration({
          marker,
          overviewRulerOptions: {
            color: "#ff0000",
          },
        });
      }
      terminal.write(line);
      first = false;
    }
    i++;
  }
}

button1.addEventListener("click", () => {
  render(false);
});
button2.addEventListener("click", () => {
  render(true);
});

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

jtbandes commented Nov 15, 2024

It seems like the marker always has line: 0. Maybe this is because the newly written input has not yet been parsed?

Waiting for the new input to be parsed before adding the marker might introduce a lot of delay (I assume I would also have to delay writing any additional lines until the parsing finishes). Is there any way to do this without waiting, or to force processing of the write buffer?

@Tyriar
Copy link
Member

Tyriar commented Nov 19, 2024

I think your issue would be solved by using the write callback:

terminal.write(line, () => {
  // The line is parsed and committed to the buffer, register markers here
})

This allows you to execute code immediately after it's parsed.

@Tyriar Tyriar closed this as completed Nov 19, 2024
@Tyriar Tyriar added the type/question A question on how to use the library label Nov 19, 2024
@jtbandes
Copy link
Contributor Author

Thank you! I think that works. It was not clear to me from docs that this callback is actually associated with the single line/chunk being written... I assumed it might be batched with other callbacks if the terminal was processing data in batches.

@jerch
Copy link
Member

jerch commented Nov 20, 2024

It was not clear to me from docs that this callback is actually associated with the single line/chunk being written... I assumed it might be batched with other callbacks if the terminal was processing data in batches.

You are right - it is not associated with single line writing, it is just a callback denoting "this chunk of data is fully parsed and processed by the terminal buffer". To get "line-wise semantics" here, you'd have to chunk the data into lines upfront, and would get a callback for each line this way.

@jtbandes
Copy link
Contributor Author

jtbandes commented Nov 20, 2024

But just to confirm, if I call write twice in a row and pass two callbacks, whenever the data is processed the callbacks will not be batched together but will immediately invoked after the corresponding data chunk is processed? e.g.

  • process chunk 1
  • call callback 1
  • process chunk 2
  • call callback 2

even if this processing is happening all together?
This is what was not clear to me from the docs :)

(In my case the chunks happen to be lines already, but I guess this is irrelevant to the ordering question)

@jerch
Copy link
Member

jerch commented Nov 20, 2024

Yes the callback gets triggered synchronous right after the chunk got processed. So no new chunk data will be handled yet. The input data processing happens normally fully synchronous, also see https://xtermjs.org/docs/guides/hooks/#lifecycle--execution-context-of-parser-hooks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/question A question on how to use the library
Projects
None yet
Development

No branches or pull requests

3 participants