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

Seamlessly navigate through tmux/vim #967

Open
DanCardin opened this issue Dec 23, 2021 · 22 comments
Open

Seamlessly navigate through tmux/vim #967

DanCardin opened this issue Dec 23, 2021 · 22 comments

Comments

@DanCardin
Copy link

DanCardin commented Dec 23, 2021

(originally commented about this on reddit and was directed to suggest it here.

The relevant tmux plugin is christoomey/vim-tmux-navigator and the corresponding vim plugin (which i use, there are a few) is aserowy/tmux.nvim.

At a high level, the idea is to bind the same tmux and vim keybinds and for both navigation and pane resize to work contextually to whether vim is focused or not (ideally interacting with vim splits seamlessly also.

The comment on reddit suggested that zellij might be able to get away without a vim plugin. Because of vim split navigation, im skeptical this can be done (fully) without a vim plugin, but I'm personally happy to fork the plugin, so long as the hooks necessary for the vim plugin to function correctly exist (relevant portion of the vim plugin i use)

But in order to be fully specified, i'll lay out the expected behavior in the event it can all be done in zellij, but being aware that if that's not possible, some of the behaviors laid out will be handled by the vim plugin

Given some layout

+-----------------------------------+----------------+
| ................................. |                |
| ⋮     vim     ⋮       vim       ⋮  |       pane 2  |
| ⋮     split 1 ⋮       split 2   ⋮  |               |
| ................................. |                |
+-----------------------------------+----------------+

Suppose keybind of C-h, C-j, C-k, C-l for navigation and M-h, M-j, M-k, M-l resizing:
navigation

  • focused split 1, with C-h, pane 1 should be focused
  • focused split 2, with C-h, split 1 should be focused
  • focused pane 2, with C-h, split 2 should be focused
  • focused split 1, with C-l, split 2 should be focused
  • focused split 2, with C-l, pane 2 should be focused
  • focused pane 2, with C-l, split 1 should be focused

resizing

  • focused pane 2, with M-h, pane 1 should shrink
  • focused pane 2, with M-l, pane 2 should shrink, pane 1 (i.e. split 2) should grow
  • focused split 1, with M-l, split 1 should grow
  • focused split 1, with M-h, split 1 should shrink
  • focused split 2, with M-l, pane 2 should shrink with split 2 getting bigger
  • focused split 2, with M-h, split 1 should shrink

With a similar table for vertical naviation.

I notice that zoom is not currently implemented today. but the above plugins (really just the vim one) have the option to only navigate vim splits when zommed. I.e. disable pane navigation if zoomed. Personally, that's the behavior i have enabled (right now), but just to be aware that this (and i suppose normal pane navigation keybinds) interact with a theoretical zoom feature

@jaeheonji
Copy link
Member

jaeheonji commented Dec 23, 2021

Hi! I also like to use neovim with Zellij. but, currently, the Zellij does not provide that feature. I personally think this feature should be processed in vim/neovim (using plugin). Of course, we can add the feature for vim/nvim, but i don't know if that's the right direction.

@DanCardin
Copy link
Author

There does need to be some level of zellij (or zellij plugin) specific behavior, since it needs to only conditionally forward the original binding to vim in the even the pane's running process is vim

Re the vim side, I'm willing to fork the (n)vim plugin i reference for myself for that side, what's unclear to me is how such a plugin would work. i.e. whether zellij supports the external control required for support it.

@jaeheonji
Copy link
Member

@DanCardin Thanks for the explanation!

First, I looked at how vim-tmux-navigator works. As you already know, the core of this plugin is the if-shell conditions statement in tmux.conf. Unfortunately, Zellij does not yet provide such an extensible config. So I think you are curious about plugins.

So, I thought about whether the above function can be implemented using the current Zellij plugin system. The conclusion seems to be impossible at present.

Because by default the Zellij plugin has an isolated environment using WASM. In plugin, there are some convenience function that can communicate with the Host (Zellij Server). For examples, hook the keyboard event.

But, the problem is, there is still no function to trigger a specific event of Zellij inside the plugin. For example, the navigation of the pane, etc.

Also, it seems difficult to confirm that vim/nvim is currently running. Because the inside of the plugin is a WASM VM, it is isolated from the host's environment variables.

Therefore, further development related to WASM is required to implement the seamless navigation function through the Zellij Plugin.

You can check which functions the plugin can use through the zellij-server/src/wasm_vm.rs file.

@DanCardin
Copy link
Author

I'm not super tuned into how the plugin interface works, but it seems like a PaneProgramChanged (or somesuch name) event could be emitted? my brief lookings into how this is done in tmux basically that they pipe the pane's tty to pgrep -t. Perhaps there's a better, more cross platform way of doing that.

being able to subscribe to an event like this seems like it would be useful elsewhere. For example, I dont know if this is default, but my tmux's tabs automatically display "nvim" or "zsh" as the tab name depending on which is focused in the currently active tab.

@jgsch
Copy link

jgsch commented Feb 23, 2022

I am also very interested for something like christoomey/vim-tmux-navigator. I think this might be the last thing that keeps me from going completely to zellij.

@Lilja
Copy link

Lilja commented Oct 28, 2022

I've spent some time looking into this issue to try to create a neovim plugin to mirror the same features as above mentioned plugin.

Tmux

Reading Chris' code, it effectively uses the following cli command to navigate to another frame: tmux shell-pane -t $TMUX_PANE -<direction>. Where <direction> is either LUDR(left, up, down, right). It take the command and runs it in vim's system-function. Which spawns a non-interactive shell and runs the command.

:echo system("tmux select-pane $TMUX_PANE -R")

It works!

Zellij

Luckily for us, zellij has as an action argument where you can navigate using zellij action move-focus-or-tab <direction>. So let's try to use it. I'm using neovim, but it's mostly the same for vim.

:echo system("zellij action move-focus-or-tab right")
ENODEV: No such device 

What gives?! An error!
I've opened up #1861 which tries to debug the issue. However, due to how zellij tries to access tty information in a non-interactive terminal, it panics and fails.

So, unless this bug is fixed which I believe will need some internal refactors of zellij and how it handles communication between client and server, this is blocked.

@jaeheonji
Copy link
Member

@Lilja Thank you for your interest in this feature.

I am also constantly interested in this feature, and did some testing after a new version was released.
I don't know if this could be a fundamental solution, but you can use lua from the nvim side to run a zellij action like this:

local pipe = io.popen("zellij action move-focus down")
pipe:close() -- necessary

I hope this will help you with your work.

@Lilja
Copy link

Lilja commented Oct 29, 2022

Thanks @jaeheonji! That worked.

I created a neovim plugin to solve this problem, Lilja/zellij.nvim which has vim-tmux-navigator compatible keybindings. Feel free to try it out.

@jaeheonji
Copy link
Member

jaeheonji commented Oct 31, 2022

Thank you for making a awesome plugin Lilja/zellij.nvim!

But, for natural navigation like tmux-nvigator, there seems to be more to be implemented in zellij side. Therefore, I will keep this issue as it is now.

@casonadams
Copy link
Contributor

casonadams commented May 31, 2023

Here is something that is getting close. I just need some help sending ctrl + w h etc.

        bind "h" {
            SwitchToMode "Normal";
            Run "bash" "-c" "[ ! -z $VIMRUNTIME ] && zellij action close-pane & zellij action move-focus left || zellij action close-pane & zellij action write 7f 68";
        }

It would be nice to be able to send-keys that way I could so something like

        bind "h" {
            SwitchToMode "Normal";
            Run "bash" "-c" "[ ! -z $VIMRUNTIME ] && zellij action close-pane & zellij action move-focus left || zellij action close-pane & zellij action send-keys ctrl+w h";
        }

@Lilja
Copy link

Lilja commented Jul 6, 2023

From @casonadams find above. I was able to make it work, with a small adjustment. But it's not working well.

If you disregard sending ctrl+w h and instead using my zellij.nvim neovim plugin, you can actually send :ZellijNavigate(Right|Left|Down|Up)<Cr> like this:

Run "bash" "-c" "[ -z $VIMRUNTIME ] && zellij action move-focus left || zellij action write-chars \":ZellijNavigateLeft \"";

☝️ note the newline. It's important as we need something to press after the command has been completed.

This doesn't work fully as the run command will open a pane, because it's expected to be used for running certain long running commands like tail or some sort of compile-watcher tool.

So we probably need a flag for Run to run inside of a subprocess and not display the contents like it does right now.

@hnorkowski
Copy link

It would be awesome if we could implement this not only for vim but also for helix (or other programs)

@Dzordzu
Copy link

Dzordzu commented Oct 14, 2023

Idea

In order to achieve this zellij can follow tmux like approach: create a custom "vim locked mode", then use plugin provided by #967 (comment).

How it would work

  • During vim startup zellij enters "vim locked mode" (command send by vim)
  • Zellij plugin detects that pane is using vim
  • Zellij triggers "vim locked mode"
  • Some of the keybindings are disabled
  • When VIM plugin detects edge of the vim, the disable mode command is sent to zellij. Afterwards, the command changing the pane/tab is sent

Depends on:

@mpasa
Copy link

mpasa commented Jan 25, 2024

@Dzordzu I believe your last point might be already addressed (in nvim at least) by this the zellij-nav.nvim plugin.

@from-nibly
Copy link

It might be obvious to some, but maybe not. If such a partial lock mode existed, it should probably be named something more generic. Maybe "Partial Lock" or "Subprocess Lock"

But maybe those two features should be separated?

  1. Be able to trigger actions based on the subprocess of the focused pane
    a. Might need to make the trigger mechanism respond to inverted queries. e.g. "process is not vim" or "process is vim"
  2. Be able to enter a Partial Lock mode where a list of keymaps are disabled.

If the features get separated then "Partial Lock" would make sense

If they are joined as a single feature then "Subprocess Lock" might make more sense.

@imsnif
Copy link
Member

imsnif commented May 2, 2024

The recent patch version (0.40.1) adds the ability to:

  1. Bind Ctrl j
  2. List connected clients to the current session with zellij action list-clients
    Sample output:
$ zellij action list-clients

CLIENT_ID ZELLIJ_PANE_ID RUNNING_COMMAND
1         plugin_2       zellij:session-manager
2         terminal_3     vim /tmp/my-file.txt

I think this should give anyone wishing to implement this sort of navigation all the tools they need (more info here: #2434 (comment))

@hiasr
Copy link
Contributor

hiasr commented May 2, 2024

I have created a plugin which solves this issue! See vim-zellij-navigator as the Zellij version of vim-tmux-navigator! Currently, it relies on an additional plugin in Neovim to know whether Neovim is running, I will change this to use list-clients once that command becomes available to plugins.

@imsnif
Copy link
Member

imsnif commented May 3, 2024

@hiasr - if you want, until this command is directly available to plugins, you can invoke zellij action list-clients from plugins using the run_command API call and parsing its output.

@imsnif
Copy link
Member

imsnif commented May 3, 2024

Also @hiasr - if I may offer another suggestion: could be cool if you make the plugin generic: a sort of discrete piece of logic that you can bind to a key and does: "move <direction> unless I am focused on <config_app_string> in which case send the key to the focused pane". I think this will also help out @mrjones2014 in implementing support in their plugin.

@hiasr
Copy link
Contributor

hiasr commented May 3, 2024

Good idea! I am currently working on migrating towards zellij action list-clients such that the additional neovim plugin is not necessary and multiple clients work as expected. Once that is finished I will look into configurability, maybe a regex you can add as an argument would cover most of the potential usecases.

@imsnif
Copy link
Member

imsnif commented May 3, 2024

And also, while I'm at it: another piece of advice - I'd recommend not using latest in the keybinding https url but using the version number explicitly. The reason for this is that Zellij caches the plugins on successful load by their URL - and so when someone would want to upgrade, if using latest they'd have to explicitly clear the cache.

@fresh2dev
Copy link

Idea

In order to achieve this zellij can follow tmux like approach: create a custom "vim locked mode", then use plugin provided by #967 (comment).

How it would work

* During vim startup zellij enters "vim locked mode" (command send by vim)

* Zellij plugin detects that pane is using vim

* Zellij triggers "vim locked mode"

* Some of the keybindings are disabled

* When VIM plugin detects edge of the vim, the disable mode command is sent to zellij. Afterwards, the command changing the pane/tab is sent

I think this sort of approach is the solution to this problem. I referenced vim-zellij-navigator and built a plugin to support this approach, in pursuit of seamless navigation for Vim and other programs that benefit from Ctrl+h/j/k/l nav, like Helix, FZF, Zoxide, Atuin, etc.

The result: fresh2dev/zellij-autolock

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

No branches or pull requests