zellij-org / zellij

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

Feature: Add auto-lock mode when pane is using alternate screen #502

Open lilyball opened 3 years ago

lilyball commented 3 years ago

When a process in a pane is using alternate screen mode, it often makes use of key bindings that Zellij may be using. For example, in less, if I want to do a fixed-string search (instead of regex search), I press Ctrl-R, but Zellij defaults Ctrl-R to Resize mode.

Suggested solution

This could be solved by giving Zellij an auto-lock mode, where it implicitly locks while in this mode, and reverts to being locked when putting focus back on this pane/tab (and it would auto-unlock upon switching away, if Zellij gains support for switching panes/tabs with the mouse or some other non-keyboard mechanism). Zellij could then enter this auto-lock mode any time the pane enters alternate screen mode. This way I can use all my familiar keyboard shortcuts in the terminal app, and I can unlock if I want to switch away. And I don't have to remember to toggle lock mode any time I go into e.g. less, or pop open vim for a moment.

This should probably use a new mode instead of 'locked', for three reasons:

  1. This makes it clear that it will exit this mode automatically when leaving alternate screen, or when moving focus to another pane/tab.
  2. This allows me to explicitly go into the regular Locked mode such that it won't exit automatically when leaving alternate screen mode (or when switching tabs/panes if there exists some non-keyboard mechanism to do so).
  3. This allows me to add key bindings that are present in auto-locked mode, without adding them to normal locked mode. For example, I may wish to add bindings that are unlikely to conflict with terminal apps to auto-locked mode, while omitting them from locked mode so I can use the latter in case the bindings do conflict.

Alternative solution

Instead of adding a separate key binding mode, Zellij could gain an optional attribute on key bindings for "available during auto-lock", and could update its default key binding set as needed (e.g. ^G should presumably still be available), though it should be conservative about what it adds by default. Auto-lock is now a mode modifier for the normal mode. Zellij could additionally gain a key binding for "toggle auto-lock" that is only available during auto-lock. Toggling it off wouldn't remove the modifier, it would just disable it (I'm thinking some visible indicator in the status bar that's colored while enabled, and greyed out while toggled off, and missing entirely when not in alternate screen). As before, if auto-lock is toggled off, it would re-enable itself upon re-focusing the pane. Additionally, if I toggle it off, leave alternate screen mode, and re-enter alternate screen mode, it should toggle back on.

I've said it's only available during normal mode, and this is because I don't think it makes sense to apply to other modes. AFAIK the only other mode that actually sends keypresses to the running process is lock mode.


I'm inclined to say I like the alternative solution better. The biggest difference here is the alternative solution doesn't require duplicating any keyboard shortcuts you want available from normal mode, you just have to annotate them appropriately. It also means auto-lock mode won't gain new shortcuts that aren't available in normal mode, since the whole point is to restrict the keybinds that Zellij takes. But maybe this is unnecessarily limiting flexibility. The primary solution certainly could display the UI the same way as the alternative solution.

I'm also thinking here that Scroll mode is useless in alternate screen and should be disabled (it just lets me scroll through some garbage left in the buffer by alternate screen mode; I don't even know why Zellij maintains a scrollable buffer at all for alternate screen. That could in theory be useful if everything past the bottom screen was actually the non-alternate scroll buffer, but that feels more confusing than it's worth. In any case, since it's not usable in alternate screen mode, we could just remove scroll mode during alternate screen and replace it with the auto-lock indicator. This could also give us Ctrl-S as the toggle for auto-lock, though I don't know offhand if that's a key binding that is commonly used by any alternate screen apps. Either way, it gives us a spot for the indicator that doesn't require perturbing the UI or taking up more space. And like lock mode, mode key bindings not available in auto-lock would just be disabled.

imsnif commented 3 years ago

While I like the idea of using the alternate screen in order to indicate when (certain) keybindings should be disabled, I'm a little worried about usability here. A few scenarios I find problematic:

  1. I like having a few vim panes open in Zellij and hopping between them.
  2. Accidentally moving focus in a multiple pane screen (I'm thinking ~7-8 panes) and landing on an alternate-screen pane can be confusing, as suddenly the alt-hjkl just stops working.

While both of these scenarios can be solved with configuration, I personally often shy away from such solutions. I want Zellij to work in a good-enough and not surprising way (as much as possible) out of the box, and leave configuration for specialized cases or advanced users.

How about if we add this as a cli option? Something like --lock-on-application or --support-autolock or some such?

lilyball commented 3 years ago

The problem is right now, Zellij’s default bindings conflict with common keys used in alternate screen applications (including less), and even with a custom keybind setup it’s going to be difficult to avoid keys wanted by alternate screen apps without becoming unusable.

imsnif commented 3 years ago

I definitely understand and totally agree this is a big pain point. Being a wrapper we will always collide with the keybindings of the things we wrap. I am not exaggerating when I say I personally lost sleep thinking about this problem more than once over the past months. The solution we have right now is adequate, but I agree that it could definitely be better. Do you really feel it is unusable though?

lilyball commented 3 years ago

The need to remember to constantly lock and unlock as I run alternate screen tools (I use ^R in less a lot) is indeed a huge barrier to adoption for me. There's a lot to like about Zellij, but tools like tmux that use a prefix key approach have a huge advantage when dealing with alternate screen apps. And since alternate screen apps are so common, this is a pretty big deal.

imsnif commented 3 years ago

I totally get it being uncomfortable. I've hit this issue myself (for me it's ctrl-r in vim). I thought about this and realized my concerns can be distilled to: "this is confusing to new users and might not always be desirable (eg. having htop in the background)"

