Request: Add new verb argument: {instance-name}
Hello again!
I'm very excited to have finally noticed this new client-server socket stuff, thanks!
I'd like to try setting up an external directory jumper to integrate with a running broot instance (related: #247, #738) -- without quitting and relaunching broot, so that state and history is preserved as much as possible.
I think broot now has everything needed for this, as long as I only expect to have a single broot instance at a time (so that another process can use broot --send instance_name to a predictable instance_name). But I don't want to worry about multiple broot instances trying to use the same socket.
So I'm requesting that a new verb argument be added, so that my shell launcher function can generate some random name (or path? name, I think), launch broot with --listen random_name, and then a verb calling an external process can pass that random_name as an argument to that external process, so it can eventually send a message back to the corresponding socket.
If this is already possible in some way, or unnecessary for some reason, or just totally the wrong way to think about this problem, please let me know!
I also wouldn't mind if broot could take care of generating the random socket name on its side, if it could be accessed via a verb argument like this.
As a workaround, maybe a verb's external command can access an environment parameter set by the launching shell script, containing the socket name. I'll test that soon.
I missed this request. I don't understand what you want the verb argument to be. Can you explain more ?
I want my Zsh br function to be something like
# -- Run broot, cd into pathfile if successful --
# Depends: zsh/mapfile
br () { # [<broot-opt>...]
emulate -L zsh -o localtraps
local pathfile=$(mktemp)
trap "=rm ${(q-)pathfile}" EXIT INT QUIT
local name=$RANDOM
if { broot --verb-output "$pathfile" --listen $name $@ } {
if [[ -r $pathfile ]] {
local folder=${mapfile[$pathfile]}
if [[ $folder ]] cd $folder
}
} else {
return
}
}
It's already like that, but without the --listen $name part.
Then I'd like to define a new verb that launches a tmux pop-up window or split pane, with a Zsh process running in it. That Zsh process will use some other tool to potentially get a folder path. If it does, that same Zsh process will run broot --send $name -c ":focus PATHGOESHERE", and close itself, returning the user to the original broot instance, whose working directory will have just been updated.
The trouble is that the $name to use within the Zsh process is unknown. I don't want to use the same name all the time, because multiple broot processes could conflict. So I figure the verb definition can supply the tmux/zsh process with the name of the socket it's listening to.
The verb could be something like external: folder-picker {instance_name}, so the folder-picker process would know how to control the correct broot process.
Can you try https://github.com/Canop/broot/pull/1047 and tell me if it's what you wanted ?
Thank you, it's working great!
~~The only wrinkle is that while the external process is running, the broot view is hidden, and I was hoping it would remain. Maybe there's a way around that, but it's an independent question for another time.~~
I'll post my working config making use of this here.
@Martin1887 you may find this interesting. I wasn't clear before, but my non-eval br function completely breaks all from_shell stuff, which depends on eval.
Note that if you're using zoxide or another not-strictly-Zsh jumper, and you don't need Zsh completion, your setup can be simpler.
Overview: tmux + Zsh + broot + zsh-z
Collapsed
The idea is to start an interactive Zsh session in a pop-up, with a comfortable folder-jumping setup, which will send a command back to broot, and eagerly exit. After jumping folders, the broot state is not clobbered, as it would be with a new broot process: you can still go back to the previous folder, and other panes remain unaffected.
Aside from whatever personal Zsh setup and directory-jumping tool you need to load, this configuration has three parts:
- the
brfunction needs to make the broot process to listen a uniquely named socket - a new verb definition, e.g. "jump"
- a specialized
.zshrcto set up the jumping environment
Zsh Function: br
Mine is non-standard in other ways, but the important bit here is that it generates a random name, and launches broot with --listen $name.
Collapsed
# -- Run broot, cd into pathfile if successful --
# Depends: zsh/mapfile
br () { # [<broot-opt>...]
emulate -L zsh -o localtraps
local pathfile=$(mktemp)
trap "=rm ${(q-)pathfile}" EXIT INT QUIT
local name=$RANDOM
if { broot --verb-output "$pathfile" --listen $name $@ } {
if [[ -r $pathfile ]] {
local folder=${mapfile[$pathfile]}
if [[ $folder ]] cd $folder
}
} else {
return
}
}
Verb Definition: jump
{
invocation: jump (?P<pathsearch>.*)?
shorcut: j
external: [ "sh" "-c" "tmux popup -e BROOT_SERVER_NAME={server-name} -e BROOT_JUMP_SEARCH={pathsearch} -E 'ZDOTDIR=~/.config/broot/zdotdir-zshz zsh -i' &" ]
leave_broot: false
}
Alternate .zshrc
~/.config/broot/zdotdir-zshz/.zshrc:
Collapsed
The commented "Fat Style Prep" would load all my usual Zsh configuration (except for ~/.zshenv), and the "Lean Style Prep" picks out just completion settings, line editing behavior, and my preferred folder jumper (zsh-z).
# -- Fat Style Prep --
# ZDOTDIR=~/.config/zsh
# . $ZDOTDIR/.zshrc
#
# if (( $+functions[miniprompt] )) miniprompt
# -- Lean Style Prep --
. ~/.config/zsh/completion_and_glob_opts.zsh
. ~/.config/zsh/inline_selection.zsh
ZSHZ_NO_RESOLVE_SYMLINKS=1
ZSHZ_UNCOMMON=1
. ~/.config/zsh/plugins/zsh-z/zsh-z.plugin.zsh
autoload -Uz compinit
compinit -i -d ~/.cache/zsh/zcompdump-$ZSH_VERSION
PROMPT='%B%F{white}-- %F{green}$ %f%b'
# -- Common --
jump () {
emulate -L zsh
if { zshz $@ } { broot --send $BROOT_SERVER_NAME -c ":focus $PWD" }
exit
}
compdef _zshz jump
print -z "jump $BROOT_JUMP_SEARCH"
trap exit INT
In Action
As a result, I can invoke the verb as j without arguments to get the popup, and start typing a folder substring, with tab completion. If I provide an argument to the verb, it gets prefilled in the popup, but can still be edited and tab-completed. Ctrl-C can quickly abort the operation.
https://github.com/user-attachments/assets/c29c986a-dbed-434a-8237-f0a1f5ec81b2
The only wrinkle is that while the external process is running, the broot view is hidden, and I was hoping it would remain. Maybe there's a way around that, but it's an independent question for another time.
Maybe create an issue for that, or maybe change this one from just the verb argument to more generally support the process you're building until it perfectly works ?
(reopen the issue if you want)
Ah, I found the following change accomplishes that bit! I'll edit it in to the above.
{
invocation: jump (?P<pathsearch>.*)?
shorcut: j
- external: tmux popup -e BROOT_SERVER_NAME={server-name} -e BROOT_JUMP_SEARCH={pathsearch} -E "ZDOTDIR=~/.config/broot/zdotdir-zshz zsh -i"
+ external: [ "sh" "-c" "tmux popup -e BROOT_SERVER_NAME={server-name} -e BROOT_JUMP_SEARCH={pathsearch} -E 'ZDOTDIR=~/.config/broot/zdotdir-zshz zsh -i' &" ]
leave_broot: false
}
Interesting, I will look into it, thanks!
I found that using nested shell commands breaks broot's quoting of things like {file}, and I think there's no way to force-apply quotation/escaping to variables. For example, with a verb with leave_broot: false and
external: [ "sh" "-c" "tmux popup \"zsh -c 'print -rl -- {file}:{line}'\" &" ]
Applying that to a path with spaces shows that the path is split into multiple arguments along the spaces. I thought maybe a workaround would be first writing the {file} with :write_output, then reading the content back into a variable. But I don't think there's a way to find out what the --verb-output file is from within a verb definition.
Would it make sense to support nested lists for nested quoting of external commands? For example:
external: [
"sh"
"-c"
[
"tmux"
"popup"
[
"zsh"
"-c"
[
"print"
"-rl"
"--"
"{file}:{line}"
]
"&"
]
]
]
For anyone who reads this far down my tangential comments, I'm reducing nesting and getting proper quoting by moving the logic out of the conf file and into a Zsh script which expects the file and line as args 1 and 2, e.g.:
{
invocation: lh
external: [ "~/.config/broot/page-in-popup.zsh" "{file}" "{line}" ]
leave_broot: false
}
Where page-in-popup.zsh is:
#!/bin/zsh -e
# <FILE> <line>
tmux popup -E -w 80% -h 90% \
". ~/.config/zsh/paging_and_printing.zsh; lh ${(q-)1}:$2" &