Description
With the changes to how ^C is handled when editing the command line buffer in interactive mode, there is a "significant" delay in how long it takes for the prompt to be reset. I've noticed this off and on since 5f849d0 and #2904, but today I had a background build going using all my cores and the delay was really bad, you could see the ^C
being painted and then there was a hang until the fish prompt was redrawn and the command line was ready to accept input on the new line.
Obviously my machine was dog-slow at this point, but I was able to use it normally except for the ctrl-c stuff, which means that this is exceptionally slow relative to the rest of fish's interactive mode handling.
The problem is that prior to 5f849d0, \cc
was bound to a builtin call (commandline ""
) which runs pretty much instantaneously. But now, it's bound to a function, which runs, evaluates some things in interpreted code, running several command substitutions then shells out to tput
to clear any potential autosuggestions on the line, then shells out to seq, and executes commandline
about a dozen times.
Profiling the old behavior with \cc
bound to commandline ''
shows the following:
390 390 > commandline ""
but now, this is what ^C triggers, as profiled:
343 26220 > __fish_cancel_commandline
382 407 -> source /usr/local/share/fish/functions/__fish_cancel_commandline.fish
25 25 --> function __fish_cancel_commandline
set -l cmd (commandline)
if test -n "$cmd"
commandline -C 1000000
if set -q fish_color_cancel
echo -ns (set_color $fish_color_cancel) "^C" (set_color normal)
else
echo -ns "^C"
end
if command -sq tput
# Clear to EOL (to erase any autosuggestion).
echo -n (tput el; or tput ce)
end
for i in (seq (commandline -L))
echo ""
end
commandline ""
commandline -f repaint
end
...
99 209 -> set -l cmd (commandline)
110 110 --> commandline
303 25261 -> if test -n "$cmd"
commandline -C 1000000
if set -q fish_color_cancel
echo -ns (set_color $fish_color_cancel) "^C" (set_color normal)
else
echo -ns "^C"
end
if command -sq tput
# Clear to EOL (to erase any autosuggestion).
echo -n (tput el; or tput ce)
end
for i in (seq (commandline -L))
echo ""
end
commandline ""
commandline -f repaint
...
19 19 --> test -n "$cmd"
249 249 --> commandline -C 1000000
22 81 --> if set -q fish_color_cancel
echo -ns (set_color $fish_color_cancel) "^C" (set_color normal)
else
echo -ns "^C"
...
21 21 ---> set -q fish_color_cancel
38 38 ---> echo -ns "^C"
33 7214 --> if command -sq tput
# Clear to EOL (to erase any autosuggestion).
echo -n (tput el; or tput ce)
...
513 513 ---> command -sq tput
286 6668 ---> echo -n (tput el; or tput ce)
6382 6382 ----> tput el
284 16910 --> for i in (seq (commandline -L))
echo ""
...
15623 16537 ---> seq (commandline -L)
431 854 ----> source /usr/local/share/fish/functions/seq.fish
8 423 -----> if not command -sq seq
# No seq command
function seq --description "Print sequences of numbers"
__fish_fallback_seq $argv
end
function __fish_fallback_seq --description "Fallback implementation of the seq command"
set -l from 1
set -l step 1
set -l to 1
switch (count $argv)
case 1
set to $argv[1]
case 2
set from $argv[1]
set to $argv[2]
case 3
set from $argv[1]
set step $argv[2]
set to $argv[3]
case '*'
printf (_ "%s: Expected 1, 2 or 3 arguments, got %d\n") seq (count $argv)
return 1
end
for i in $from $step $to
if not string match -rq '^-?[0-9]*([0-9]*|\.[0-9]+)$' $i
printf (_ "%s: '%s' is not a number\n") seq $i
return 1
end
end
if [ $step -ge 0 ]
echo "for( i=$from; i<=$to ; i+=$step ) i;" | bc
else
echo "for( i=$from; i>=$to ; i+=$step ) i;" | bc
end
end
...
415 415 ------> not command -sq seq
60 60 ----> commandline -L
89 89 ---> echo ""
454 454 --> commandline ""
31 31 --> commandline -f repaint
40 178 > fish_mode_prompt
57 138 -> fish_default_mode_prompt
10 81 --> if test "$fish_key_bindings" = "fish_vi_key_bindings"
or test "$fish_key_bindings" = "fish_hybrid_key_bindings"
switch $fish_bind_mode
case default
set_color --bold --background red white
echo '[N]'
case insert
set_color --bold --background green white
echo '[I]'
case replace_one
set_color --bold --background green white
echo '[R]'
case visual
set_color --bold --background magenta white
echo '[V]'
end
set_color normal
echo -n ' '
...
45 45 ---> test "$fish_key_bindings" = "fish_vi_key_bindings"
26 26 ---> test "$fish_key_bindings" = "fish_hybrid_key_bindings"
37 1174 > fish_prompt
20 20 -> set -l color_cwd
16 16 -> set -l suffix
26 62 -> switch "$USER"
case root toor
if set -q fish_color_cwd_root
set color_cwd $fish_color_cwd_root
else
set color_cwd $fish_color_cwd
end
set suffix '#'
case '*'
set color_cwd $fish_color_cwd
set suffix '>'
...
21 21 --> set color_cwd $fish_color_cwd
15 15 --> set suffix '>'
228 1039 -> echo -n -s "$USER" @ (prompt_hostname) ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
24 83 --> prompt_hostname
59 59 ---> string replace -r "\..*" "" $hostname
41 41 --> set_color $color_cwd
91 641 --> prompt_pwd
20 20 ---> set -l options 'h/help'
26 26 ---> argparse -n prompt_pwd --max-args=0 $options -- $argv
6 20 ---> if set -q _flag_help
__fish_print_help prompt_pwd
return 0
...
14 14 ----> set -q _flag_help
13 13 ---> set -q fish_prompt_pwd_dir_length
15 15 ---> set -l fish_prompt_pwd_dir_length 1
53 53 ---> set realhome ~
193 273 ---> set -l tmp (string replace -r '^'"$realhome"'($|/)' '~$1' $PWD)
80 80 ----> string replace -r '^'"$realhome"'($|/)' '~$1' $PWD
25 130 ---> if [ $fish_prompt_pwd_dir_length -eq 0 ]
echo $tmp
else
# Shorten to at most $fish_prompt_pwd_dir_length characters per directory
string replace -ar '(\.?[^/]{'"$fish_prompt_pwd_dir_length"'})[^/]*/' '$1/' $tmp
...
42 42 ----> [ $fish_prompt_pwd_dir_length -eq 0 ]
63 63 ----> string replace -ar '(\.?[^/]{'"$fish_prompt_pwd_dir_length"'})[^/]*/' '$1/' $tmp
46 46 --> set_color normal
The current implementation is 67 times slower and that's without my PC being bogged down with any background tasks that would slow down kernel calls and external executions, followed up with a repeat evaluation of the prompt (and mine is the default, fast prompt) and with all events firing (and this is how it performs with an external seq
available).
I know @ridiculousfish wanted to revert this behavior in #4713 for subjective complaints (his and others), but I'm not trying to dig that up again - all I'm saying is that if we keep the current behavior, it needs to be implemented in reader.cpp
or as an execution mode for the commandline
builtin because the current implementation gives a rather poor experience in an otherwise snappy UI.