zellij-org / zellij

A terminal workspace with batteries included
https://zellij.dev
MIT License
19.61k stars 616 forks source link

OSC 7 alternative with doom emacs and neovim #3184

Open amiorin opened 4 months ago

amiorin commented 4 months ago

The debate in my team is if it is better to run the terminal inside emacs or not. One feature of running vterm inside emacs is that the working directory is following the root of the current project opened in emacs. After some thinking we decided to try to solve the problem from the init script of fish.

I'm sharing the fish code here. Maybe it will be useful to other zellij users. It can be adapted to other shells and neovim.

set emacs_exp '(with-current-buffer (window-buffer (selected-window)) (projectile-project-root))'
set emacs_dir (emacsclient -a 'echo' --eval "$emacs_exp" 2> /dev/null)
if test "$emacs_dir" != "nil"
    if test "$emacs_dir" != "$emacs_exp"
        cd (echo $emacs_dir | jq -r)
    end
end

We still think that emacs and the shell should communicate the CWD to zellij using OSC 7. See #898 and #892. Maybe zellij should not forward the OSC 7 but it should capture it and use it.

I'd be very happy to support them, for sure. But we also can't just pass them through as is.

An example of OSC 7 to illustrate:

  1. One pane sends an OSC 7 to Zellij telling it the working directory is "/home/pane1". Zellij passes it to the terminal emulator which logs the current directory as "/home/pane1".
  2. The user opens another pane, which sends an OSC 7 to Zellij telling it the working directory is "/home/pane2", Zellij forwards it to the terminal emulator which logs the current directory as "/home/pane2"
  3. The user changes focus back to pane 1, no further signals are sent because neither of the panes know anything changed. The terminal emulator thinks the working directory is "/home/pane2" while it actually is "/home/pane1".

Another example for OSC 133:

  1. We have two panes open that are vertically split (side by side). The pane on the left sends an OSC 133;A to illustrate the start of a command. Zellij forwards it as is to the terminal emulator.
  2. The pane on the left writes a few lines to the terminal which are rendered in the left pane and then terminates the command with an OSC 133;B.
  3. Since there's a pane on the right, the terminal emulator thinks the command also includes those lines on the pane to the right, because it doesn't know what panes are and that's what we told it to do.

In short - we have to keep track of these things. These are two examples, but there are loads of others. This is the reason we swallow these codes - because otherwise the terminal emulator won't do what the user or the command are expecting it to.

As I said - I'm totally up to supporting all of these codes. It's some work, but not more than we've already done.

imsnif commented 4 months ago

It's funny, I totally forgot about OSC 7 and implemented various workarounds to this over time. Will definitely implement support for it soon.

Otherwise though - could you explain what you mean? Do you mean that when you open new panes they should be in the same cwd as the original emacs pane? Because this should work already (minus a couple of issues I hope to fix before the next release).

amiorin commented 4 months ago

It doesn't work as expected because the cwd of emacs and emacsclient in osx (checked with lsof -d cwd) doesn't change when switching between projects inside emacs. Therefore vterm (the terminal inside emacs) and zellij new-pane have different cwd. The script above asks emacs what is the root of the current project so that vterm, zellij, and wezterm use the same cwd.

The other thing we would love to see is https://github.com/christoomey/vim-tmux-navigator for zellij. I can open other ticket if needed where I can go in the details.

imsnif commented 4 months ago

So just to get it straight: we're talking about opening a terminal and having its cwd start as the cwd of emacs (assuming it is focused), right? This should be fixed by implementing OSC 7 - I hope to get to it before next release, but I can't promise.

I think someone did a version of this plugin somewhere... either way, it can be done with plugins today but not in a very robust manner. In a couple of versions it'll be easier with some new action interrupt APIs.