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

Feedback #35

Closed
maximbaz opened this issue Jul 5, 2020 · 320 comments
Closed

Feedback #35

maximbaz opened this issue Jul 5, 2020 · 320 comments

Comments

@maximbaz
Copy link
Contributor

maximbaz commented Jul 5, 2020

Hey @romkatv! I'm giving z4h/v3 a spin, and would like to share some ideas and ask some questions at the same time 🙂

  1. Tab completion: traversing hidden folders

You mentioned it is possible to add an option to traverse hidden folders as well when glob_dots is set, could you please add it or give me a hint how to do this locally?

Turns out I edit files in hidden folders too often, it would be helpful if fzf included everything.

  1. Tab completion: ignoring some patterns

The standard completion system respects ignored-patterns.

This was a great hint, just as one idea it allows to ignore .zwc files, for example with zstyle ':completion:*:*:kak:*:*' ignored-patterns '*.zwc' opening .p10k.zsh in editor is simpler, as kak .p<Tab> now has only one match instead of two, so fzf doesn't show up at all and I go straight to .p10k.zsh.

Currently recursive directory listing doesn't respect it but it's on my TODO list to fix this.

Would be awesome! Could you please suggest what would be a proper zstyle syntax that you want to support for ignoring folders for cd? Say for example I wanted to ignore ~/.cache/ and ~/.docker/ and everything underneath them.

  1. Tab completion: do not require space to search different dirs

Suppose I just cloned zsh4humans, I press <Alt-Down> and I want to navigate to zsh4humans/fn. Typing z fn will find it, but typing zfn will not. I am used to just typing in fzf without having to think where I should put spaces... Could we at least have an option, if the current behavior is something you prefer?

By the way, while <Alt-Down> shows

zsh4humans
zsh4humans/fn

But cd <Tab> shows

zsh4humans
./zsh4humans/fn

Both work, but the latter is less aesthetic :)

  1. Tab completion: fzf-tab continuous-trigger

Am I right that it will become unnecessary when everything will be traversed? If so, this could be cleaned up I presume:

zsh4humans/.zshrc

Lines 56 to 58 in 6af0bfc

# When presented with the list of choices upon hitting Tab, accept selection and
# trigger another completion with this key binding. Great for completing file paths.
zstyle ':fzf-tab:*' continuous-trigger tab

  1. Tab completion: multiple selection doesn't seem to work

Or I'm doing something wrong :) What I expected to work is to type $ cp .zsh<Tab> and press Ctrl+Space to select more than one entry

  1. Tab completion: add grouping and multiple coloring

Have you considered adding groups and using different colors to fzf completion? I have some half-broken leftovers from prezto, but they will suffice to show a difference:

zstyle ':completion:*:*:*:*:*' menu select
zstyle ':completion:*:matches' group 'yes'
zstyle ':completion:*:options' description 'yes'
zstyle ':completion:*:options' auto-description '%d'
zstyle ':completion:*:corrections' format ' %F{green}-- %d (errors: %e) --%f'
zstyle ':completion:*:descriptions' format ' %F{yellow}-- %d --%f'
zstyle ':completion:*:messages' format ' %F{purple} -- %d --%f'
zstyle ':completion:*:warnings' format ' %F{red}-- no matches found --%f'
zstyle ':completion:*:default' list-prompt '%S%M matches%s'
zstyle ':completion:*' format ' %F{yellow}-- %d --%f'
zstyle ':completion:*' group-name ''
zstyle ':completion:*' verbose yes

Current style:

image

With grouping and coloring:

image

I don't care about group names too much, we could just hide them, but I do think coloring different types of autocomplete is useful and nice.

  1. "Additional Zsh startup files" in README

I would suggest to rephrase this a little, let me give you an example when editing those files makes sense: it is a nice and easy way to start GUI. Here's how I do it:

  • In .zprofile I have [[ -z $DISPLAY && "$(tty)" == "/dev/tty1" ]] && exec sway
  • In .zshenv I have a list of environment variables that I want to be exported both in terminal and also for GUI
    • .zshenv is loaded before .zprofile, so whatever I export in .zshenv is visible by sway and all GUI apps
  • In .zshrc I have only setup that is relevant for terminal, but not GUI

Let me know if this makes sense. Right now I simply put all my variables on top of .zshenv generated by z4h, but I'm wondering if the README needs to be adjusted to relax the bold phrase a bit, maybe just say that everything that z4h generates must be preserved without modifications?

  1. Avoid exporting XDG_CACHE_HOME

I would suggest to drop this line:

export XDG_CACHE_HOME="$HOME/.cache"

I believe every software knows how to fallback to $HOME/.cache in the absence of that variable, and it should be a very conscious user decision to export all those XDG_* variables, let's not do it for them.

  1. Add TIMEFMT='user=%U system=%S cpu=%P total=%*E' to z4h

First saw it in your dotfiles, and instantly fell in love. I believe it's exactly one of those things that makes zsh for humans and should be done for everyone 🙂

  1. Terminal title to contain timestamp

Because transient prompt (often) removes the timestamp of when a command was started, you once recommended me to add the time to the terminal title instead, to be able to see how long the command is already running. I still think it was a great idea, might be worth adding directly to z4h? Time is only needed for when a command is running (not when title shows current dir), and maybe only when transient prompt is enabled (but I'd probably just show the time always when command is running). What do you think?

  1. Support moooooore LS_COLORS

Have you seen this project? https://github.com/trapd00r/LS_COLORS

I think it would be very cool to tap into their work and have an integration with it, just like you do with zsh-syntax-highlight and others. Currently I can source their file and it will affect my ls, but I don't think tab completion respects this variable, maybe because colors are set immediately after a built-in LS_COLORS is defined?

zstyle ':completion:*' list-colors "${(@s.:.)LS_COLORS}"

  1. Various small ideas

I have had a few small snippets taken from here and there that I use quite frequently, want to show them and see if you would want to take anything directly in z4h:

  • I still use your trick to have a new line added in transient prompt, just curious if noone else requested this to become a simple config variable? :)
typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=off
p10k-on-pre-prompt()  { p10k display '1'=show }
p10k-on-post-prompt() { p10k display '1'=hide }
  • Bind this to Ctrl+/ and it will toggle comment for the currently typed command, just like in VS Code and other editors :)
