Cursor and prompt control in function to avoid prompt flick
tmpm697 opened this issue · 10 comments
What happened, and what did you expect to happen?
set-env FZF_DEFAULT_OPTS "--height=40%"
set-env FZF_DEFAULT_COMMAND ""
fn flick-test {
echo "1\n2\n3\n4\n5\n" | fzf --reverse
sleep 3
edit:redraw &full=$true
}
set edit:insert:binding[Ctrl-T] = { flick-test >$os:dev-tty 2>&1 }
github-flick.mov
expecting: after select candidate in fzf and exit fzf cleanly, sleep 3
will not drop cursor to next line while sleep 3
is running --> should keep cursor and prompt as before trigger ctrl-t
so i think a flag that on/off prompt manually by user would solve this issue.
idk if this is bug or feature request, but it looks like a bug to me.
Output of "elvish -version"
0.20.1
Code of Conduct
- I agree to follow Elvish's Code of Conduct.
expecting: after select candidate in fzf and exit fzf cleanly, sleep 3 will not drop cursor to next line while sleep 3 is running --> should keep cursor and prompt as before trigger ctrl-t
What you describe isn't possible. The fzf
command has already written the text followed by a newline. The newline written by fzf
is causing the terminal to move the cursor to the line after the selection. This isn't due to anything Elvish is doing.
It's not clear what you expect. Try doing the same thing, by adding the following to the end of you ~/.bashrc:
export FZF_DEFAULT_OPTS="--height=40%"
export FZF_DEFAULT_COMMAND=""
flick-test() {
echo $'1\n2\n3\n4\n5' | fzf --reverse
sleep 3
}
bind -x '"\C-t":"flick-test"'
The only difference is that bash will move the cursor to the line following the prompt in effect when you press Ctrl-T. Both Elvish and Bash will redraw the prompt, including anything you might have typed (e.g., "echo") before pressing Ctrl-T. Personally, I prefer the Elvish behavior.
You can try to remove sleep 3
--> fzf
will exit and return prompt super fast, you're including fzf
in this case but it's minor. The issue is sleep
command holding prompt.
It's ideal if user can also
instruct fzf that it should keep prompt intact, just draw its list and redraw its own list below only
Holding
prompt is reasonable when you're in interactive mode, in which shell waiting for user to type smth and then let the command change the prompt and wait for it to return result.
But in a function, especially when trigger keybinding to call a function, the interactive behavior causes flick issue which should be a voided.
I still don't understand what the problem is. There is no way to tell an external program like fzf
it should keep the Elvish prompt intact. Elvish could be modified to behave like Bash but it's not clear that is preferable. On the contrary, I like the Elvish behavior of letting the external command use the line containing the current prompt. I also suspect you are using the word "flicker" in a manner different from how the rest of us who have engaged with you on this issue use the term because none of us consider what you are describing to be an example of "flicker". So like @MiLk on the discussion channel I'm going to bow out of this discussion because, despite trying really hard, I still don't understand what the problem is.
Thanks @krader1961 for the bash version, indeed the same thing happens (except as you say, bash moves the cursor position down so the old prompt is not affected by fzf output). In bash the partially entered text stays on screen (i.e. in bash type 3 then ctrl+t then select 5 and you'll see the 3 and 5 on the screen), very confusing! Elvish removes the partial text so this doesn't happen, I would assume this is a deliberate design choice.
@tmpm697 -- if you use a two line prompt (I use starship) in elvish then it looks more similar to bash...
@iandol I agree with your analysis. What is unclear to me is whether that difference in behavior is what @tmpm697 is complaining about. That's because their original problem statement is ambiguous. Specifically, this statement:
expecting: after select candidate in fzf and exit fzf cleanly, sleep 3 will not drop cursor to next line while sleep 3 is running --> should keep cursor and prompt as before trigger ctrl-t
@tmpm697 It might help if you (a) commented on how the Bash behavior differs from the Elvish behavior, and (b) provided a mockup of the Elvish behavior you prefer. Regarding point (a) does Bash behave as you prefer? Obviously you can't run Elvish to address my point (b) but it should be straightforward to create a simulated output using the markdown triple-quote mechanism to create a mockup of the output you expect to see.
What is unclear to me is whether that difference in behavior is what @tmpm697 is complaining about
I am pretty sure it is. For him the prompt is "flickering", which is visible in his first video as a single frame where the Elvish prompt disappears then reappears, causing a "flash". The behaviour is best described as prompt flicker (a fluctuation in brightness caused by the temporary removal of the prompt). He wants the Elvish prompt to remain on screen during the sleep, so that when it returns from sleep there is no flicker on that line.
Here is what Elvish is doing. FRAME C is the critical one, where line 1 prompt disappears.
FRAME A:
~/.config/test>
FRAME B:
~/.config/test>
> |
6/6------------------------------
> 1
2
FRAME C:
1
|
FRAME D:
1
~/.config/test>
I think he would want FRAME C to be like this (line 1 keeps the prompt, it is line 2 that now holds the fzf output during the sleep):
FRAME C-ALT:
~/.config/test>
1
|
How FRAME D would then be drawn I think is not the issue, the point is the prompt disappears then reappears...
As I said above, using a two-line prompt you don't see this as most of the prompt is on the first line.
@iandol thanks, it seems to be like that, when fzf is called -> move cursor where it's needed (in this case drop cursor next line and hold where user can type input)
my idea is simple, hold
the cursor/prompt until a program need it or user explicitly allow it, i.e: when fzf needs cursor, gives it, but it should not need prompt
until user want to update current dir or current-command which is often after fzf exit.
surprisingly fzf has option --no-clear
which instructs fzf not
to redraw when it exits but currently aik, if use it prompt will be swallowed by fzf fuzzy menu.
so fzf redraw a lot and it hold
the prompt and current-command also while it's running which it shouldn't be, it should hold only area below prompt for its fuzzy menu.
more info if someone stumble by this issue, this flick issue with fzf
and terminal will be reduced if you set fzf --height 100%
--> fzf take full terminal screen and display fuzzy list at top
or fzf --layout=default --height 100%
--> fzf takes full terminal screen and display fuzzy list at bottom.
or you proactively drop new line for fzf echo "", fzf
or you use two lines prompt which @iandol mentioned above.
but they are not what i want :)
After a while battling with this issue, I think it's not shells in general to blame but mostly terminals.
As general shell users, you use pipe and whatever commands to achieve your purpose, but this is not the case when you deal with script that every call cost you the time to return back to your interactive mode,
which mean the more you're exposed to have a prompt flick,
the close one is writing your script which cost free or instantly return back to your shell which is a bit challenge as you need to understand your shells.