Constantly updated clock in zsh prompt? - zsh

I know that I can exec a date command in my zsh prompt.
However, it shows the old time; to see the current time, I have to hit <return> and get a new prompt with the current time.
Is there a way to configure the zsh prompt to constantly update itself every second?

Note: I wrote this answer for a similar question, but seeing how this question has more views I think reposting my answer here would be useful.
This is in fact possible without resorting to strange hacks. I've got this in my .zshrc
RPROMPT='[%D{%L:%M:%S %p}]'
TMOUT=1
TRAPALRM() {
zle reset-prompt
}
The TRAPALRM function gets called every TMOUT seconds (in this case 1), and here it performs a prompt refresh, and does so until a command starts execution (and it doesn't interfere with anything you type on the prompt before hitting enter).
Source: http://www.zsh.org/mla/users/2007/msg00944.html (It's from 2007!)

Sounds like a pleasant request to me. If anything it makes more sense than showing the time when the prompt was displayed.
Fortunately Peter Stephenson posted a technique. Try something like this in .zshrc:
PROMPT="[%T] %n#%M %~ %# "
schedprompt() {
emulate -L zsh
zmodload -i zsh/sched
# Remove existing event, so that multiple calls to
# "schedprompt" work OK. (You could put one in precmd to push
# the timer 30 seconds into the future, for example.)
integer i=${"${(#)zsh_scheduled_events#*:*:}"[(I)schedprompt]}
(( i )) && sched -$i
# Test that zle is running before calling the widget (recommended
# to avoid error messages).
# Otherwise it updates on entry to zle, so there's no loss.
zle && zle reset-prompt
# This ensures we're not too far off the start of the minute
sched +30 schedprompt
}
schedprompt

This would be .... unpleasant in a standard zsh prompt (or bash, or other shells).
I suggest you'd be better off using Gnu Screen.
Screen can have a status line which can show the time.
Here's an example screenrc scroll down to "Red Hat Magazine A guide to GNU Screen" to see the sample (i'll reproduce that here) which will, when screen is run, show the current time in the lower right corner of the terminal:
~/.screenrc
hardstatus alwayslastline
hardstatus string '%{= kG}[ %{G}%H %{g}][%= %{=kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B}%Y-%m-%d %{W}%c %{g}]'
# Default screens
screen -t shell1 0
screen -t shell2 1
http://www.gnu.org/software/screen/

Related

How can I get backward-delete-word to add to the current kill-ring in zsh?

I use zsh and I would like backward-kill-word in Emacs mode to behave like Emacs (and bash, fwiw). The behaviour that I have failed to reproduce is that when I press multiple backward-kill-word Emacs adds the killed text to the cut buffer (the first item in the killring) making it possible for me to yank everything with one yank command.
How can I configure zsh to behave like this aspect of Emacs editors?
Actually, by default, Zsh's cut buffer works exactly the same as in Emacs. Just use zsh -f to start Zsh without config files and try it.
However, are you perhaps using zsh-autosuggestions or zsh-syntax-highlighting? There are bugs in these plugins that break this feature:
https://github.com/zsh-users/zsh-autosuggestions/issues/363
https://github.com/zsh-users/zsh-syntax-highlighting/issues/150#issuecomment-658381485
Fixes have been submitted, but for zsh-autosuggestions, none have yet been merged, and for zsh-syntax-highlighting, the fix won't work until Zsh 5.9 has been released.
In the meantime, though, zsh-autocomplete contains a workaround that fixes the problem. If you add that plugin, your cut buffer will start functioning like normal again.

Can the number of sleeping task in the current window be shown in Tmux statusbar?

I often use ^Z to make sleep a process, possibly open a new one, make this one sleep too, and so on, also moving between different Tmux windows.
So what I would like, is that the Tmux status bar update relevantly to indicate me how many processes are sleeping in the currently focused window.
Is that possible?
This is a common question - how to pass information from a shell inside tmux to tmux. The easiest way to do this is to have your shell do it as part of PS1 or some other variable that is evaluated when the prompt is printed.
There are two things you can do:
1) Set a user option with tmux set -w #myoption xyz, then you can use it in the status line with #{#myoption}. This has the disadvantage that it cannot work over ssh.
2) Set the pane title using the escape sequence, for example: printf "\033]2;xyz\033\\". It is then available in #{pane_title}. This works over ssh but had the disadvantage that there is no way to prevent applications also changing the title if they want.
In either case you will only want to run this when TMUX is set, so something like:
[ -n "$TMUX" ] && tmux set -w #myoption $(jobs|wc -l)

Select from zsh completion menu by number

