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

Preview window sizing - specify size of finder list instead of preview window #3570

Closed
6 of 10 tasks
jstm88 opened this issue Jan 9, 2024 · 4 comments
Closed
6 of 10 tasks

Comments

@jstm88
Copy link

jstm88 commented Jan 9, 2024

  • I have read through the manual page (man fzf)
  • I have the latest version of fzf
  • I have searched through the existing issues

Info

  • OS
    • Linux
    • Mac OS X
    • Windows
    • Etc.
  • Shell
    • bash
    • zsh
    • fish

Problem / Steps to reproduce

With the current option set, the preview window can be sized according to two primary methods:

  • Set the preview window to a fixed number of lines/columns
  • Set the preview window to a percentage

In both of these cases, the finder (i.e. the actual searchable list) fills the remainder of the space. It does not appear possible, however, to specify the size of the finder list, then allow the preview window to fill the remainder.

This applies to both horizontal and vertical layouts. For horizontal splits, the number of lines shown in the finder could be specified, while in horizontal layouts the size of the finder could be set to an exact character width.

I have seen a few other topics related to automatically sizing the preview window, but none that I saw seemed to cover the use case of fixing the finder list to a specified number of lines (or width).

Suggestions

The simplest version of this would be a way to specify that the size given in the preview window's configuration string is meant to apply to the finder component. This would probably be the easiest implementation, requiring one additional specifier to be added to the syntax. I know this syntax is already relatively complex so the benefits should be weighed. Perhaps adding either a minus sign or exclamation mark before the size might make sense here. For example --preview-window 'down:-10' would result in 10 lines in the finder, and the preview window filling the remaining space.

Another thing to consider is allowing the finder to set its line count to exactly the number of lines in the input, leaving all remaining space for the preview. This would be great but would also need to consider dynamic updating as more lines come in from a longer running process. Here, it would be nice to be able to specify a maximum size, with the size of the finder list growing up to that size. For vertical splits, the ability to size to the character count of the longest item would be a similar concept.

As a final consideration, it might be possible to specify a "hook" function, where we could implement our own algorithm for responding to incoming lines. I imagine this would take a set of inputs (the most relevant being the current terminal width/height, current item count, and the character count of the longest item received) and it would simply return the desired height or width. Certainly the most complex, but this could also be extremely powerful.

@junegunn
Copy link
Owner

What's the exact use case? I'd like to know why you need the functionality.


it might be possible to specify a "hook" function

The new transform action opens up a whole new possibilities.

seq 100 | fzf --preview 'date; seq 1000' --bind 'focus:transform:echo change-preview-window:down,{}'

There are two limitations though,

  • Currently there is no direct way to access the number of matches or the total number of entries from the command template. We could consider adding placeholder expressions like {fzf:total_count} or expose the information via environment variables
  • change-preview-window redraws the whole screen, and you might notice the flicking of the screen

@cohml
Copy link

cohml commented Jan 11, 2024

What's the exact use case? I'd like to know why you need the functionality.

#3572 provides one possible use case where exposing the totalCount (or really, the matchCount) could prove useful.

@jstm88
Copy link
Author

jstm88 commented Jan 11, 2024

Thanks @junegunn, that's actually extremely close to being able to do what I'm trying to do.

--bind "focus:transform:echo \"change-preview-window:\$[\$(tput lines 2< $TTY) - $TARGETLINES - 4]\""

Each time this runs it gets the current window height (note that $TTY is embedded into the bind string in order to allow tput to get the size of the enclosing terminal). Then the height of the preview is calculated based on the number of target lines in the list (after compensating for the borders and headers, which is 4).

The main limitation is that focus does not run when the enclosing terminal changes height. As far as I can tell, there's no available trigger that would do the equivalent, so I don't think --bind is capable of doing dynamic resizing. Triggering a selection change resets it so it's close (and usable for me) but adding something like a resize trigger would be really great here.

Also, I have yet to implement the logic that limits line count. This is the simple case (set finder to a target length) but the final goal is to also limit that target based on count. So effectively the finder would be set to min(target, item_count).

For getting the item count (and other similar values) the thread @cohml linked to does indicate that using the --listen option could be used in combination with my bind string to allow the script to query fzf for the line count. However, @junegunn you also mentioned exposing these via placeholder expressions. I don't see anything in the documentation to suggest this is a thing right now, so it seems like that might be a future feature.

Combining this, I think my specific use case can be mostly covered:

  • Continue to use focus as the trigger
  • To resize based on result count, use --listen and then query localhost in the --bind function.

Then, if and when new features are added:

  • Switch the trigger to resize
  • Switch to placeholders instead of querying the server

Excited to see where this goes. The --bind function has huge potential if it's able to have the triggers and inputs it needs.

@junegunn
Copy link
Owner

resize event is added.

The current solution isn't ideal because the maximum number of items fzf can display on screen varies depending on --info style, --header, preview window border, etc. So you have to do some calculations as shown below. But the effects of --border, --margin, and --padding options are covered by using $FZF_LINES.

# Script to dynamically resize the preview window
transformer='
  # 1 line for info, another for prompt, and 2 more lines for preview window border
  lines=$(( FZF_LINES - FZF_MATCH_COUNT - 4 ))
  if [[ $FZF_MATCH_COUNT -eq 0 ]]; then
    echo "change-preview-window:hidden"
  elif [[ $lines -gt 3 ]]; then
    echo "change-preview-window:$lines"
  elif [[ $FZF_PREVIEW_LINES -ne 3 ]]; then
    echo "change-preview-window:3"
  fi
'
seq 10000 | fzf --preview 'seq {} 10000' --preview-window up \
                --bind "result:transform:$transformer" \
                --bind "resize:transform:$transformer"

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

No branches or pull requests

3 participants