Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start fzf from current row #405

Closed
g0xA52A2A opened this issue Nov 4, 2015 · 15 comments
Closed

Start fzf from current row #405

g0xA52A2A opened this issue Nov 4, 2015 · 15 comments

Comments

@g0xA52A2A
Copy link

Rather than just dropping this on the wiki I just wanted to post this first as I'm sure it's pretty ugly.

This works out how may rows the terminal has and which row you are on. It then starts fzf on the current row and displays the possible completion options above or below depending on which has the most space. I find this makes the invocation of fzf less jarring in some ways.

Any and all feedback appreciated!

# The logic in the getpos function is stolen from
# http://stackoverflow.com/a/2575525
# Pass "row" or "col" as an argument to get their positions
getpos () {
  exec < /dev/tty
  oldstty=$(stty -g)
  stty raw -echo min 0
  echo -en "\033[6n" > /dev/tty
  IFS=';' read -r -d R -a pos
  stty $oldstty
  local row=$((${pos[0]:2} - 1))  # strip off the esc-[
  local col=$((${pos[1]} - 1))

  if [[ $1 = row ]]; then
    echo $row
  elif [[ $1 = col ]]; then
    echo $col
  fi
}

lines=$(tput lines)
row=$(getpos row)
halfway=$(expr $lines / 2)

# Start fzf from the current row
if [ "$row" -lt "$halfway" ]; then
  start_row=$(expr $row - 1)
  FZF_DEFAULT_OPTS+=' --reverse '
  FZF_DEFAULT_OPTS+=" --margin ${start_row},0,0 "
else
  start_row=$(expr $lines - $row + 1)
  FZF_DEFAULT_OPTS+=" --margin 0,0,${start_row} "
fi

fzf
@junegunn
Copy link
Owner

junegunn commented Nov 5, 2015

Amazing, I never thought this would be possible. This is definitely going to be useful when not on tmux. With a few improvements we can even consider adding it to bin directory of the repo. I'll try it for a while and give you some feedback. Thanks.

@g0xA52A2A
Copy link
Author

I got the desire of this sort of layout having played with selecta. It has some rendering issues which seem to be addressed in a rust clone heatseaker which I've stumbled across today. Not sure if you've thought about this kind of interface for fzf? Just an off-hand comment, I appreciate it's not very useful without patches.

@junegunn
Copy link
Owner

junegunn commented Nov 5, 2015

Oh yeah, I'm aware of those projects. Unlike fzf, they use low-level ANSI codes to control the screen instead of depending on ncurses. The approach has the benefit of not having to use fullscreen, which I think is really nice. However, it seems much less stable than rock-solid ncurses, and cannot reliably support various key bindings and mouse like fzf does (yes I do use mouse on fzf sometimes!). And since tmux integration, I'm more or less content with the way fzf works.

I suggest a few changes to the script:

  • start_row=$(expr $lines - $row) without + 1 seems to work better for me
  • fzf should take the command-line arguments
    • But we should override --reverse and --margin, so I think it's better to directly pass those options to fzf instead of setting FZF_DEFAULT_OPTS
  • It seems $row never reaches $lines, so we always have at least one empty line when the script is started with the cursor at the bottom of the screen which is most of the time. So I think it's reasonable to adjust the margin for that case.
# Start fzf from the current row
opts=
if [ "$row" -lt "$halfway" ]; then
  start_row=$(expr $row - 1)
  opts="--reverse --margin ${start_row},0,0"
else
  start_row=$(expr $lines - $row)
  [ $start_row -eq 1 ] && start_row=0
  opts="--no-reverse --margin 0,0,${start_row}"
fi

fzf "$@" $opts

And I like the script so far, it looks pretty clever, though I'm almost always on tmux so I'm not so sure if I'm going to use it often. Do you think it makes sense to include the script in the official repo?

@g0xA52A2A
Copy link
Author

Thanks for the insight! I agree with all your points.

Do you think it makes sense to include the script in the official repo?

Originally I was intending to just put this on the wiki, I think this should be fairly portable so I guess it's not harmful to have it in the main repo. If it does go into the repo maybe the getpos function should be simplified to just return the row number? I left the column stuff in just in-case I wanted to use it later.

@d630
Copy link

d630 commented Nov 5, 2015

@George-B What's your termial? I have tested it in st, with no luck ...

By the way: You can calculate in POSIX shell without subshells using arithmetic expansion like $(( x + y )). In bash you can also use let or (( x=y+z )) ( or: typeset -i x=y+z ; x=x+=i)

@g0xA52A2A
Copy link
Author

@d630 Guilty confession I'm in PuTTY most of the time these days, thanks for the arithmetic tip. I'll have to spin up a VM and do some testing with st and other terminals.

@g0xA52A2A
Copy link
Author

@d630 have you tried with modification @junegunn suggested? In my initial testing I realized my original example does not work if FZF_DEFAULT_OPTS is unset. This works for me in st and gnome terminal on a Fedora 23 VM.

@d630
Copy link

d630 commented Nov 5, 2015

@junegunn
Copy link
Owner

junegunn commented Nov 5, 2015

@George-B How about sending me a pull request? We can continue the discussion there. By the way, I have absolutely no idea how we should call the script ;)

I think we can even consider using it in the default key bindings and fuzzy completion when not on tmux.

@acornejo
Copy link
Contributor

AFAIK ncurses still clears the whole screen even when starting using a margin right?

@acornejo
Copy link
Contributor

PS: I ask because I was preparing a pull-request which added an "auto-margin" option which retrieved the current cursor position and then computed the margin accordingly. However, after all the ioctls where done I realized that margin doesn't really prevent fzf from clearing the entire screen.

@junegunn
Copy link
Owner

AFAIK ncurses still clears the whole screen even when starting using a margin right?

@acornejo Yeah, that is basically how ncurses works.

@acornejo
Copy link
Contributor

Tks @junegunn, just closed the PR. If clearing the screen is unavoidable I don't see how starting from the current row is a desirable feature (if someone sees value on it, let me know since I had the code to add this to the fzf binary instead of doing it through shell scripts).

@g0xA52A2A
Copy link
Author

Woah totally forgot about this! I'm actually not using fzf much these days, @junegunn should this be closed?

@junegunn
Copy link
Owner

@acornejo I think the benefit is that we don't have to move our focus when fzf is started in full screen mode. But yeah, the usefulness of it is quite limited.

@George-B I'll close it. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants