xtermjs / xterm.js

A terminal for the web
https://xtermjs.org/
MIT License
17.62k stars 1.62k forks source link

Nvim and tmux dont resize with fitaddon, but normal terminal does (electron) #3873

Closed FormalSnake closed 2 years ago

FormalSnake commented 2 years ago

Resizing my xterm window makes the content grow and shrink, as expected, but when i run vim or tmux, and then resize, it doesnt work at all.

Details

Steps to reproduce

  1. Use xterm addon fit.
  2. run tmux or vim and then resize window

https://user-images.githubusercontent.com/90651091/175765816-0662d0c2-3511-4511-bf11-950f3e1bddd5.mov

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Kaiium</title>
    <link rel="stylesheet" href="xterm/css/xterm.css" />
    <script src="xterm/lib/xterm.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.5.0/lib/xterm-addon-fit.js"></script>
  </head>
  <body>
    <!--<div
      id="DragBar"
      style="-webkit-app-region: drag; width: 100%; height: 20px"
    ></div>-->
    <div id="terminal"></div>

    <script src="index.js"></script>
  </body>
</html>

index.js

const { WebglAddon } = require("xterm-addon-webgl");
const { getSettings } = require("./settings");

const ipc = require("electron").ipcRenderer;

const { bgColor, cols, rows, CursorBlink, FontFamily, FontSize } =
  getSettings();

//const FitAddon = require("xterm-addon-fit");
var term = new Terminal({
  fontSize: FontSize,
  fontFamily: FontFamily,
  cursorBlink: CursorBlink,
  termProgram: "Kaiium",
});
term.setOption("theme", {
  background: bgColor,
});
var webgl = new WebglAddon();
var fitAddon = new FitAddon.FitAddon();

/*term.onData(function (data) {
  term.write(data);
});*/
document.body.style.backgroundColor = bgColor;
term.open(document.getElementById("terminal"));
term.loadAddon(fitAddon);
term.loadAddon(webgl);
fitAddon.fit();

function log() {
  console.log(
    term.cols,
    term.rows,
    viewport.style.lineHeight,
    viewport.style.height
  );
}

var viewport = document.querySelector(".xterm-viewport");
log();

term.onRender = function () {
  fitAddon.fit();
};

window.onresize = function () {
  log();
  fitAddon.fit();
};

ipc.on("terminal.incomingData", (event, data) => {
  term.write(data);
});

term.onData((e) => {
  ipc.send("terminal.keystroke", e);
});
console.log(bgColor);

main.js

const {
  app,
  BrowserWindow,
  ipcMain,
  globalShortcut,
  Menu,
  MenuItem,
} = require("electron");

const pty = require("node-pty");
const os = require("os");
const { getSettings } = require("./settings");
const username = process.env["LOGNAME"];

const { autoUpdater } = require("electron-updater");

const { bgColor, cols, rows, shellSettings } = getSettings();

console.log(getSettings());

var shell =
  os.platform() === "win32"
    ? "powershell.exe"
    : shellSettings; /* "/opt/homebrew/bin/fish"*/

autoUpdater.checkForUpdatesAndNotify();

let mainWindow;
function createWindow() {
  mainWindow = new BrowserWindow({
    height: 1080,
    width: 1920,
    frame: false,
    transparent: true,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
      enableRemoteModule: true,
      allowRunningInsecureContent: true,
    },
  });
  mainWindow.loadURL(`file://${__dirname}/index.html`);
  mainWindow.on("closed", function () {
    mainWindow = null;
  });

  //ipcing

  var ptyProcess = pty.spawn(shell, [], {
    name: "xterm-color",
    cols: cols,
    rows: rows,
    cwd: process.env.HOME,
    env: process.env,
  });

  ptyProcess.on("data", function (data) {
    mainWindow.webContents.send("terminal.incomingData", data);
    console.log("Sent data to terminal");
  });
  ipcMain.on("terminal.keystroke", (event, key) => {
    ptyProcess.write(key);
  });
}

app.on("ready", createWindow);

app.on("window-all-closed", function () {
  if (process.platform !== "darwin") {
    app.quit();
  }
});

app.on("activate", function () {
  if (mainWindow === null) {
    createWindow();
  }
});

This is most of my source code, if you wonder why some variables seem to come from nothing, like the shell settings, i have a configuration system. In the configuration i also set initial rows and columns, and vim and tmux use that, instead of the newly updated ones.

Tyriar commented 2 years ago

Something doesn't seem right, I don't have time to look into this atm though.