I have a suggestion: how about if we do everything you suggested but have the user confirm entering the mode? Either a box or some indication on the status bar reading something like "Defer UI to this application?" (ideally with simpler language for non-native English speakers) And this prompt can be enabled/disabled/always-yes/always-no through the config. The user would also be able to enter this mode manually later when focused on this application pane if they selected no.

What do you think?

dreamcat4 commented 2 years ago

Hello. As a brand new user (of today, day 1) who is already being affected by this...

it feels like I need a way to invoke the ctrl+g lock mode on the cmdline while zellij is already running. So I can then alias that to specific applications which i frequently launch: micro and less. Etc. That would help a lot here. Since then I would no longer need to manually remember to type ctrl+g anywhere near so often. It gets tiresome pretty quickly.

What would that look like for a user like me? ...Well IDK! Maybe something a bit like this?

~/.profile:

function micro()
{
  zellij cmd --panel lock
  micro "$@"
  zellij cmd --panel unlock
}

function less()
{
  zellij cmd --panel lock
  less "$@"
  zellij cmd --panel unlock
}

And I would like to say that I would be pretty happy with something as simple as that. Nevermind of the actual specific name of the commands, or how to invoke it on the cmdline. That does not matter to me. so long as there is a command, that it can be triggered or invoked.

Actually I can probably already (today) just do something else to outside of zellij, to then send the ctrl+g keybind through Xorg system. Or in a different way for wayland. And that should work.... But it just isn't so simple or direct to do it that more obscure way (to cover and be compatible with those 2 entirely different systems which use entirely different mechanisms and tools etc.)

However what else is still missing?

Well yes! It helps a lot to have panel navigation keybinds remain available (while locked). To allow keyboard only users to escape the panel. And use other panels. Then come back to the original panel. Because for such a program like less, (or an editor like vim etc.). We typically keep open and refer back to many times. (and mouse users can already click to other panels while locked, for feature parity).

So I look in the default config.yaml, where it was saying:

    locked:
        - action: [SwitchToMode: Normal,]
          key: [Ctrl: 'g',]

I added to it (just the 4 navigation ones):

    locked:
        - action: [SwitchToMode: Normal,]
          key: [Ctrl: 'g',]
        - action: [MoveFocusOrTab: Left,]
          key: [ Alt: 'h', Alt: Left]
        - action: [MoveFocusOrTab: Right,]
          key: [ Alt: 'l', Alt: Right]
        - action: [MoveFocus: Down,]
          key: [ Alt: 'j', Alt: Down]
        - action: [MoveFocus: Up,]
          key: [ Alt: 'k', Alt: Up]

And that works great. I can now navigate between panels whilst still in locked mode.

However what we are still missing here is per-panel level of locking. Which is to say if global lock mode is ctrl+g. Then a panel lock would be a different action. For example ctrl+shift+g. And then we might be figuring this out, and saying well...

the whole point of locking (even the global lock mode) is to allow interacting with 1 specific focussed foreground program of conflicting bindings. And that 1 foregrounded program is only ever going to be located in that 1 specfic panel. So you might as well do away with the general concept of a "global" lock mode completely! And just make it per-panel by default. With an automatic memory such that re-entering the locked panel then remembers it's current mode (locked or unlocked). And then navigating away will either lock or unlock depending on that specific panel's locked state. So a new metadata entry for each panel object then. Or class member / attribute whatever.

Which zellij is not doing at the moment. But I believe it probably should. After skim reading this issue (wasn't paying close enough attention sorry), and also realizing that my own desired solution (for auto enabling / disabling lock mode on those program's launch and exit)... was is in fact not completely adequate on its own. It also requires the per-panel level locking feature. So that I can navigate away from the program and back to it. Without further workflow disruptions!!!

I understand that this seems to be something which probably makes you want to tear your hair out. I think. But all I can say is that I think it's probably? worth it? To deal with this earlier, rather than later down the road. If you agree that it is the right way forwards here.

And if the individual user can set (with enough obscurity) just those panel nav keybinds. Then that is probably up to the user to choose a global set of (total of 5) keybinds. That is non-conflicting with all of there commonly used programs.

I don't have much else to add except... it would really make my day. And be a huge relief to see this move forwards.

I suppose conversely it might be quite annoying, from my perspective if it didn't go anywhere. Because i cannot see any other reasonable alternative solutions here. At least I don't expect to be smart enough to think up any better suggestions. Than this one.

Have a good day.

[edit] Sorry forgot to say: Great program BTW! So much better than TMUX. Really thank you for spending so much effort on getting it so good here. Only been using it for a short time but it's really very impressive. Thank you for this.