my-pound-toggle() {
    if [[ "$BUFFER" = '#'* ]]; then
        if [[ $CURSOR != $#BUFFER ]]; then
            (( CURSOR -= 1 ))
        fi
        BUFFER="${BUFFER:1}"
    else
        BUFFER="#$BUFFER"
        (( CURSOR += 1 ))
    fi
}
zle -N my-pound-toggle
  • Bind this to Ctrl+V,V to edit the current command in EDITOR, very useful for multi-line commands
autoload -Uz edit-command-line
zle -N edit-command-line
  • Make Ctrl+Z toggle pressing Ctrl+Z and fg, very useful for quickly checking terminal behind an editor and going back to the editor
my-ctrl-z() {
    if [[ $#BUFFER -eq 0 ]]; then
        BUFFER="fg"
        zle accept-line -w
    else
        zle push-input -w
        zle clear-screen -w
    fi
}
zle -N my-ctrl-z

That's enough for now 😄

UPDATE: OK, one more 😁 Have you considered to add these options to the list of default options in z4h?

  • HIST_IGNORE_ALL_DUPS and HIST_SAVE_NO_DUPS to keep the history file smaller?
  • RC_QUOTES to allow 'Henry''s Garage' instead of 'Henry'\''s Garage'?
@romkatv
Copy link
Owner

romkatv commented Jul 6, 2020

Hey @romkatv! I'm giving z4h/v3 a spin, and would like to share some ideas and ask some questions at the same time

Thanks!

  1. Tab completion: traversing hidden folders

You mentioned it is possible to add an option to traverse hidden folders as well when glob_dots is set, could you please add it or give me a hint how to do this locally?

This should do it:

diff --git a/fn/-z4h-comp-files b/fn/-z4h-comp-files
index 9c63668..02ea709 100644
--- a/fn/-z4h-comp-files
+++ b/fn/-z4h-comp-files
@@ -14,13 +14,13 @@
 
   if (( only_dirs )); then
     if (( dot_glob )); then
-      local dirs=($path_prefix${^${(Q)words:#.*}}/*(D-/Y1N:h:t))
+      local dirs=($path_prefix${^${(Q)words}}/*(D-/Y1N:h:t))
     else
       local dirs=($path_prefix${^${(Q)words:#.*}}/*(-/Y1N:h:t))
     fi
   else
     if (( dot_glob )); then
-      local dirs=($path_prefix${^${(Q)words:#.*}}/*(DY1N:h:t))
+      local dirs=($path_prefix${^${(Q)words}}/*(DY1N:h:t))
     else
       local dirs=($path_prefix${^${(Q)words:#.*}}/*(Y1N:h:t))
     fi
@@ -36,7 +36,6 @@
       cmd+=(-path ./${(b)dir}/'*' -o)
     done
     cmd[-1]=(')' -prune)
-    cmd+=(-o -name '.*' -prune)
     (( dot_glob )) && cmd+=(-print)
     cmd+=(-o -print)
   fi
diff --git a/fn/z4h-cd-down b/fn/z4h-cd-down
index ba47b08..ee71d35 100644
--- a/fn/z4h-cd-down
+++ b/fn/z4h-cd-down
@@ -9,7 +9,7 @@
 
   if (( dot_glob )); then
     local dirs=(./*(-/DN))
-    local non_empty=(${^${dirs:#./.*}}/*(D-/Y1N:h:t))
+    local non_empty=(${^dirs}/*(D-/Y1N:h:t))
   else
     local dirs=(./*(-/N))
     local non_empty=(${^dirs}/*(-/Y1N:h:t))
@@ -23,7 +23,6 @@
       cmd+=(-path ./${(b)dir}/'*' -o)
     done
     cmd[-1]=(')' -prune)
-    cmd+=(-o -name '.*' -prune)
     (( dot_glob )) && cmd+=(-print)
     cmd+=(-o -print)
   fi

The standard completion system respects ignored-patterns.

This was a great hint, just as one idea it allows to ignore .zwc files, for example with zstyle ':completion:*:*:kak:*:*' ignored-patterns '*.zwc' opening .p10k.zsh in editor is simpler, as kak .p<Tab> now has only one match instead of two, so fzf doesn't show up at all and I go straight to .p10k.zsh.

I like this! I added this zstyle to zsh4humans.

Currently recursive directory listing doesn't respect it but it's on my TODO list to fix this.

Would be awesome! Could you please suggest what would be a proper zstyle syntax that you want to support for ignoring folders for cd? Say for example I wanted to ignore ~/.cache/ and ~/.docker/ and everything underneath them.

I don't know yet.

  1. Tab completion: do not require space to search different dirs

Suppose I just cloned zsh4humans, I press <Alt-Down> and I want to navigate to zsh4humans/fn. Typing z fn will find it, but typing zfn will not. I am used to just typing in fzf without having to think where I should put spaces... Could we at least have an option, if the current behavior is something you prefer?

You are using an unreleased version of zsh4humans, which is essentially my personal dotfiles. I'm experimenting with --exact fzf flag right now, which turns off fuzzy matching by default. You can still get fuzzy matching for a term with 'zfn. You can also search for --exact in zsh4humans and remove it.

FWIW, after a few days of adjusting to --exact I very much prefer it. Fuzzy matching in fzf is its main weakness. All other fuzzy finders I've tried have much better fuzzy matching logic.

By the way, while <Alt-Down> shows

zsh4humans
zsh4humans/fn

But cd <Tab> shows

zsh4humans
./zsh4humans/fn

That's a bug. Fixed.

  1. Tab completion: fzf-tab continuous-trigger

Am I right that it will become unnecessary when everything will be traversed?

It's still necessary for two reasons.

  1. Not all directories are traversed by default. E.g., .git is not traversed but sometimes I want to type something like cat .git/HEAD or ls .git/refs/remotes/*/*.
  2. If you tab-complete in a giant directory tree with the goal of retrieving x/blah, you can quickly find x/ and press Tab instead of waiting for everything before x/ to be traversed first.
  1. Tab completion: multiple selection doesn't seem to work

Works for me.

docker run -e TERM -e COLORTERM -w /root -it --rm alpine sh -uec '
  apk add zsh curl
  echo POWERLEVEL9K_DISABLE_CONFIGURATION_WIZARD=true >~/.p10k.zsh
  sh -c "$(curl -fsSL https://raw.githubusercontent.com/romkatv/zsh4humans/v3/install)"'

image

And then, after pressing Enter:

image

(Superfluous spaces between arguments are the result of a bug in fzf-tab. I don't know yet if it's fixable.)

Have you considered adding groups and using different colors to fzf completion?

Maybe. In general I don't like group colors because it can look awful without sorting (and I don't want to enable sorting of completion candidates) and interferes with fzf's highlighting of matched terms. If fzf supported highlting via reverse video, that would help.

  1. "Additional Zsh startup files" in README

I would suggest to rephrase this a little

I haven't updated docs in v3 yet. You may have noticed that v3 has two rc files but the docs say there is just one.

  • In .zprofile I have [[ -z $DISPLAY && "$(tty)" == "/dev/tty1" ]] && exec sway

This is awful. Does you OS come without init system? Using zsh rc files to start services isn't something I would recommend or consider a valid use case.

  • In .zshenv I have a list of environment variables that I want to be exported both in terminal and also for GUI

This is equally awful. Does you system come without /etc/environment, ~/.pam_environment or equivalent? .zshenv is for setting up environment specific to zsh. It's evaluated in every zsh process (e.g., zsh -c 'echo hi'). What you are looking for is environment that gets set up when a user logs in.

  1. Avoid exporting XDG_CACHE_HOME

I would suggest to drop this line:

export XDG_CACHE_HOME="$HOME/.cache"

Removed. This line was originally in .zshrc so that users who do want to override XDG_* knew where to put them. In v3 I've moved the top of .zshrc to .zshenv because that code is very tricky and because 99.9% of users shouldn't change it. I also envision that some users will want to have ZDOTDIR=~/.zsh or similar, and this setup has explicit support for it.

  1. Add TIMEFMT='user=%U system=%S cpu=%P total=%*E' to z4h

Done.

  1. Terminal title to contain timestamp

I plan to support it via zstyle where you can specify preexec and precmd terminal title formats similarly to prompt (with %-escapes and stuff).

Because transient prompt (often) removes the timestamp of when a command was started, you once recommended me to add the time to the terminal title instead, to be able to see how long the command is already running. I still think it was a great idea, might be worth adding directly to z4h? Time is only needed for when a command is running (not when title shows current dir), and maybe only when transient prompt is enabled (but I'd probably just show the time always when command is running). What do you think?

Maybe. I prefer to show less by default and let users add extra stuff if they want. I think it's better than showing stuff than users don't want (even if they have an option to turn it off).

  1. Support moooooore LS_COLORS

Have you seen this project? https://github.com/trapd00r/LS_COLORS

Yes. I used it in the past.

Currently I can source their file and it will affect my ls, but I don't think tab completion respects this variable, maybe because colors are set immediately after a built-in LS_COLORS is defined?

That's a bug. Fixed.

My position here is the same as w.r.t. to terminal title. zsh4humans by default should be usable and should have all vital features. Extra features should be easy to turn on. Every time users want to turn something off, it's worse than when users want to turn something on. Both of these imply that the defaults aren't optimal for the user but turning off is worse than on.

trapd00r/LS_COLORS is easy to enable for those who want it. If it was on by default, I would turn it off in my own dotfiles. The more colors you add to regular files, the more difficult it becomes to distinguish between regular and special files. That distinction is important to me.

I think some regular file colors would help me but I cannot think of a default that would work for everyone.

  • I still use your trick to have a new line added in transient prompt, just curious if noone else requested this to become a simple config variable? :)

I don't think anyone has asked for it. If this were to become popular, I could add an option to the configuration wizard.

  • Bind this to Ctrl+/ and it will toggle comment for the currently typed command, just like in VS Code and other editors :)

This looks like what I used to have in my .zshrc. Nowadays I use Alt+O instead. It requires fewer keystrokes to recover the stashed command. I also want to try push-input and see how that goes.

  • Bind this to Ctrl+V,V to edit the current command in EDITOR, very useful for multi-line commands

I used it for a while but I no longer do. Editing in $EDITOR means no completions and no syntax highlighting. I now edit multi-line commands directly in zle. It takes a little while to get used to pressing Alt+Enter instad of Enter but after that it's quite comfortable.

  • Make Ctrl+Z toggle pressing Ctrl+Z and fg, very useful for quickly checking terminal behind an editor and going back to the editor
my-ctrl-z() {
    if [[ $#BUFFER -eq 0 ]]; then
        BUFFER="fg"
        zle accept-line -w
    else
        zle push-input -w
        zle clear-screen -w
    fi
}
zle -N my-ctrl-z

The idea looks interesting although the specifics look rather unintuitive to me. How about this?

my-ctrl-z() {
  (( ${(%):-%j} > 0 )) && fg
}
zle -N my-ctrl-z
bindkey '^Z' my-ctrl-z

That's enough for now

UPDATE: OK, one more Have you considered to add these options to the list of default options in z4h?

  • HIST_IGNORE_ALL_DUPS

Currently if you press Ctrl+R, you'll see all commands you've typed in the current zsh session (except for consecutive dups). I find it valuable. HIST_IGNORE_ALL_DUPS will lose that.

to keep the history file smaller?

z4h sets HIST_SAVE_NO_DUPS, so dups are not saved to the history file.

HIST_SAVE_NO_DUPS

This is set.

  • RC_QUOTES to allow 'Henry''s Garage' instead of 'Henry'\''s Garage'?

This is too dangerous to enable by default as it changes the meaning of POSIX-compliant commands. Can be very surprising. Users who want this option can put it in their own .zshrc.

romkatv added a commit that referenced this issue Jul 6, 2020
@romkatv
Copy link
Owner

romkatv commented Jul 6, 2020

I recalled there is one more case where I use continuous tab completion.

mkdir -p /tmp/a/b{1,2}/c{1,2}
cd /tmp/a/b/c<TAB>

This will first offer you to choose between b1 and b2. If you confirm your selection with Tab, it'll immediately present you with the choice between c1 and c2.

By the way, have you tried z4h ssh? Do you use ssh often? I can give you a short intro about setting it up to take full advantage of file transfers to the remote and then back to local host. For me z4h ssh (which I invoke simply as ssh) was one of the main reasons I've switched to z4h.

@maximbaz
Copy link
Contributor Author

maximbaz commented Jul 6, 2020

Tab completion: traversing hidden folders

This should do it...

Yup, works, thanks 🙂

I'm experimenting with --exact fzf flag right now, which turns off fuzzy matching by default. You can still get fuzzy matching for a term with 'zfn. You can also search for --exact in zsh4humans and remove it.
FWIW, after a few days of adjusting to --exact I very much prefer it. Fuzzy matching in fzf is its main weakness. All other fuzzy finders I've tried have much better fuzzy matching logic.

Thanks for the hint! I do agree that the matching algorithm in fzf is worse than in competitors, but I still prefer the fuzzy flow 🙂 I removed --exact for now.

I guess long-term it would make sense to leave it up to users to put --exact to their $FZF_DEFAULT_OPTS, I imagine flags like --exact are very subjective to people's preferences and with these flags consistency is very important with how you are using fzf for everything else outside of z4h (in other words, not to confuse your muscle memory, if you use --exact outside of z4h you would want to have --exact also in z4h, and the opposite). What do you think?

Am I right that it will become unnecessary when everything will be traversed?

It's still necessary for two reasons...
I recalled there is one more case where I use continuous tab completion.

Riiiight, makes total sense.

Tab completion: multiple selection doesn't seem to work

Works for me....

Uh, my bad, turns out Ctrl+Space was bound by another app. It's working now 🙂

What would be nice if Ctrl+Space would not only toggle the current element, but also move to the next one. Because when you multi-select, you usually select several items, usually consequent, so there is little reason to stay on the current item.

This is awful. Does you OS come without init system?
This is equally awful. Does you system come without /etc/environment, ~/.pam_environment or equivalent?

Hehe 🙂 I'm still in search for a good way to manage this, but PAM environment is also not ideal as its syntax is limited in what you can do, and then people tend to have their variables declared all over the place... In any case, your point is accepted 👍

Every time users want to turn something off, it's worse than when users want to turn something on. Both of these imply that the defaults aren't optimal for the user but turning off is worse than on.

I like this logic!

Make Ctrl+Z toggle pressing Ctrl+Z and fg

The idea looks interesting although the specifics look rather unintuitive to me. How about this?

This one has two downsides:

  • It "breaks" transient prompt, as in if you open an editor and then press Ctrl+Z 6 times, you will see that part of the prompt will not become transient, it will have all the icons
  • When you finally exit the editor, the prompt will be "dirty", there will be text "[1] + continued" in the prompt already typed, and the latest prompt will still contain the icon for background job

image

To be frank, the snippet I posted is also not ideal, if you press Ctrl+Z 6 times your prompt will also contain useless garbage. The true ideal behavior would be like Alt+<arrow> bindings behave in z4h, where the prompt is being redrawn instead of being "submitted", i.e. the cursor stays on the same line in the terminal. I don't know if it's possible to achieve though...

By the way, have you tried z4h ssh? Do you use ssh often?

I use it often, I have tried z4h ssh and find it amazing! By the way, I confirm that with the latest zsh-bin everything works perfectly with kitty.

I can give you a short intro about setting it up to take full advantage of file transfers to the remote and then back to local host.

Would really appreciate this!


And thanks for all the fixes you have already made after this thread 🙂

@romkatv
Copy link
Owner

romkatv commented Jul 6, 2020

I guess long-term it would make sense to leave it up to users to put --exact to their $FZF_DEFAULT_OPTS

This is what worries me the most when you try a version of my code that isn't yet ready for others to use. On one hand it's great to have early feedback. On the other hand you find the product and the code behind it of worse quality than what you came to expect, and your feedback is also higher on noise than normal (but still very valuable) due to the observations of "I know" kind.

It's not my plan to have --exact hard-coded. It's just something I can do to my own dotfiles to see how it feels. When v3 is released, it will definitely have a way to control fzf flags, and it'll almost certainly be done with zstyle. Since z4h doesn't use any of the builtin fzf widgets, it doesn't make sense to respect FZF_* parameters. I've already yanked them out in preparation.

If v3 will have a default for fuzzy/not-fuzzy search, it'll be fuzzy. It'll be easy to change. Non-fuzzy isn't so much better to warrant going against the status quo established by fzf.

I'm not sure if I mentioned it before. If everything goes well, v4 will likely be the last version of zsh4humans. Or to put it the other way, v3 will be the last version that I don't want to become popular because I want to break backward compatibility one more time. Before I release v3, I'll address some major issues and clean things up. I'll try to keep the release low key just like the previous versions. I want feedback but only from intelligent users. v4 will have a setup wizard similar to the one in p10k where you'll be able to choose this vs that for the common options that I anticipate. Once v4 is out, I'll maintain backward compatibility for as long as I muster.

What would be nice if Ctrl+Space would not only toggle the current element, but also move to the next one.

Good idea. I don't control fzf but maybe it's something I can add upstream.

This one has two downsides:

  • It "breaks" transient prompt, as in if you open an editor and then press Ctrl+Z 6 times, you will see that part of the prompt will not become transient, it will have all the icons

Ah, you want something like Alt+Tab for full-screen apps in the terminal? That sounds cool! I'll see what I can do.

By the way, I confirm that with the latest zsh-bin everything works perfectly with kitty.

Thanks!

I can give you a short intro about setting it up to take full advantage of file transfers to the remote and then back to local host.

Would really appreciate this!

I've put it on my TODO list. Will ping you later.

And thanks for all the fixes you have already made after this thread 🙂

Thanks for the suggestions and bug reports! Invaluable as always.

@maximbaz
Copy link
Contributor Author

maximbaz commented Jul 6, 2020

This is what worries me the most when you try a version of my code that isn't yet ready for others to use. On one hand it's great to have early feedback. On the other hand you find the product and the code behind it of worse quality than what you came to expect, and your feedback is also higher on noise than normal (but still very valuable) due to the observations of "I know" kind.

Makes sense 🙂 Don't get me wrong, I knew what I subscribed for when I decided to try v3 despite your warning about it not being ready - feel free to just reply with "I know" on such comments 👍

Ah, you want something like Alt+Tab for full-screen apps in the terminal? That sounds cool! I'll see what I can do.

Precisely!


Found a small issue when testing history retrieval over ssh, on closing connection I get this error:

(anon):zf_mv:1: /tmp/zshxurItS: invalid cross-device link

It is coming from this line:

() { fc -pa -- $1 $HISTSIZE $SAVEHIST } $1 && zf_mv -f -- $1 $local_hist

My /tmp is on RAM (tmpfs), and it seems zf_mv cannot move files between different devices; changing zf_mv to mv on that line fixes the issue but I'm not sure it's the right approach.

@romkatv
Copy link
Owner

romkatv commented Jul 6, 2020

Found a small issue when testing history retrieval over ssh, on closing connection I get this error:

Thanks!

it seems zf_mv cannot move files between different devices

Yeah, this annoying limitation is even documented. It's really annoying when you are trying to write fast crash-safe code.

changing zf_mv to mv on that line fixes the issue but I'm not sure it's the right approach.

This isn't safe. Pick up the right fix here: c200c73.

@maximbaz
Copy link
Contributor Author

maximbaz commented Jul 6, 2020

I found a... weirdness 🤔

Say I have a file aliases.zsh containing the following:

alias sayhello='echo hello'
greet() { sayhello world }

If I source aliases.zsh in .zshrc, open a new shell and run greet world, it will work as expected. But if I instead z4h source aliases.zsh in .zshrc, then greet world will not expand the alias and crash with command not found: sayhello

Seems like if you source a script from within a function, it does it... in a different context or something 🤔

It's easy to workaround (e.g. by replacing the alias with sayhello() { echo "$@" }), but maybe you'll have any ideas how to make the behavior of z4h source match source...

@romkatv
Copy link
Owner

romkatv commented Jul 7, 2020

I found a... weirdness

Aww, that sucks. I've asked on zsh-workers: https://www.zsh.org/mla/workers//2020/msg01019.html. I'm not holding my breath though.

@maximbaz
Copy link
Contributor Author

maximbaz commented Jul 7, 2020

Another small observation: bash completions seem to be loaded too late in the game, for example in order to enable completions for azure-cli we need to z4h source this file in .zshrc, and it would fail unless we also autoload and call bashcompinit manually. I'm not sure if this is just a matter of extracting bashcompinit out of -z4h-post-init(), because there is some other stuff related to the completions in that function... 🤔

romkatv added a commit that referenced this issue Jul 8, 2020
@romkatv
Copy link
Owner

romkatv commented Jul 8, 2020

Another small observation: bash completions seem to be loaded too late in the game

Thanks for letting me know. To be honest, I haven't tested this feature and I don't use bash completions myself.

I've moved the call to bashcompinit to z4h init, so az completions should work. There are still cases where it won't work though. E.g., complete -p and complete -r won't work until zsh is fully initialized. I don't know if bash completion functions ever call these during initialization.

@romkatv
Copy link
Owner

romkatv commented Jul 9, 2020

Aww, that sucks. I've asked on zsh-workers: https://www.zsh.org/mla/workers//2020/msg01019.html. I'm not holding my breath though.

I received the reply I expected from reading the code of zcompile.

  1. zcompile foo && source foo is not equivalent to source foo in one aspect: the former won't expand aliases defined in foo while sourcing foo. This is by design.
  2. You shouldn't use aliases in scripts. That's not what they are meant for.

While I agree with (2), I cannot enforce it and I don't want to have this gotcha in z4h source. So I've changed z4h source to not compile by default. You can pass -c to enable compilation.

# Do not zcompile.
z4h source foo.zsh
# Do zcompile.
z4h source -c bar.zsh

Note that -c doesn't always speed things up. Compared to plain z4h source, it takes additional N - M * file_size seconds. If the file is very small, z4h source -c is slower than plain z4h source. The threshold is fairly low though.

@maximbaz
Copy link
Contributor Author

maximbaz commented Jul 9, 2020

Do you have any plans for merging <Alt-down> and cd <Tab> to have a common implementation underneath both features? Just thinking that it takes time to maintain both, and from a user perspective it is kinda annoying when you stumble upon minor inconsistencies between them (because over time you stop noticing which one of the two you use). I found myself using fzf-tab continuous-trigger quite often actually (for one of the cases you mentioned, to stop traversing everything and focus on a certain dir), and this feature is only available via cd <Tab>.

In general I've been extensively using v3 this entire week, testing different features, and I must say it is working really great, very solid work!

@romkatv
Copy link
Owner

romkatv commented Jul 10, 2020

Do you have any plans for merging <Alt-down> and cd <Tab> to have a common implementation underneath both features?

I think you want to ask a different question.

from a user perspective it is kinda annoying when you stumble upon minor inconsistencies between them

That's a good question. Or rather a good bug report / feature request.

I found myself using fzf-tab continuous-trigger quite often actually (for one of the cases you mentioned, to stop traversing everything and focus on a certain dir), and this feature is only available via cd <Tab>.

Fixed. Now Tab works in Alt+Down.

In general I've been extensively using v3 this entire week, testing different features, and I must say it is working really great, very solid work!

Thanks! I'm glad.

By the way, what do you think of word-based widgets? Do you use them? Have you noticed that they are different from the stock widgets? Do they behave the way you would expect?

Perhaps there are more widgets that you haven't tried? Here's the list of bindings that I recommend trying.

Cursor movement

Bindings Description
Ctrl+Left Previous word
Ctrl+Right Next word
Ctrl+Home Beginning
Ctrl+End End

Deletions

Bindings Description
Ctrl+Backspace Previous word
Ctrl+Delete Next word
Alt+K Everything left of cursor
Ctrl+K Everything right of cursor
Ctrl+U Current line
Alt+J Everything

History

Bindings Description
Up Previous local history event
Down Next local history event
Ctrl+Up Previous shared history event
Ctrl+Down Next shared history event

Miscellaneous

Bindings Description
Alt+M Accept autosuggestion without moving cursor
Alt+O Push command to history without executing
Ctrl+/ Undo
Alt+/ Redo
Alt+H Show help for command

Undo is super useful. I undo Tab completions often. For example, I might type something like rmdir -- ./**/*~*/.git/*(/^F), hit Tab to expand the glob, visually validate that it does what I expect (this one is supposed to match empty directories recursively except in .git), and then hit Ctrl+/ to undo the expansion before executing the command. This way I have the command with an unexpanded glob in my history in case I want to run it again.

Another common use case for Undo is after pasting form clipboard. I often find out that clipboard has something other than what I expect.

Local history (Up) vs global history (Ctrl+Up) is great if you use several zsh sessions at once.

The default behavior of prefix-based history widgets (like Up in z4h) is to move cursor to the end. This has some unintuitive consequences as it effectively introduces two cursors. One cursor is visible, and it's positioned at the end. The other cursor is invisible and it's positioned at the same place where it was before you pressed Up. The invisible cursor demarcates the command prefix used by the widget in case you press Up again. Here's an example of how it usually works.

  • Type cd and press Up. You'll see the last command from your history that starts with cd . Let's say it's cd ~/foo.
  • Now you have a visible cursor at the end and an invisible cursor after cd .
  • Press Up. You'll see the one before last command from your history that starts with cd . Perhaps cd /bar.

The last point is tricky because it requires you to remember where the invisible cursor is. Many actions lead to the invisible cursor change its position to align with the visible cursor, so this can be tricky. E.g., if after the first Up you were to manually move cursor to the left and then back, the next Up wouldn't give you cd /bar. Instead, it would give you a command that starts with cd ~/foo.

In z4h there is always one cursor position. Or, to put it another way, the invisible cursor is always at the same position as the visible. This is achieved by not changing the cursor position when you press Up. This makes it much easier to reason about Up. This key always gives you a command that has the same prefix as the current command line up to the cursor.

I also noticed that when I press Up I'm more likely to change the command at the front rather than at the back (add sudo, or some flag), so it also saves keystrokes.

Alt+H is nice. Try typing typeset and hitting this key combo. Also try it on git clone.

I use Alt+M often. If you want to accept an autosuggestions and edit something close to the current cursor position, Alt+M can save many keystrokes.

Ctrl+K, Alt+K and Alt+J make command line editing much more efficient.

Let me know if you discover any issues with these or have improvement suggestions.

@maximbaz
Copy link
Contributor Author

By the way, what do you think of word-based widgets? Do you use them? Have you noticed that they are different from the stock widgets? Do they behave the way you would expect?

There maybe are some subtle differences comparing to what I was used to (like $WORDCHARS, will get to that in a second), but in general they behave the way I expect, I think defaults are chosen well.

Perhaps there are more widgets that you haven't tried? Here's the list of bindings that I recommend trying.

Oh thanks for sharing so much details!

  • Movement & Deletions shortcuts

    The keys are intuitive once you read through them 👍

    I noticed you set WORDCHARS to empty string, it makes sense for precision jumps (e.g. when you want to update something in the middle of a file path), but on the other hand sometimes you just want to get to the beginning of a long file path and it is annoying to press Ctrl+Left many times.

    What do you think about implementing two additional shortcuts that would jump to a next/previous whitespace? This idea is inspired by vim and other modal editors, where you have shortcuts that operate on word and WORD. Ctrl+Alt+Left/Right seems to be available?

    I think it could also be a good idea to set WORDCHARS='' in z4h-init only if WORDCHARS var is not defined by that point yet, in case user does want to customize it before loading z4h.

  • History shortcuts

    Good idea, but I might be doing something wrong, they all seem to operate on a local history.

    Is my expectation correct in this example?

    • Open two terminals side by side
    • In terminal 1 run echo 1
    • In terminal 2 run echo 2
    • Back in terminal 1, if I press Ctrl+Up I should get echo 2, but I get echo 1

    As for prefix-based history widgets:

    The default behavior of prefix-based history widgets (like Up in z4h) is to move cursor to the end. This has some unintuitive consequences as it effectively introduces two cursors...

    Riiiiight, that's why when I was using this plugin separately (before z4h), it would change background color of the text between the beginning of the prompt and the invisible cursor, to highlight the common prefix part that is being searched...

    I definitely think you found a more intuitive approach than that.

  • Alt+O is amazing! This is what I was using "toggle comment" for, but now it's 100 times better.

  • Ctrl+/ and Alt+/ are amazing! Your examples are awesome demo, I will learn to use them more.

    The only feedback I have is that having a default binding use special symbols will most likely not work well for international people, for example @cyrinux uses Azerty and he has to press Shift+: in order to get / char, and so when you press Ctrl+Shift+<anything>, this binding is not being passed to zsh, terminal catches it.

    I don't have a good alternative in mind, and of course it's easy to change, but if you can think of a different default, it might be worth considering.

  • Alt+H is a good one too, I also haven't used it before!

    Try typing typeset and hitting this key combo. Also try it on git clone.

    Wow! I have a couple of suggestions, but I think they all might be suggestions for run-help which you don't control...

    1. It prints to stdout how it expands commands and aliases, I don't really need to see that info
    2. When I have alias gcl="git clone --recursive", $ gcl<Alt-h> shows help for git, not git clone (even without --recursive)
  • Alt+M is again something I haven't used before, but your example makes a very good case!

@romkatv
Copy link
Owner

romkatv commented Jul 13, 2020

There maybe are some subtle differences comparing to what I was used to (like $WORDCHARS, will get to that in a second), but in general they behave the way I expect, I think defaults are chosen well.

Let me show how z4h word-based widgets are different from the defaults. Suppose you have this command line:

ls / foo/bar

The default forward-word with the default WORDCHARS (which includes /) will go over the following cursor positions:

ls / foo/bar
^  ^ ^

This is OK-ish but too coarse most of the time. Ideally, there should be another position where the cursor stops -- somewhere between foo and bar.

Without / in WORDCHARS:

ls / foo/bar
^    ^   ^

Note how the cursor jumps over the first argument of ls. This problem becomes more apparent if you set WORDCHARS to empty (like most zsh users seem to do).

ls . / $_ &> foo/bar
^            ^   ^

That jump from ls straight to foo really sucks.

For comparison, in z4h it looks like this:

ls . / $_ &> foo/bar
^  ^ ^ ^  ^  ^   ^

sometimes you just want to get to the beginning of a long file path and it is annoying to press Ctrl+Left many times.

Indeed.

What do you think about implementing two additional shortcuts that would jump to a next/previous whitespace?

I've added 4 new widgets:

# Move cursor one zsh word forward.
bindkey '^[[1;6C' z4h-forward-zword        # ctrl+shift+right
# Move cursor one zsh word backward.
bindkey '^[[1;6D' z4h-backward-zword       # ctrl+shift+left
# Delete next zsh word.
bindkey '^[[3;6~' z4h-kill-zword           # ctrl+shift+del
# Delete previous zsh word.
bindkey '^[^H'    z4h-backward-kill-zword  # ctrl+alt+bs

Here's how they tokenize commands:

foo '  bar / baz  ' $(qux quux)
^   ^               ^

I'm running out of decent keys to bind things to, so you'll likely have to rebind these to whatever works for you.

Let me know what you think about these widgets.

I think it could also be a good idea to set WORDCHARS='' in z4h-init only if WORDCHARS var is not defined by that point yet, in case user does want to customize it before loading z4h.

You can set WORDCHARS in ~/.zshrc after z4h init.

  • History shortcuts
    Good idea, but I might be doing something wrong, they all seem to operate on a local history.
    Is my expectation correct in this example?

    • Open two terminals side by side
    • In terminal 1 run echo 1
    • In terminal 2 run echo 2
    • Back in terminal 1, if I press Ctrl+Up I should get echo 2, but I get echo 1

Zsh reads shared history before precmd, so you need to press Enter in terminal 1 to pick up the latest command from terminal 2.

@cyrinux uses Azerty and he has to press Shift+: in order to get / char, and so when you press Ctrl+Shift+<anything>, this binding is not being passed to zsh, terminal catches it.

Noted. Eventually z4h will have an interactive wizard for setting up bindings but for now I'm afraid the only solution is to rebind things in zshrc.

suggestions for run-help [...]

  1. It prints to stdout how it expands commands and aliases, I don't really need to see that info
  2. When I have alias gcl="git clone --recursive", $ gcl<Alt-h> shows help for git, not git clone (even without --recursive)

(1) doesn't seem terrible but (2) is something I'll try to fix. I also noticed what appears to be inconsistent behavior:

% alias ls='ls --color=auto'
% run-help ls
ls is an alias for ls --color=auto
Press any key for more help or q to quit

If I press any key other than q, it'll open man page on ls. Seems fine. However, with alias gcl="git clone --recursive" man gets opened automatically.

@maximbaz
Copy link
Contributor Author

maximbaz commented Jul 13, 2020

Let me show how z4h word-based widgets are different from the defaults

Uh, yeah definitely z4h approach is a lot better! And with the 4 new widgets the workflow is very nice, easy to choose if you want to make a short and precise jump vs long to the end of the zword jump.

I've added 4 new widgets:
I'm running out of decent keys to bind things to, so you'll likely have to rebind these to whatever works for you.

Using Ctrl+Shift makes sense (also is consistent with text editors where you additionally press Shift to jump by WORD), I cheated and made kitty terminal send ^[^H when I press Ctrl+Shift+Backspace, so that all 4 new key bindings use Ctrl+Shift consistently. In kitty you also must "open up" Ctrl+Shift keys before they are available to zsh, so if you are interested, the full config is this:

map ctrl+shift+left      noop
map ctrl+shift+right     noop
map ctrl+shift+delete    noop
map ctrl+shift+backspace send_text all \x1b\x08

Other than that, these widgets behave exactly as I expect them to do, and I think they are a very nice addition to the toolkit.

Zsh reads shared history before precmd, so you need to press Enter in terminal 1 to pick up the latest command from terminal 2.

Ooh, I see! Yes now I can reproduce the difference between local and global history.

Would it make sense to make zsh read shared history on Ctrl+Up keypress as well? Maybe together with some smart way of detecting if it has to vs if history file hasn't changed since the last time it was read. Just to make this feature a bit more obvious for users who don't know how it is implemented internally.

UPDATE 1: I know you added bindkey -M emacs '^H' backward-kill-word to .zshrc for demo purposes, but would make sense to also have that binding in the core z4h (and be mapped to z4h-backward-kill-word instead)

UPDATE 2: There's also a small issue with z4h-backward-kill-word, it doesn't move the cursor upon removal. Type cat one.txt | grep something, put cursor right before the dot and press Ctrl+W to remove one (maybe with an intention to write two instead), but the cursor will no longer stay on the dot.

@romkatv
Copy link
Owner

romkatv commented Jul 14, 2020

Using Ctrl+Shift makes sense (also is consistent with text editors where you additionally press Shift to jump by WORD)

I think Ctrl is the standard key modifier on Windows and Linux to move/delete words. Holding shift usually enables selection, so Ctrl+Shift+Right selects the next word.

By the way, I've been contemplating implementing the same Shift behavior in Zsh. I think it can be reproduced exactly with just one difference. After selecting text with Shift+Arrows you'll have to use a shortcut other than the standard you've configured in the terminal to copy to clipboard. E.g., I normally copy text from the terminal to clipboard with Ctrl+Shift+C or Ctrl+Insert but here I'll need to press Ctrl+S or something like that. (Currently my Ctrl+S binding copies the whole command line to clipboard.)

What do you think of this?

I cheated and made kitty terminal send ^[^H when I press Ctrl+Shift+Backspace, so that all 4 new key bindings use Ctrl+Shift consistently. In kitty you also must "open up" Ctrl+Shift keys before they are available to zsh, so if you are interested, the full config is this:

map ctrl+shift+left      noop
map ctrl+shift+right     noop
map ctrl+shift+delete    noop
map ctrl+shift+backspace send_text all \x1b\x08

Nice!

Would it make sense to make zsh read shared history on Ctrl+Up keypress as well?

Yes, that would definitely be better but it's very difficult to achieve. z4h simply exposes the builtin zsh history via bindings. In order to read global history on Ctrl+Up I would need to write a ton of code.

In Zsh, anything that uses history can request either local or global history (there is also internal history but it's less interesting). I chose for Ctrl+R and for autosuggestions to use global history, but I could also choose to use local, or to provide Ctrl+Shift+R for local history. I didn't do this because it doesn't seem very useful.

On the other hand, I made Up and Down use local history. I think this is what everyone expects and what I prefer myself.

When I just added Ctrl+Up and Ctrl+Down I was using them a lot. Nowadays Ctrl+R without a query shows your whole global history, so most of the time I use Ctrl+R instead of Ctrl+Up. I'm thinking of removing Ctrl+Up and Ctrl+Down bindings. This will free up these keys for something more useful and I won't have to explain this local/global history distinction.

UPDATE 1: I know you added bindkey -M emacs '^H' backward-kill-word to .zshrc for demo purposes, but would make sense to also have that binding in the core z4h (and be mapped to z4h-backward-kill-word instead)

I don't want to overwrite the default bindings in z4h. ^H in emacs keymap is bound to backward-delete-char and some users expect it to work that way. If you have to define an extra binding, that's one thing. You are just adding more stuff on top z4h. But if z4h overrides the default binding that you like, that's quite different. In this case z4h is being overly aggressive and opinionated.

So, instead of following your suggestions I've moved the binding for z4h-backward-kill-zword to .zshrc (^[^H is bound to backward-kill-word by default). You'll need to add it to your own .zshrc.

UPDATE 2: There's also a small issue with z4h-backward-kill-word, it doesn't move the cursor upon removal. Type cat one.txt | grep something, put cursor right before the dot and press Ctrl+W to remove one (maybe with an intention to write two instead), but the cursor will no longer stay on the dot.

Thanks! Fixed.

@maximbaz
Copy link
Contributor Author

I'm thinking of removing Ctrl+Up and Ctrl+Down bindings. This will free up these keys for something more useful and I won't have to explain this local/global history distinction.

I think this reasoning here, and your choice for Ctrl+R and autosuggestions to use global history, all make sense.

Just one question to confirm, I noticed that contrary to Ctrl+Up, Ctrl+R and autosuggestions both require not just pressing Enter, but actually running some other command to refresh the global history - is there a reason for why history is not refreshed for them in precmd?

Example:

  • Open two terminals side by side
  • In terminal 1 run echo 1
  • In terminal 2 run echo 2
  • Back in terminal 1, press Enter, then try Ctrl+R or echo<Up>, both will not see echo 2 until you run something else first in terminal 1.

By the way, I've been contemplating implementing the same Shift behavior in Zsh. I think it can be reproduced exactly with just one difference. After selecting text with Shift+Arrows you'll have to use a shortcut other than the standard you've configured in the terminal to copy to clipboard.

Interesting idea, before I comment too much I'd like to clarify my understanding first, my first impression is that it will only be useful for "copy region to clipboard" operation, because "select to delete" or "select to replace" would require same or more number of keypresses comparing to a simple deletion using Ctrl+{,Shift+}{Delete,Backspace} keys - is that right or am I missing something here?

@romkatv
Copy link
Owner

romkatv commented Jul 14, 2020

I noticed that contrary to Ctrl+Up, Ctrl+R and autosuggestions both require not just pressing Enter, but actually running some other command to refresh the global history - is there a reason for why history is not refreshed for them in precmd?

Example:

  • Open two terminals side by side
  • In terminal 1 run echo 1
  • In terminal 2 run echo 2
  • Back in terminal 1, press Enter, then try Ctrl+R or echo<Up>, both will not see echo 2 until you run something else first in terminal 1.

I confirm this. Looks like a zsh bug at the first glance. I'll dig into it when I get some free time.

Interesting idea, before I comment too much I'd like to clarify my understanding first, my first impression is that it will only be useful for "copy region to clipboard" operation, because "select to delete" or "select to replace" would require same or more number of keypresses comparing to a simple deletion using Ctrl+{,Shift+}{Delete,Backspace} keys - is that right or am I missing something here?

People use shift-select + delete in text editors even though the same logic applies there. If I were to implement this feature in zsh, I'd make delete and backspace work on selection so that it works the way people expect.

I should've mentioned that this is all very speculative. If I could create true terminal selection with Shift-Arrows (the same kind of selection you can produce with a mouse), I would definitely do it but zsh-only selection with custom keys to copy/cut/paste doesn't sound very exciting to me. But maybe am I'm wrong. Maybe I would like it if I tried it.

@tumd
Copy link
Contributor

tumd commented Jul 17, 2020

Sorry for hijacking this issue, but it's called 'Feedback' which is a very general topic, and that's what this post is about.

I was wondering if this function would be acceptable to include in z4h. It's quite subtle until you realize you've used it without knowing it. It does happen from time to time (at least for me) you find or grep for files, copying one of the results and pasting it to your prompt right after you've written cd.

Another thing; I just noticed that e93734c sets the $ZSH variable (?), the same variable-name I have been using for my own zsh-snippets located in ~/.zsh/. And (without actually test it yet by updating z4h) I guess there might be a collision.

ZSH=${ZSH:-${ZDOTDIR:-$HOME}/.zsh}

() {
  for config_file ($ZSH/rc/*.zsh) z4h source $config_file
}

What would be the recommended way to include your own zsh-folder similar to the above?

Thank you for your awesome work and inspiring code. :)

@romkatv
Copy link
Owner

romkatv commented Jul 17, 2020

Sorry for hijacking this issue, but it's called 'Feedback' which is a very general topic, and that's what this post is about.

Sure, feedback is welcome.

I was wondering if this function would be acceptable to include in z4h. It's quite subtle until you realize you've used it without knowing it. It does happen from time to time (at least for me) you find or grep for files, copying one of the results and pasting it to your prompt right after you've written cd.

Maybe, although the motivation is rather low. I don't recall ever having an error from cd because I'd passed an existing file that's not a directory as an argument.

If some feature cannot be simply enabled by the user through their own config, or if enabling it correctly is difficult, tricky or error prone, then it's a strong signal that it must be provided by z4h. This cd function is not of this kind. You can define it in your zshrc or whatever.

Another thing; I just noticed that e93734c sets the $ZSH variable (?)

If this is a question, the answer is yes, it does set ZSH parameter unless it was already set.

the same variable-name I have been using for my own zsh-snippets located in ~/.zsh/. And (without actually test it yet by updating z4h) I guess there might be a collision.

I guess you'd better test it.

What would be the recommended way to include your own zsh-folder similar to the above?

Not sure I understand what you are asking. If you want to create ~/.zsh and point ZSH to it, go ahead. If understand you currently, you've already done that, so 👍

(FWIW, I personally don't find ZSH pointing to ~/.zsh useful. It hardly saves typing and it increases complexity due to indirection and opens up an avenue for clashes. Note that ZSH is used by Oh My Zsh.)

@maximbaz
Copy link
Contributor Author

Want to share a couple of more observations regarding how file completion works, would be nice if it these can be improved:

  1. I noticed that tab completion doesn't cross mountpoint boundaries, for example my /run/user/1000 is mounted on tmpfs, so $ vim /run/<Tab> will not list anything inside /run/user/1000/. I use btrfs with multiple subvolumes, so I stumble upon this quite often. Not critical, but slightly annoying 🙂

  2. In a git repo, try git log -p -- <Tab>, you will only see autocompletions for the files and folders in current dir, but not recursive like you would get with $ vim <Tab>.

@romkatv
Copy link
Owner

romkatv commented Jul 19, 2020

  1. I noticed that tab completion doesn't cross mountpoint boundaries

This is intentional. Weird and bad things can happen if you traverse all directories. To stay on the safe side I made tab completion in z4h stay within a single filesystem.

I've added a note to make it customizable although I don't know yet how exactly it should look like. Perhaps a blacklist of target filesystems into which it's not allowed to recurse if the search has started from another filesystem? The current behavior would be described as blacklist='*' (do not recurse into any filesystems that are different from the starting point). Setting blacklist to '' (empty) would allow recursing into everything. When you notice that recursing into devtmpfs is not something you want, you can add it to the blacklist.

Would that work for you?

  1. In a git repo, try git log -p -- <Tab>, you will only see autocompletions for the files and folders in current dir, but not recursive like you would get with $ vim <Tab>.

Yeah, this really sucks. Not only git completion is dead slow, it also drops most of the information it computes on the floor forcing you to repeatedly perform (slow!) completion.

To fix this one would have to change/patch/hack git completion. No changes in zsh4humans required. It's not possible to do it without changing git completion.

I've added it to my TODO list but it's a good task for anyone else to pick up. It's well isolated and independent from zsh4humans.

What would be really cool is to implement git completion on top of gitstatus. It has all the info. Then it would be super fast. This is just musings though. I suspect it's a ton of work.

@maximbaz
Copy link
Contributor Author

maximbaz commented Jul 19, 2020

Weird and bad things can happen if you traverse all directories.
Setting blacklist to '' (empty) would allow recursing into everything. When you notice that recursing into devtmpfs is not something you want, you can add it to the blacklist.

I see. I think the use-case that I have (which would apply to btrfs, zfs, and maybe others) can be solved without any configuration, if z4h would by default traverse not only the filesystem of the starting point, but also filesystem of where the / is mounted (e.g. $ mount | awk '/on \/ / {print $5}'). I think this should be safe? And I doubt anyone would really ask for more (but let's see).

UPDATE: re-reading your message, I think what you meant by "blacklist='*' (do not recurse into any filesystems that are different from the starting point)" is not what I initially understood, if you are suggesting that if starting point filesystem if btrfs, and a folder is discovered during traversal is mounted also on btrfs, then that folder will be traversed - then this approach will work perfectly well as well, and again maybe configuration is not needed altogether.

If not, then I would suggest providing whitelist instead of blacklist, so that users could just add whitelist='btrfs' and still benefit from ignoring everything else in mount just like vanilla z4h does, without spending too much time on configuring blacklist very precisely.

To fix this one would have to change/patch/hack git completion. No changes in zsh4humans required. It's not possible to do it without changing git completion.

Makes sense!

@romkatv
Copy link
Owner

romkatv commented Dec 20, 2021

And finally, wouldn't it just be simpler for you to develop improvements (e.g. like cwd propagation)

Relevant discussion: kovidgoyal/kitty#3948 (comment) (from this comment and below).

If I merge the two tmux processes into one, things will work seamlessly in all terminals except Kitty. For Kitty I'll still have to use the cwd propagation hack. It's not too bad. The downside of that hack is that in some terminals (Konsole) prompt title becomes broken because their default settings don't trust shells to set prompt title. These terminals (Konsole) proudly display something like /tmp/z4h-tmux-cwd-1000-17925-.dev.tty1 for eternity instead.

@infokiller
Copy link

@infokiller in the default configuration, z4h is using tmux to implement some additional features, but it's a "invisible" tmux, where we almost don't even know that there is a tmux running at all - there are no windows or panes, no mutiplexing, no status bar, etc - so we are not using tmux for what it's used in the traditional sense, it's as if it's not there, and thus using terminal tabs still make sense. You can read more details about how this idea got started and how it evolved over time in this issue, starting from #35 (comment)

Thanks @maximbaz and sorry I missed the earlier discussion. Will this work if I also use tmux as a multiplexer (and using the patched one)?
I searched previous comments that mention tmux using gh issue view 'https://github.com/romkatv/zsh4humans/issues/35' -c and couldn't find an answer, but could have easily missed something in 300 comments :)

Hope I'm not derailing the discussion but I'm also curious why you or other people don't like using tmux in a single terminal tab. I'm referring to these comments:

When I first noticed the word tmux I was prepared to be disappointed

That makes two of us 😅

I personally prefer using tmux in a single terminal tab over using the native terminal tabbing/splitting features in Kitty and other terminals because:

  • It works over SSH and in remote servers that don't have even have graphical programs
  • It doesn't die when the graphical session dies
  • It has pretty great scripting capabilities
  • It's a more modular approach because you can use tmux with any backing terminal (Kitty, GNOME terminal, etc.)

@romkatv
Copy link
Owner

romkatv commented Dec 21, 2021

Thanks @maximbaz and sorry I missed the earlier discussion. Will this work if I also use tmux as a multiplexer (and using the patched one)?

zsh4humans has 3 modes:

  1. integrated tmux (a.k.a. you are using tmux but you don't know that)
  2. regular tmux
  3. no tmux; this is only for debugging

When you run zsh4humans installer, it asks you whether you want zsh to always run in tmux. If you answer Yes, you get (2). If you answer No, you get (1). You can get (3) only by manually modifying zshrc. Doing that will disable some features in zsh4humans.

@vbauerster
Copy link

There is one drawback of seamless tmux integration anyone may encounter. Tmux will suppress modern terminal features like curly underscores, hyperlinks or proper CSI u support.

@romkatv
Copy link
Owner

romkatv commented Dec 22, 2021

@vbauerster This is fixable though. I don't proactively fix these things but when someone complains (with a real use case rather than a theoretical concern), I do.

@infokiller
Copy link

@vbauerster at least for curly underline you can fix it with:

# Enable unofficial extensions to terminfo:
# - 24-bit color (Tc)
# - Overline (Smol)
# - Styled underline (Smulx)
# - Colored underline (Setulc)
set -sa terminal-overrides ',xterm-*:Tc'
set -sa terminal-overrides ',xterm-*:Smulx=\E[4::%p1%dm'
set -sa terminal-overrides ',xterm-*:Setulc=\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m'

@romkatv
Copy link
Owner

romkatv commented Dec 22, 2021

@vbauerster at least for curly underline you can fix it with:

Thanks! I've enabled Smulx and Setulc when Tc is enabled.

@vbauerster
Copy link

@romkatv I believe you can set-option -as terminal-features 'xterm*:usstyle' instead of raw terminal-overrides. Quotation from man:

usstyle Allows underscore style and colour to be set.

@infokiller
Copy link

infokiller commented Dec 22, 2021

BTW, I use this script (mostly copied) to test the terminal capabilities: https://github.com/infokiller/config-public/blob/master/.my_scripts/util/terminal-capabilities-test

You can test it quickly using:

curl -fsSL 'https://raw.githubusercontent.com/infokiller/config-public/master/.my_scripts/util/terminal-capabilities-test' | bash -s --

But frankly, I'm sure @romkatv will show me a much better way to do this :)

@romkatv
Copy link
Owner

romkatv commented Dec 23, 2021

@romkatv I believe you can set-option -as terminal-features 'xterm*:usstyle' instead of raw terminal-overrides.

Thanks! That's much better. I've switched to this option.

BTW, I use this script (mostly copied) to test the terminal capabilities: https://github.com/infokiller/config-public/blob/master/.my_scripts/util/terminal-capabilities-test

I've tried it on VTE with and without integrated tmux and the output looks the same. I believe it also looks as expected, meaning that all features work.

I'm sure @romkatv will show me a much better way to do this :)

I'd replace all echo -e calls with print and remove the hashbang. Then it would work without bash.

For testing truecolor I use this zsh script:

() {
  emulate -L zsh -o prompt_percent -o ksh_arrays
  zmodload zsh/mathfunc
  local bg fg
  local -i i r g b
  for i in {0..$((COLUMNS-1))}; do
    b='i * 255 / COLUMNS'
    r='255 - b'
    g='255 - abs(r - b)'
    printf -v bg '%02x' $r $g $b
    print -nP "%K{#$bg} "
  done
  print
}

The output looks gorgeous in a full-screen terminal.

@infokiller
Copy link

@romkatv I believe you can set-option -as terminal-features 'xterm*:usstyle' instead of raw terminal-overrides.

Thanks! That's much better. I've switched to this option.

BTW, I use this script (mostly copied) to test the terminal capabilities: infokiller/config-public@master/.my_scripts/util/terminal-capabilities-test

I've tried it on VTE with and without integrated tmux and the output looks the same. I believe it also looks as expected, meaning that all features work.

I'm sure @romkatv will show me a much better way to do this :)

I'd replace all echo -e calls with print and remove the hashbang. Then it would work without bash.

I assume you meant printf (print is zsh specific right?)
I went ahead and applied your suggestions so that it works in POSIX shells.

For testing truecolor I use this zsh script:

() {
  emulate -L zsh -o prompt_percent -o ksh_arrays
  zmodload zsh/mathfunc
  local bg fg
  local -i i r g b
  for i in {0..$((COLUMNS-1))}; do
    b='i * 255 / COLUMNS'
    r='255 - b'
    g='255 - abs(r - b)'
    printf -v bg '%02x' $r $g $b
    print -nP "%K{#$bg} "
  done
  print
}

The output looks gorgeous in a full-screen terminal.

Thanks for showing me that, it's cool that it adopts the color resolution to the available width.

@romkatv
Copy link
Owner

romkatv commented Dec 23, 2021

I assume you meant printf (print is zsh specific right?)

Yes, that should've been printf.

The problem with echo is that it behaves differently in different shells. echo -e blah can print either -e blah or just blah. echo '\n' can print either \n or LF. In sh it MUST do the former: you can try it with sh -c 'echo -e blah'. In portable scripts you can invoke echo only without -e and -E, only when the first argument (after the optional -n) is guaranteed to not start with -, and only if there are no backslashes in the arguments. A more practical approach is to never invoke echo and use printf instead. You still need to guarantee that the first argument of printf never starts with - but that's fairly easy.

@vbauerster
Copy link

Thanks! That's much better. I've switched to this option.

I confirm it works with integrated tmux. I've tested in WezTerm, which supports all kinds of underlines, with following command:

printf "\x1b[58:2::255:0:0m\x1b[4:1msingle\x1b[4:2mdouble\x1b[4:3mcurly\x1b[4:4mdotted\x1b[4:5mdashed\x1b[0m\n"

@infokiller
Copy link

I assume you meant printf (print is zsh specific right?)

Yes, that should've been printf.

The problem with echo is that it behaves differently in different shells. echo -e blah can print either -e blah or just blah. echo '\n' can print either \n or LF. In sh it MUST do the former: you can try it with sh -c 'echo -e blah'. In portable scripts you can invoke echo only without -e and -E, only when the first argument (after the optional -n) is guaranteed to not start with -, and only if there are no backslashes in the arguments. A more practical approach is to never invoke echo and use printf instead. You still need to guarantee that the first argument of printf never starts with - but that's fairly easy.

Thanks for explaining. Indeed, I try to use printf -- instead of echo because of this issue. At least dash understands -- for printf (I use dash to test POSIX compatibility).
Thanks @vbauerster for showing the terminal-features, it's a much cleaner way indeed (and new in tmux 3.2 based on the tmux changelog).

@fladson
Copy link

fladson commented Jan 5, 2022

zsh4humans has 3 modes:
integrated tmux (a.k.a. you are using tmux but you don't know that)
regular tmux
no tmux; this is only for debugging
When you run zsh4humans installer, it asks you whether you want zsh to always run in tmux. If you answer Yes, you get (2). If you answer No, you get (1). You can get (3) only by manually modifying zshrc. Doing that will disable some features in zsh4humans.

Sorry to go back to this, but do you have the code required for option 3?
And which features would be disabled in this case? I don't use tmux anymore and would like to not have it integrated in the shell in any way.
Thanks for the awesome tool.

@romkatv
Copy link
Owner

romkatv commented Jan 5, 2022

would like to not have it integrated in the shell in any way.

You don't need to do anything. The default config doesn't integrate tmux in the shell. If something doesn't work the way you like, describe what that is.

@maximbaz
Copy link
Contributor Author

Discovered a small case where having an underlying tmux plays a role: if you want to set Apple Touch ID as sufficient auth for sudo (using PAM), this mysteriously won't work if there is a tmux running underneath.

Apparently this works in screen that is shipped together with OS, but not tmux, and there was an attempt to fix this in tmux itself, which failed and the solution is to install some third-party thing: https://superuser.com/a/1348180

Not saying that we need to do something about it, except perhaps to have this documented somehow, to make it discoverable, especially if we stop using the term "tmux" to describe what z4h uses in the default configuration.

@romkatv
Copy link
Owner

romkatv commented Feb 1, 2022

Folks,

I'm throwing the towel on integrated tmux. In the current state it's rough around the edges and I'm not giving it enough of my time and attention to make it work well in diverse environments. I've modified the installer so that it does not enable integrated tmux. It's still possible to enable it with zstyle ':z4h:' start-tmux integrated but this is not documented anywhere.

This makes the default config even further removed from what I use myself. In the past I've already disabled recursive file completions, ssh teleportation and several other things that were causing excessive maintenance strain. It doesn't feel rewarding to improve the default z4h experience anymore.

I'm personally happy with z4h with integrated tmux and will keep using it. There are several things in it that I find invaluable and that aren't found anywhere else: ssh teleportation with shared command history, fzf completions with recursive file completions, persistent directory history, fast and non-glitchy syntax highlighting with autosuggestions, etc. You are welcome to keep using zsh4humans if you like. It's not going anywhere and your zsh config won't stop working. I promised that there won't be any backward-incompatible changes in z4h and I'm keeping it. However, I'm unlikely to implement any features except those that would be useful to me. The same goes for bug reports.

I've put the following notice at the top of the homepage:

  • THE PROJECT HAS VERY LIMITED SUPPORT
  • NO NEW FEATURES ARE IN THE WORKS
  • MOST BUGS WILL GO UNFIXED

The situation may change in the future but I advise you to assume that it won't.

Lastly, I thank all of you for giving this project a shot and for providing valuable feedback. It's what made z4h what it is. It's actually pretty cool!

@romkatv
Copy link
Owner

romkatv commented Feb 2, 2022

This giant issue has served its purpose. Closing. Please open individual issues for bug reports. I mentioned above that most bugs will go unfixed, so keep that in mind when deciding whether to spend your time on reporting a bug or not. Bug reports are useful to me even if I'm not going to fix them.

@bb010g
Copy link

bb010g commented Feb 5, 2022

You are welcome to keep using zsh4humans if you like. It's not going anywhere and your zsh config won't stop working. I promised that there won't be any backward-incompatible changes in z4h and I'm keeping it. However, I'm unlikely to implement any features except those that would be useful to me. The same goes for bug reports.

@romkatv Are community-supplied patches that implement new features or fix bugs still likely to be reviewed and/or merged?

@romkatv
Copy link
Owner

romkatv commented Feb 7, 2022

@romkatv Are community-supplied patches that implement new features or fix bugs still likely to be reviewed and/or merged?

I don't have a hard rule. It all depends on costs and benefits of the patch. If it takes me only a minute to review the patch and it's obviously an improvement, I'll merge it even if it's something minor (like a typo in docs) or if it'll be useful only to one person. Most PRs that I get require a full rewrite; to justify merging them they need to do something important for the project (affect many users, etc.) I'm just going with common sense here.

@romkatv
Copy link
Owner

romkatv commented Feb 20, 2022

FYI: I've compiled a bunch of configuration tips from various issues into a new document: https://github.com/romkatv/zsh4humans/blob/master/tips.md.

romkatv added a commit that referenced this issue Oct 30, 2023
This makes tmux more transparent. Most importantly, it propagates all
environment variables from the parent rather than just those listed in
.tmux.conf under update-environment. It also propagates cgroups. See
#35 (comment)
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