I discovered this little navigation trick the other day, which allows me to trigger menu completions by number when I enter 'cd -'
~ cd -
0 -- ~/home
1 -- ~/home/stuff
2 -- ~/downloads
3 -- ~/wallpaper
Shell scripting syntax still reads like a foreign language to me, but to get this functionality my directory stack history is piped into the function below.
DIRSTACKSIZE=9
DIRSTACKFILE=~/.zdirs
if [[ -f $DIRSTACKFILE ]] && [[ $#dirstack -eq 0 ]];
then dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
[[ -d $dirstack[1] ]] && cd $dirstack[1] && cd $OLDPWD
fi
chpwd() {
print -l $PWD ${(u)dirstack} >$DIRSTACKFILE
}
The magical part is being able to choose from the list by number, but I have come to learn that this is probably
because the functionality for navigation by number is baked in to the 'cd -' command. Still, I'd like to use this everywhere.
Any tips writing a wrapper function (or something like that, I guess) for the completion menu that pipes in completions from the menu when it is triggered
and displays them in a numbered list where those numbers select the corresponding element?
I've gotten started reading the manual and what not, but everything remains rather opaque. Thanks!
First off, the code snippet you show has nothing to do with completion. Instead, what it does is to record the directory stack to a file in order to preserve it between zsh sessions. (Personally, I'm not even sure this is a good idea.)
A good place to start investigating zsh completions is the _complete_help ZLE widget. This is bound by default to ^Xh in zsh's viins (vi insert) keyboard map, but is unbound by default in the emacs keymap. If you want to use it in the emacs keymap (the default for many people), you have to bind it:
bindkey -M emacs "^Xh" _complete_help
Now you can type cd - (or cd +) and follow it by CTRL-Xh instead of TAB. You should see the following output:
tags in context :completion::complete:cd::
directory-stack (_directory_stack _cd)
(At this point I'll admit we're getting close to the limits of my knowledge of the zsh completion system.)
Now you can see the completer functions for the directory-stack tag in this particular context. The one you're probably interested in is _directory_stack, and you can see the content of that function with:
functions _directory_stack
…which is where those leading numbers are actually generated.
Arguably it's possible to write similar completion functions for other completion contexts, and apply the using zstyle. However, this is non-trivial completion magic, and beyond anything I have attempted

Tmux refresh client call from fish shell alias

I want tmux pane title to refresh immediately after I start htop, so I added alias in my config.fish:
alias h "htop;tmux refresh-client -S"
But it does nothing. I also tried with delay:
alias h "htop;sleep 0.1;tmux refresh-client -S"
That also did nothing - tmux still refreshes only after default interval, which is too long for me, and you can only decrease it to 1 second and not less.
What did I do wrong and is it even possible what I want to do?
Maybe this is a bit easier to see when we remove the alias from the equation:
echo banana; sleep 5s; echo sausage
will echo "banana", wait for 5 seconds and only then print "sausage", so
htop; tmux refresh-client -S
will run htop, wait until it is finished and then run tmux refresh-client -S, at which point fish will be the foreground process again.
What would have to be done instead is to get the shell to integrate with tmux. Now, apparently tmux has an escape sequence for Names and titles, so
printf '\ekhtop\e\\' # \e is \033 - the escape character
changes the window title to "htop".
Fish has events that functions can be bound to, so something like
function tmux_name --on-event fish_preexec
printf '\ek%s\e\\' "$argv" # the argument for preexec is the commandline about to be executed
end
will set the tmux window name always to the command line. This won't reset it when the command has finished, so we need a second function
function tmux_reset_name --on-event fish_postexec
# $argv for postexec is also the commandline
# so we can't use it. Just hardcode "fish".
printf '\ek%s\e\\' fish
end
Not that this is perfect or anything - it'll still set the title even for very short-running commands, it'll use the full commandline even for long commands (maybe using just $argv[1] would be better).
Note that these functions will have to be defined in config.fish or a file explicitly sourced by it (or ~/.config/fish/conf.d/), because function files are autoloaded, so fish won't know about the event.

Set/Unset bell/flag state for a window

I tend to have multiple windows in a tmux session, and run long processes (such as database migrations and complex queries, etc) in one window while I keep focus on another.
I'd like to set something up to flag the window when the process is finished. I plan to do this with zsh functions, but I'm having trouble finding the command to set a bell on a given tmux window. I looked at set-window-option and I found window_flag but I don't know how to set window_flag
How can I set and clear an indicator for a given tmux window via a shell command?
In order to send a bell to any terminal, including tmux, you just have to print \a to the terminal. You can use echo '\a' or print '\a' for that. (On shells other than ZSH you might need to use echo -e '\a' or printf '\a' instead.)
If a bell occurred in a window tmux adds a ! to the window name in the status bar. Activating a window automatically removes the bell flag, that also means that a the flag will not be set if the bell occurs in the currently active window.
You can also set a separate style for these windows in the status line with window-status-bell-style option (the default seems to be reverse, that is switching fore- and background colors).
Additionally you can get tmux to show a short message if a bell occurred by setting the bell-action option to any.
I have the following in my ~/.zshrc to ring the bell, if a process takes at least 60 seconds to finish:
autoload -Uz add-zsh-hook
typeset -i LONGRUNTIME=60
save_starttime () {
starttime=$SECONDS
}
set_longrunning_alert () {
if ((LONGRUNTIME > 0 && SECONDS - starttime >= LONGRUNTIME)); then
print "\a"
fi
}
add-zsh-hook preexec save_starttime
add-zsh-hook precmd set_longrunning_alert

Resources