You could try debug into this function to make sure it's calling terminal.resize as expected:

https://github.com/xtermjs/xterm.js/blob/55beec8b9674ac3aae6728adc36bb34b1468c875/addons/xterm-addon-fit/src/FitAddon.ts#L34-L48

jerch commented 2 years ago

@superlopez-real Maybe I've overlooked it - where do you propagate the changed terminal size back to ptyProcess?

FormalSnake commented 2 years ago

@superlopez-real Maybe I've overlooked it - where do you propagate the changed terminal size back to ptyProcess?

I think that happens in the plugin

FormalSnake commented 2 years ago

Something doesn't seem right, I don't have time to look into this atm though.

You could try debug into this function to make sure it's calling terminal.resize as expected:

https://github.com/xtermjs/xterm.js/blob/55beec8b9674ac3aae6728adc36bb34b1468c875/addons/xterm-addon-fit/src/FitAddon.ts#L34-L48

Sure ill try it out

FormalSnake commented 2 years ago

I've done it, i think, but it didn't do the console.log when resizing the window.

if (
      this._terminal.rows !== dims.rows ||
      this._terminal.cols !== dims.cols
    ) {
      core._renderService.clear();
      this._terminal.resize(dims.cols, dims.rows);
      console.log("Resized terminal");
    }
  }
jerch commented 2 years ago

@superlopez-real Maybe I've overlooked it - where do you propagate the changed terminal size back to ptyProcess?

I think that happens in the plugin

Nope, the plugin only deals with changes on terminal side. You still need to announce those changes back to the pty.

FormalSnake commented 2 years ago

@superlopez-real Maybe I've overlooked it - where do you propagate the changed terminal size back to ptyProcess?

I think that happens in the plugin

Nope, the plugin only deals with changes on terminal side. You still need to announce those changes back to the pty.

How would i do that?

jerch commented 2 years ago

This depends on how you connect to the server side. Untested:

// client side
term.onResize((size: { cols: number, rows: number }) => {
  ipc.send("terminal.resize", size);
});

// server side
ipcMain.on("terminal.resize", (event, size) => {
  ptyProcess.resize(size.cols, size.rows);
});

(Not sure, if that mangles the values correctly for server side, well you basically need to get those 2 int values over.)

FormalSnake commented 2 years ago

This depends on how you connect to the server side. Untested:

// client side
term.onResize((size: { cols: number, rows: number }) => {
  ipc.send("terminal.resize", size);
});

// server side
ipcMain.on("terminal.resize", (event, size) => {
  ptyProcess.resize(size.cols, size.rows);
});

(Not sure, if that mangles the values correctly for server side, well you basically need to get those 2 int values over.)

I dont have a server side terminal, it is a custom terminal application for your own computer, but ill try it out.

FormalSnake commented 2 years ago

This depends on how you connect to the server side. Untested:

// client side
term.onResize((size: { cols: number, rows: number }) => {
  ipc.send("terminal.resize", size);
});

// server side
ipcMain.on("terminal.resize", (event, size) => {
  ptyProcess.resize(size.cols, size.rows);
});

(Not sure, if that mangles the values correctly for server side, well you basically need to get those 2 int values over.)

How do i convert this to javascript? and where do i get the cols and rows from

jerch commented 2 years ago

I dont have a server side terminal, it is a custom terminal application for your own computer, but ill try it out.

You have a client-server application, your main.js runs as server part and index.js as client part. Thats the reason why have to use ipc messaging between (separate processes).

How do i convert this to javascript?

Thats almost javascript, just remove the type annotations of the client part.

and where do i get the cols and rows from

From the terminal onResize event as shown above.

FormalSnake commented 2 years ago

I dont have a server side terminal, it is a custom terminal application for your own computer, but ill try it out.

You have a client-server application, your main.js runs as server part and index.js as client part. Thats the reason why have to use ipc messaging between (separate processes).

How do i convert this to javascript?

Thats almost javascript, just remove the type annotations of the client part.

and where do i get the cols and rows from

From the terminal onResize event as shown above.

oooh ok, ill try it out

FormalSnake commented 2 years ago
ipcMain.on("terminal.resize", (event, size) => {
  ptyProcess.resize(size.cols, size.rows);
});

YOU FIXED IT!! thanks a lot.

For anyone doing this in javascript, change

term.onResize((size: { cols: number, rows: number }) => {
  ipc.send("terminal.resize", size);
});

to

term.onResize(function (size) {
  ipc.send("terminal.resize", size);
});