tmux-sessionx icon indicating copy to clipboard operation
tmux-sessionx copied to clipboard

refactor: pre-compute most arguments

Open LoricAndre opened this issue 1 year ago • 2 comments

This helps with #123, the popup opens almost instantly.

This is very basic work with very little tests done, to show what a solution to the issue could look like.

@omerxx if this looks good to you in principle, I'll take the time to make it cleaner and test it further, with your help if possible for the tests

LoricAndre avatar Sep 25 '24 21:09 LoricAndre

Hi @LoricAndre, thanks for the effort you've put into this. Can you please explain in words the changes? I've seen some additions but lots of code moving around?

Also, when you finalize the change could you please fix the inconsistent indentations?

Thanks!

omerxx avatar Sep 30 '24 09:09 omerxx

Hi,

Thanks for the reply. The gist of the changes is to build the fzf command from the tmux global variables in sessionx.tmux, which will slightly increase tmux's startup time but will greatly improve the delay needed to open the fzf window when invoking sessionx.sh using the keybind.

I'll take some time to run a formatter on the scripts to fix the indent later

LoricAndre avatar Sep 30 '24 18:09 LoricAndre

I tried this as well and it does feel faster. But I really wish I figured out a way to measure it properly.

But I do believe one key difference might be this line: https://github.com/omerxx/tmux-sessionx/pull/152/files#diff-72ef2c900eace70d48151727d85d1645359fa3086b0ea71d7a70d87c6e71cb5fR33

Old code creates a bash subshell, new one doesnt, right?

Was this intentional or was it done by some formatter? One formatter has already clearly been run as it looks like an automated attempt to put the members of the file in alphabetical order. An effort should be made to minimize the diff before merging.

alexanderfast avatar Oct 17 '24 06:10 alexanderfast

Not sure, I cleaned up what I could when moving everything around. I think I have a pretty basic formatter, so that part was probably done by hand

LoricAndre avatar Oct 20 '24 19:10 LoricAndre

Hi @LoricAndre this does look good but I did run some tests and found a severe issue with session renaming:

  1. pop sessionx
  2. create a new session
  3. ctrl-r to rename
  4. call it newnew
  5. name didn't change and you know have a ${name) session...

also, could you please make sure not to include changes of indentation if possible? only so that it makes easier to track changes....

I must say, I do agree with the main change being @alexanderfast's comment. Let me push the change, and tell me whether you still see a difference with your changes.

omerxx avatar Oct 21 '24 21:10 omerxx

I tried it with @alexanderfast's comment only, and it was closer to the original than to my changes.

The rename issue should be fixed, and the indent should be a lot better

LoricAndre avatar Oct 22 '24 17:10 LoricAndre

@LoricAndre yep, I've also created a cache option that seems to be helping a lot, care to give it a go and tell me what you think? https://github.com/omerxx/tmux-sessionx/pull/154

omerxx avatar Oct 22 '24 21:10 omerxx

I've found is_tmuxinator_enabled function call in the sessionx.tmux file. But this function is only declared in tmuxinator.sh file, which is not sourced. I think that's why I can't use tmuxinator in this version :)

Marat-Gumerov avatar Oct 23 '24 11:10 Marat-Gumerov

Let's make this PR happen :)

omerxx avatar Oct 23 '24 13:10 omerxx

I've found is_tmuxinator_enabled function call in the sessionx.tmux file. But this function is only declared in tmuxinator.sh file, which is not sourced. I think that's why I can't use tmuxinator in this version :)

This should be fixed in the last version, good catch !

Can you try again now ?

LoricAndre avatar Oct 24 '24 10:10 LoricAndre

I've found is_tmuxinator_enabled function call in the sessionx.tmux file. But this function is only declared in tmuxinator.sh file, which is not sourced. I think that's why I can't use tmuxinator in this version :)

This should be fixed in the last version, good catch !

Can you try again now ?

tmuxinator still seems to be disabled or not working. When I run the new version from shell, using ./sessionx.tmux I see some errors:

$ ./sessionx.tmux
./sessionx.tmux: line 8: scripts/*: No such file or directory
./sessionx.tmux: line 94: is_fzf-marks_enabled: command not found
./sessionx.tmux: line 147: is_tmuxinator_enabled: command not found
./sessionx.tmux: line 150: is_fzf-marks_enabled: command not found

I guess that source scripts/* does not work as expected. So I made some changes. I've replaced source scripts/* with:

source "$SCRIPTS_DIR/tmuxinator.sh"
source "$SCRIPTS_DIR/fzf-marks.sh"

And added:

export PS4='+ $(date "+%s.%N")\011 '
bash -x scripts/sessionx.sh "$(build_args) $(build_fzf_opts)"

to the end of file. Now I see another error:

sh: -c: line 1: syntax error near unexpected token `('
sh: -c: line 1: `fzf-tmux -p '75%,75%' -- --bind 'ctrl-t:change-preview(/home/mt/.config/tmux/plugins/tmux-sessionx/scripts/preview.sh -t {1})' --bind 'ctrl-x:reload(find /home/mt/.config -mindepth 1 -maxdepth 1 -type d -o -type l)+change-preview(ls {})' --bind 'ctrl-w:reload(tmux list-windows -a -F #{session_name}:#{window_name})+change-preview(/home/mt/.config/tmux/plugins/tmux-sessionx/scripts/preview.sh -w {1})' --bind 'ctrl-e:reload(find /home/mt/.config/tmux/plugins/tmux-sessionx -mindepth 1 -maxdepth 1 -type d -o -type l)+change-preview(ls {})' --bind 'ctrl-f:reload(zoxide query -l)+change-preview(ls {})' --bind 'ctrl-b:reload(echo -e "")+change-preview(/home/mt/.config/tmux/plugins/tmux-sessionx/scripts/preview.sh {1})' --bind 'alt-bspace:execute-silent(tmux kill-session -t {})+reload(/home/mt/.config/tmux/plugins/tmux-sessionx/scripts/reload_sessions.sh)' --bind 'bspace:backward-delete-char' --bind 'esc:abort' --bind 'ctrl-n:up' --bind 'ctrl-p:down' --bind 'enter:replace-query+print-query' --bind 'ctrl-u:preview-half-page-up' --bind 'ctrl-d:preview-half-page-down' --bind 'ctrl-r:execute(bash -c '\''read -p \"New name: \" name; tmux rename-session -t \"{1}\" \"\${name}\" '\'')+reload(bash -c \"tmux list-sessions | sed -E '\''s/:.*$//'\''; \")' --bind '?:toggle-preview' --bind 'change:first' --exit-0 --header='enter=󰿄 / alt-bspace=󱂧 / ctrl-r=󰑕 / ctrl-x=󱃖 / ctrl-w= / ctrl-e=󰇘 / ctrl-b=󰌍 / ctrl-t=󰐆 / ctrl-u= / ctrl-d= / ctrl-f=' --preview='/home/mt/.config/tmux/plugins/tmux-sessionx/scripts/preview.sh {}' --preview-window='top,75%,,' --layout='default' --pointer='▶' --prompt ' ' --print-query --tac --scrollbar '▌▐' --bind 'focus:transform-preview-label:echo [ {} ]' --bind F1:reload(tmuxinator list --newline | sed '1d')+change-preview(cat ~/.config/tmuxinator/{}.yml 2>/dev/null) --color pointer:9,spinner:92,marker:46 2>>/tmp/tmux-sessionx.log'

When I compare this line with the one from the main branch, I see that the binding for the tmuxinator is not surrounded with single quotes.

As I can see, some other quotes are also missing, for example:

  • original: --bind 'ctrl-w:reload(tmux list-windows -a -F '\''#{session_name}:#{window_name}'\'')+change-preview(/home/mt/.config/tmux/plugins/tmux-sessionx/scripts/preview.sh -w {1})'
  • this version: --bind 'ctrl-w:reload(tmux list-windows -a -F #{session_name}:#{window_name})+change-preview(/home/mt/.config/tmux/plugins/tmux-sessionx/scripts/preview.sh -w {1})'

I don't understand where these single quotes come from, but they seem to be very important

Marat-Gumerov avatar Oct 24 '24 12:10 Marat-Gumerov

It seems to me, that bindings should be passed to sessionx.sh using the declare -p command. So sessionx.sh will be able to deserialize the array of bindings using the eval command and pass it to the fzf-tmux call. In this case, the shell will be able to quote arguments properly.

Marat-Gumerov avatar Oct 24 '24 12:10 Marat-Gumerov

This has become quite hellish because of the quotes, so I'd love a better way to manage the bindings. I've never used declare -p, would you be able to provide a snippet that I could use to understand ?

LoricAndre avatar Oct 24 '24 18:10 LoricAndre

This has become quite hellish because of the quotes, so I'd love a better way to manage the bindings. I've never used declare -p, would you be able to provide a snippet that I could use to understand ?

I have zero experience with bash :) But I can show you some code, suggested by ChatGPT. I've tested it a little bit and it works as expected, so:

  • in sessionx.tmux we serialize our args array and save it to a file:
ser=$(declare -p args)
echo $ser > /tmp/sessionx.args
  • in sessionx.sh we read it back from file and evaluate:
ser=$(cat /tmp/sessionx.args)
eval "$ser"

This eval call declares the args variable inside the sessionx.sh file. So you can pass it to the fzf/fzf-tmux call.

Please note, that in this case you should remove all the quotes you've added to the args array. For example, the line:

        --bind "'$TREE_MODE'"

should be

        --bind "$TREE_MODE"

Note 2: I couldn't pass the $ser value as an argument, maybe it is too long or has other problems with the quotes :)

Marat-Gumerov avatar Oct 25 '24 06:10 Marat-Gumerov

Oh OK, I don't think declare has anything to do with this, as the args are already a bash array. Rather, the issue is a little better thanks to the args being saved to a file instead of stored in a variable. I'd rather not use a file if I can avoid it for now, unless @omerxx thinks otherwise ?

LoricAndre avatar Oct 25 '24 08:10 LoricAndre

Oh OK, I don't think declare has anything to do with this, as the args are already a bash array. Rather, the issue is a little better thanks to the args being saved to a file instead of stored in a variable. I'd rather not use a file if I can avoid it for now, unless @omerxx thinks otherwise ?

args is a bash array, but the result of the build_args function is not. That's the difference.

For example, if you have a file check.sh with the code:

echo $1
echo $2
echo $3

and you have an array:

arr=(
  value
  "value with 'single quotes'"
  "value with \"double\" quotes"
)

Then you have this result:

$ ./check.sh ${arr[@]}
value
value with 'single quotes'
value with "double" quotes

But:

$ arr2=$(echo ${arr[@]})
$ ./check.sh $arr2
value value with 'single quotes' value with "double" quotes


That's why I think you should not use echo ${args[@]} in your code. It breaks everything.

BTW, I hope that using a file is not really necessary in this case.

Marat-Gumerov avatar Oct 25 '24 10:10 Marat-Gumerov

I'm not sure, but maybe we can use tmux set-option and tmux show-option to store and retrieve the serialized array.

Marat-Gumerov avatar Oct 25 '24 10:10 Marat-Gumerov

I'm not sure, but maybe we can use tmux set-option and tmux show-option to store and retrieve the serialized array.

Yes, I've tested it and it is perfect:

Log
++ 1729852081.509751313  tmux show-option -gqv @sessionx-all-args
+ 1729852081.514528742   ser='declare -a args=([0]="--bind" [1]="ctrl-t:change-preview(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh -t {1})" [2]="--bind" [3]="ctrl-x:reload(find /home/mt/.config -mindepth 1 -maxdepth 1 -type d -o -type l)+change-preview(ls {})" [4]="--bind" [5]="ctrl-w:reload(tmux list-windows -a -F #{session_name}:#{window_name})+change-preview(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh -w {1})" [6]="--bind" [7]="ctrl-e:reload(find /home/mt/tmp/tmux-sessionx-declare/tmux-sessionx -mindepth 1 -maxdepth 1 -type d -o -type l)+change-preview(ls {})" [8]="--bind" [9]="ctrl-f:reload(zoxide query -l)+change-preview(ls {})" [10]="--bind" [11]="ctrl-b:reload(echo -e \"\")+change-preview(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh {1})" [12]="--bind" [13]="alt-bspace:execute-silent(tmux kill-session -t {})+reload(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/reload_sessions.sh)" [14]="--bind" [15]="bspace:backward-delete-char" [16]="--bind" [17]="esc:abort" [18]="--bind" [19]="ctrl-n:up" [20]="--bind" [21]="ctrl-p:down" [22]="--bind" [23]="enter:replace-query+print-query" [24]="--bind" [25]="ctrl-u:preview-half-page-up" [26]="--bind" [27]="ctrl-d:preview-half-page-down" [28]="--bind" [29]="ctrl-r:execute(bash -c '\''\\'\'''\''read -p \\\"New name: \\\" name; tmux rename-session -t \\\"{1}\\\" \\\"\\\${name}\\\" '\''\\'\'''\'')+reload(bash -c \\\"tmux list-sessions | sed -E '\''\\'\'''\''s/:.*\$//'\''\\'\'''\''; \\\")" [30]="--bind" [31]="?:toggle-preview" [32]="--bind" [33]="change:first" [34]="--exit-0" [35]="--header=enter=󰿄 / alt-bspace=󱂧 / ctrl-r=󰑕 / ctrl-x=󱃖 / ctrl-w=  / ctrl-e=󰇘 / ctrl-b=󰌍 / ctrl-t=󰐆  / ctrl-u= / ctrl-d= / ctrl-f=" [36]="--preview=/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh  {}" [37]="--preview-window=top,75%,," [38]="--layout=default" [39]="--pointer=▶" [40]="--prompt" [41]=" " [42]="--print-query" [43]="--tac" [44]="--scrollbar" [45]="▌▐" [46]="--bind" [47]="focus:transform-preview-label:echo [ {} ]" [48]="--bind" [49]="F5:reload(tmuxinator list --newline | sed '\''1d'\'')+change-preview(cat ~/.config/tmuxinator/{}.yml 2>/dev/null)")'
+ 1729852081.515504268   eval 'declare -a args=([0]="--bind" [1]="ctrl-t:change-preview(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh -t {1})" [2]="--bind" [3]="ctrl-x:reload(find /home/mt/.config -mindepth 1 -maxdepth 1 -type d -o -type l)+change-preview(ls {})" [4]="--bind" [5]="ctrl-w:reload(tmux list-windows -a -F #{session_name}:#{window_name})+change-preview(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh -w {1})" [6]="--bind" [7]="ctrl-e:reload(find /home/mt/tmp/tmux-sessionx-declare/tmux-sessionx -mindepth 1 -maxdepth 1 -type d -o -type l)+change-preview(ls {})" [8]="--bind" [9]="ctrl-f:reload(zoxide query -l)+change-preview(ls {})" [10]="--bind" [11]="ctrl-b:reload(echo -e \"\")+change-preview(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh {1})" [12]="--bind" [13]="alt-bspace:execute-silent(tmux kill-session -t {})+reload(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/reload_sessions.sh)" [14]="--bind" [15]="bspace:backward-delete-char" [16]="--bind" [17]="esc:abort" [18]="--bind" [19]="ctrl-n:up" [20]="--bind" [21]="ctrl-p:down" [22]="--bind" [23]="enter:replace-query+print-query" [24]="--bind" [25]="ctrl-u:preview-half-page-up" [26]="--bind" [27]="ctrl-d:preview-half-page-down" [28]="--bind" [29]="ctrl-r:execute(bash -c '\''\\'\'''\''read -p \\\"New name: \\\" name; tmux rename-session -t \\\"{1}\\\" \\\"\\\${name}\\\" '\''\\'\'''\'')+reload(bash -c \\\"tmux list-sessions | sed -E '\''\\'\'''\''s/:.*\$//'\''\\'\'''\''; \\\")" [30]="--bind" [31]="?:toggle-preview" [32]="--bind" [33]="change:first" [34]="--exit-0" [35]="--header=enter=󰿄 / alt-bspace=󱂧 / ctrl-r=󰑕 / ctrl-x=󱃖 / ctrl-w=  / ctrl-e=󰇘 / ctrl-b=󰌍 / ctrl-t=󰐆  / ctrl-u= / ctrl-d= / ctrl-f=" [36]="--preview=/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh  {}" [37]="--preview-window=top,75%,," [38]="--layout=default" [39]="--pointer=▶" [40]="--prompt" [41]=" " [42]="--print-query" [43]="--tac" [44]="--scrollbar" [45]="▌▐" [46]="--bind" [47]="focus:transform-preview-label:echo [ {} ]" [48]="--bind" [49]="F5:reload(tmuxinator list --newline | sed '\''1d'\'')+change-preview(cat ~/.config/tmuxinator/{}.yml 2>/dev/null)")'
++ 1729852081.516737601  args=(['0']='--bind' ['1']='ctrl-t:change-preview(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh -t {1})' ['2']='--bind' ['3']='ctrl-x:reload(find /home/mt/.config -mindepth 1 -maxdepth 1 -type d -o -type l)+change-preview(ls {})' ['4']='--bind' ['5']='ctrl-w:reload(tmux list-windows -a -F #{session_name}:#{window_name})+change-preview(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh -w {1})' ['6']='--bind' ['7']='ctrl-e:reload(find /home/mt/tmp/tmux-sessionx-declare/tmux-sessionx -mindepth 1 -maxdepth 1 -type d -o -type l)+change-preview(ls {})' ['8']='--bind' ['9']='ctrl-f:reload(zoxide query -l)+change-preview(ls {})' ['10']='--bind' ['11']='ctrl-b:reload(echo -e "")+change-preview(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh {1})' ['12']='--bind' ['13']='alt-bspace:execute-silent(tmux kill-session -t {})+reload(/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/reload_sessions.sh)' ['14']='--bind' ['15']='bspace:backward-delete-char' ['16']='--bind' ['17']='esc:abort' ['18']='--bind' ['19']='ctrl-n:up' ['20']='--bind' ['21']='ctrl-p:down' ['22']='--bind' ['23']='enter:replace-query+print-query' ['24']='--bind' ['25']='ctrl-u:preview-half-page-up' ['26']='--bind' ['27']='ctrl-d:preview-half-page-down' ['28']='--bind' ['29']='ctrl-r:execute(bash -c '\''\'\'''\''read -p \"New name: \" name; tmux rename-session -t \"{1}\" \"\${name}\" '\''\'\'''\'')+reload(bash -c \"tmux list-sessions | sed -E '\''\'\'''\''s/:.*$//'\''\'\'''\''; \")' ['30']='--bind' ['31']='?:toggle-preview' ['32']='--bind' ['33']='change:first' ['34']='--exit-0' ['35']='--header=enter=󰿄 / alt-bspace=󱂧 / ctrl-r=󰑕 / ctrl-x=󱃖 / ctrl-w=  / ctrl-e=󰇘 / ctrl-b=󰌍 / ctrl-t=󰐆  / ctrl-u= / ctrl-d= / ctrl-f=' ['36']='--preview=/home/mt/tmp/tmux-sessionx-declare/tmux-sessionx/scripts/preview.sh  {}' ['37']='--preview-window=top,75%,,' ['38']='--layout=default' ['39']='--pointer=▶' ['40']='--prompt' ['41']=' ' ['42']='--print-query' ['43']='--tac' ['44']='--scrollbar' ['45']='▌▐' ['46']='--bind' ['47']='focus:transform-preview-label:echo [ {} ]' ['48']='--bind' ['49']='F5:reload(tmuxinator list --newline | sed '\''1d'\'')+change-preview(cat ~/.config/tmuxinator/{}.yml 2>/dev/null)')
++ 1729852081.517799511  declare -a args

It takes only 8 ms to read and deserialize all arguments.

Marat-Gumerov avatar Oct 25 '24 10:10 Marat-Gumerov

So now in sessionx.tmux we do:

ser=$(declare -p args)
tmux set-option -g @sessionx-all-args "$ser"

and in sessionx.sh we do:

ser=$(tmux show-option -gqv @sessionx-all-args)
eval "$ser"

Marat-Gumerov avatar Oct 25 '24 10:10 Marat-Gumerov

I used tmux options to send the arguments, but I'm not so sure about the declare -p part, specifically because of the need for eval. I tried it out, and the complexity it brings seems higher than what it brings.

LoricAndre avatar Oct 25 '24 17:10 LoricAndre

I used tmux options to send the arguments, but I'm not so sure about the declare -p part, specifically because of the need for eval. I tried it out, and the complexity it brings seems higher than what it brings.

Tmuxinator still does not work in this version

Marat-Gumerov avatar Oct 29 '24 09:10 Marat-Gumerov

Hi people, hadn't visited this thread in a while, seems like things are still not 100% ready yet right?

omerxx avatar Nov 21 '24 20:11 omerxx

I had quite forgotten about it tbh, but tmuxinator should be fixed in the latest version

LoricAndre avatar Nov 23 '24 15:11 LoricAndre

With recent merges and the other fixes I'm assuming this is no longer relevant, if anyone visits this thread and wants it back, please do feel free to reopen with an explanation, and aligning the conflicts too :)

omerxx avatar Dec 28 '24 12:12 omerxx