mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-06-03 16:00:49 +00:00
(Experimental) Improve Sixel graphics support (#2544)
Progress: * Sixel image can now be displayed with other text, and is scrollable * If an image can't be displayed entirely due to the scroll offset, fzf will render a wireframe to indicate that an image should be displayed * Renamed $FZF_PREVIEW_{WIDTH,HEIGHT} to $FZF_PREVIEW_PIXEL_{WIDTH,HEIGHT} for clarity * Added bin/fzf-preview.sh script to demonstrate how to display an image using Kitty or Sixel protocol An example: ls *.jpg | fzf --preview='seq $((FZF_PREVIEW_LINES*9/10)); fzf-preview.sh {}; seq 100' A known issue: * If you reduce the size of the preview window, the image may extend beyond the preview window
This commit is contained in:
parent
bac385b59c
commit
d02b9442a5
26
CHANGELOG.md
26
CHANGELOG.md
|
@ -3,27 +3,21 @@ CHANGELOG
|
||||||
|
|
||||||
0.43.1
|
0.43.1
|
||||||
------
|
------
|
||||||
- (Experimental) Added support for Sixel graphics in the preview window
|
- (Experimental) Sixel image support in preview window (not available on Windows)
|
||||||
```sh
|
- `$FZF_PREVIEW_PIXEL_WIDTH` and `$FZF_PREVIEW_PIXEL_HEIGHT` are set to
|
||||||
# 1. $FZF_PREVIEW_WIDTH and $FZF_PREVIEW_HEIGHT will be set to the pixel width
|
the pixel width and height of the preview window
|
||||||
# and height of the preview window
|
- [bin/fzf-preview.sh](bin/fzf-preview.sh) is added to demonstrate how to
|
||||||
# 2. Special preview window flag 'clear' is added to always completely
|
display an image using Kitty image protocol or Sixel. You can use it
|
||||||
# erase the preview window. This is similar to https://github.com/vifm/vifm/issues/588.
|
like so:
|
||||||
fzf --preview='
|
```sh
|
||||||
if file --mime-type {} | grep -qvF image/; then
|
fzf --preview='fzf-preview.sh {}'
|
||||||
bat --color=always {}
|
```
|
||||||
elif [[ -n $FZF_PREVIEW_WIDTH ]]; then
|
|
||||||
convert {} -resize ${FZF_PREVIEW_WIDTH}x${FZF_PREVIEW_HEIGHT} sixel:-
|
|
||||||
else
|
|
||||||
echo "Cannot display image data (unsupported platform)"
|
|
||||||
fi
|
|
||||||
' --preview-window clear
|
|
||||||
```
|
|
||||||
- Bug fixes
|
- Bug fixes
|
||||||
|
|
||||||
0.43.0
|
0.43.0
|
||||||
------
|
------
|
||||||
- (Experimental) Added support for Kitty image protocol in the preview window
|
- (Experimental) Added support for Kitty image protocol in the preview window
|
||||||
|
(not available on Windows)
|
||||||
```sh
|
```sh
|
||||||
fzf --preview='
|
fzf --preview='
|
||||||
if file --mime-type {} | grep -qF image/; then
|
if file --mime-type {} | grep -qF image/; then
|
||||||
|
|
30
bin/fzf-preview.sh
Executable file
30
bin/fzf-preview.sh
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# The purpose of this script is to demonstrate how to preview a file or an
|
||||||
|
# image in the preview window of fzf.
|
||||||
|
|
||||||
|
file=$1
|
||||||
|
type=$(file --mime-type "$file")
|
||||||
|
|
||||||
|
if [[ ! $type =~ image/ ]]; then
|
||||||
|
# Sometimes bat is installed as batcat.
|
||||||
|
if command -v batcat > /dev/null; then
|
||||||
|
batname="batcat"
|
||||||
|
elif command -v bat > /dev/null; then
|
||||||
|
batname="bat"
|
||||||
|
else
|
||||||
|
cat "$1"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
${batname} --style="${BAT_STYLE:-numbers}" --color=always --pager=never -- "$file"
|
||||||
|
elif [[ $KITTY_WINDOW_ID ]]; then
|
||||||
|
# 'memory' is the fastest option but if you want the image to be scrollable,
|
||||||
|
# you have to use 'stream'
|
||||||
|
kitty icat --clear --transfer-mode=memory --stdin=no --place="${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}@0x0" "$file" | sed \$d
|
||||||
|
echo -en "\e[m"
|
||||||
|
elif [[ -n $FZF_PREVIEW_PIXEL_WIDTH ]]; then
|
||||||
|
convert "$file" -resize "${FZF_PREVIEW_PIXEL_WIDTH}x${FZF_PREVIEW_PIXEL_HEIGHT}>" -dither FloydSteinberg sixel:-
|
||||||
|
else
|
||||||
|
file "$file"
|
||||||
|
fi
|
|
@ -592,34 +592,12 @@ e.g.
|
||||||
sleep 0.01
|
sleep 0.01
|
||||||
done'\fR
|
done'\fR
|
||||||
|
|
||||||
Since 0.43.0, fzf has experimental support for Kitty graphics protocol,
|
fzf has experimental support for Kitty graphics protocol and Sixel graphics.
|
||||||
so if you use Kitty, you can make fzf display an image in the preview window.
|
The following example uses https://github.com/junegunn/fzf/blob/master/bin/fzf-preview.sh
|
||||||
|
script to render an image using either of the protocols inside the preview window.
|
||||||
|
|
||||||
e.g.
|
e.g.
|
||||||
\fBfzf --preview='
|
\fBfzf --preview='fzf-preview.sh {}'
|
||||||
if file --mime-type {} | grep -qF "image/"; then
|
|
||||||
kitty icat --clear --transfer-mode=memory --stdin=no --place=${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}@0x0 {} | sed \\$d
|
|
||||||
else
|
|
||||||
bat --color=always {}
|
|
||||||
fi
|
|
||||||
'\fR
|
|
||||||
|
|
||||||
fzf also has experimental support for Sixel graphics.
|
|
||||||
|
|
||||||
e.g.
|
|
||||||
\fB# 1. $FZF_PREVIEW_WIDTH and $FZF_PREVIEW_HEIGHT will be set to
|
|
||||||
# the pixel width and height of the preview window
|
|
||||||
# 2. Special preview window flag 'clear' is needed to always completely
|
|
||||||
# erase the preview window
|
|
||||||
fzf --preview='
|
|
||||||
if file --mime-type {} | grep -qvF image/; then
|
|
||||||
bat --color=always {}
|
|
||||||
elif [[ -n $FZF_PREVIEW_WIDTH ]]; then
|
|
||||||
convert {} -resize ${FZF_PREVIEW_WIDTH}x${FZF_PREVIEW_HEIGHT} sixel:-
|
|
||||||
else
|
|
||||||
echo "Cannot display image data (unsupported platform)"
|
|
||||||
fi
|
|
||||||
' --preview-window clear\fR
|
|
||||||
|
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,6 @@ type previewOpts struct {
|
||||||
scroll string
|
scroll string
|
||||||
hidden bool
|
hidden bool
|
||||||
wrap bool
|
wrap bool
|
||||||
clear bool
|
|
||||||
cycle bool
|
cycle bool
|
||||||
follow bool
|
follow bool
|
||||||
border tui.BorderShape
|
border tui.BorderShape
|
||||||
|
@ -341,7 +340,7 @@ type Options struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultPreviewOpts(command string) previewOpts {
|
func defaultPreviewOpts(command string) previewOpts {
|
||||||
return previewOpts{command, posRight, sizeSpec{50, true}, "", false, false, false, false, false, tui.DefaultBorderShape, 0, 0, nil}
|
return previewOpts{command, posRight, sizeSpec{50, true}, "", false, false, false, false, tui.DefaultBorderShape, 0, 0, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultOptions() *Options {
|
func defaultOptions() *Options {
|
||||||
|
@ -1455,10 +1454,6 @@ func parsePreviewWindowImpl(opts *previewOpts, input string, exit func(string))
|
||||||
opts.wrap = true
|
opts.wrap = true
|
||||||
case "nowrap":
|
case "nowrap":
|
||||||
opts.wrap = false
|
opts.wrap = false
|
||||||
case "clear":
|
|
||||||
opts.clear = true
|
|
||||||
case "noclear":
|
|
||||||
opts.clear = false
|
|
||||||
case "cycle":
|
case "cycle":
|
||||||
opts.cycle = true
|
opts.cycle = true
|
||||||
case "nocycle":
|
case "nocycle":
|
||||||
|
@ -1793,7 +1788,7 @@ func parseOptions(opts *Options, allArgs []string) {
|
||||||
opts.Preview.command = ""
|
opts.Preview.command = ""
|
||||||
case "--preview-window":
|
case "--preview-window":
|
||||||
parsePreviewWindow(&opts.Preview,
|
parsePreviewWindow(&opts.Preview,
|
||||||
nextString(allArgs, &i, "preview window layout required: [up|down|left|right][,SIZE[%]][,border-BORDER_OPT][,wrap][,clear][,cycle][,hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default]"))
|
nextString(allArgs, &i, "preview window layout required: [up|down|left|right][,SIZE[%]][,border-BORDER_OPT][,wrap][,cycle][,hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default]"))
|
||||||
case "--height":
|
case "--height":
|
||||||
opts.Height = parseHeight(nextString(allArgs, &i, "height required: [~]HEIGHT[%]"))
|
opts.Height = parseHeight(nextString(allArgs, &i, "height required: [~]HEIGHT[%]"))
|
||||||
case "--min-height":
|
case "--min-height":
|
||||||
|
|
136
src/terminal.go
136
src/terminal.go
|
@ -121,10 +121,12 @@ type previewer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type previewed struct {
|
type previewed struct {
|
||||||
version int64
|
version int64
|
||||||
numLines int
|
numLines int
|
||||||
offset int
|
offset int
|
||||||
filled bool
|
filled bool
|
||||||
|
wipe bool
|
||||||
|
wireframe bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type eachLine struct {
|
type eachLine struct {
|
||||||
|
@ -278,6 +280,7 @@ type Terminal struct {
|
||||||
theme *tui.ColorTheme
|
theme *tui.ColorTheme
|
||||||
tui tui.Renderer
|
tui tui.Renderer
|
||||||
executing *util.AtomicBool
|
executing *util.AtomicBool
|
||||||
|
termSize tui.TermSize
|
||||||
}
|
}
|
||||||
|
|
||||||
type selectedItem struct {
|
type selectedItem struct {
|
||||||
|
@ -308,6 +311,7 @@ const (
|
||||||
reqRefresh
|
reqRefresh
|
||||||
reqReinit
|
reqReinit
|
||||||
reqFullRedraw
|
reqFullRedraw
|
||||||
|
reqResize
|
||||||
reqRedrawBorderLabel
|
reqRedrawBorderLabel
|
||||||
reqRedrawPreviewLabel
|
reqRedrawPreviewLabel
|
||||||
reqClose
|
reqClose
|
||||||
|
@ -447,7 +451,7 @@ type searchRequest struct {
|
||||||
|
|
||||||
type previewRequest struct {
|
type previewRequest struct {
|
||||||
template string
|
template string
|
||||||
pwindow tui.Window
|
pwindowSize tui.TermSize
|
||||||
scrollOffset int
|
scrollOffset int
|
||||||
list []*Item
|
list []*Item
|
||||||
}
|
}
|
||||||
|
@ -687,7 +691,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||||
initialPreviewOpts: opts.Preview,
|
initialPreviewOpts: opts.Preview,
|
||||||
previewOpts: opts.Preview,
|
previewOpts: opts.Preview,
|
||||||
previewer: previewer{0, []string{}, 0, false, true, disabledState, "", []bool{}},
|
previewer: previewer{0, []string{}, 0, false, true, disabledState, "", []bool{}},
|
||||||
previewed: previewed{0, 0, 0, false},
|
previewed: previewed{0, 0, 0, false, false, false},
|
||||||
previewBox: previewBox,
|
previewBox: previewBox,
|
||||||
eventBox: eventBox,
|
eventBox: eventBox,
|
||||||
mutex: sync.Mutex{},
|
mutex: sync.Mutex{},
|
||||||
|
@ -1930,7 +1934,7 @@ func (t *Terminal) renderPreviewSpinner() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) renderPreviewArea(unchanged bool) {
|
func (t *Terminal) renderPreviewArea(unchanged bool) {
|
||||||
if t.previewOpts.clear {
|
if t.previewed.wipe && t.previewed.version != t.previewer.version {
|
||||||
t.pwindow.Erase()
|
t.pwindow.Erase()
|
||||||
} else if unchanged {
|
} else if unchanged {
|
||||||
t.pwindow.MoveAndClear(0, 0) // Clear scroll offset display
|
t.pwindow.MoveAndClear(0, 0) // Clear scroll offset display
|
||||||
|
@ -1951,15 +1955,11 @@ func (t *Terminal) renderPreviewArea(unchanged bool) {
|
||||||
body = t.previewer.lines[headerLines:]
|
body = t.previewer.lines[headerLines:]
|
||||||
// Always redraw header
|
// Always redraw header
|
||||||
t.renderPreviewText(height, header, 0, false)
|
t.renderPreviewText(height, header, 0, false)
|
||||||
if t.previewOpts.clear {
|
t.pwindow.MoveAndClear(t.pwindow.Y(), 0)
|
||||||
t.pwindow.Move(t.pwindow.Y(), 0)
|
|
||||||
} else {
|
|
||||||
t.pwindow.MoveAndClear(t.pwindow.Y(), 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
t.renderPreviewText(height, body, -t.previewer.offset+headerLines, unchanged)
|
t.renderPreviewText(height, body, -t.previewer.offset+headerLines, unchanged)
|
||||||
|
|
||||||
if !unchanged && !t.previewOpts.clear {
|
if !unchanged {
|
||||||
t.pwindow.FinishFill()
|
t.pwindow.FinishFill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1972,10 +1972,29 @@ func (t *Terminal) renderPreviewArea(unchanged bool) {
|
||||||
t.renderPreviewScrollbar(headerLines, barLength, barStart)
|
t.renderPreviewScrollbar(headerLines, barLength, barStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) makeImageBorder(width int, top bool) string {
|
||||||
|
tl := "┌"
|
||||||
|
tr := "┐"
|
||||||
|
v := "╎"
|
||||||
|
h := "╌"
|
||||||
|
if !t.unicode {
|
||||||
|
tl = "+"
|
||||||
|
tr = "+"
|
||||||
|
h = "-"
|
||||||
|
v = "|"
|
||||||
|
}
|
||||||
|
repeat := util.Max(0, width-2)
|
||||||
|
if top {
|
||||||
|
return tl + strings.Repeat(h, repeat) + tr
|
||||||
|
}
|
||||||
|
return v + strings.Repeat(" ", repeat) + v
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unchanged bool) {
|
func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unchanged bool) {
|
||||||
maxWidth := t.pwindow.Width()
|
maxWidth := t.pwindow.Width()
|
||||||
var ansi *ansiState
|
var ansi *ansiState
|
||||||
spinnerRedraw := t.pwindow.Y() == 0
|
spinnerRedraw := t.pwindow.Y() == 0
|
||||||
|
Loop:
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
var lbg tui.Color = -1
|
var lbg tui.Color = -1
|
||||||
if ansi != nil {
|
if ansi != nil {
|
||||||
|
@ -1993,16 +2012,59 @@ func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unc
|
||||||
t.previewer.scrollable = true
|
t.previewer.scrollable = true
|
||||||
break
|
break
|
||||||
} else if lineNo >= 0 {
|
} else if lineNo >= 0 {
|
||||||
|
x := t.pwindow.X()
|
||||||
|
y := t.pwindow.Y()
|
||||||
if spinnerRedraw && lineNo > 0 {
|
if spinnerRedraw && lineNo > 0 {
|
||||||
spinnerRedraw = false
|
spinnerRedraw = false
|
||||||
y := t.pwindow.Y()
|
|
||||||
x := t.pwindow.X()
|
|
||||||
t.renderPreviewSpinner()
|
t.renderPreviewSpinner()
|
||||||
t.pwindow.Move(y, x)
|
t.pwindow.Move(y, x)
|
||||||
}
|
}
|
||||||
for _, passThrough := range passThroughs {
|
for _, passThrough := range passThroughs {
|
||||||
|
// Handling Sixel output
|
||||||
|
requiredLines := 0
|
||||||
|
if strings.HasPrefix(passThrough, "\x1bP") {
|
||||||
|
t.previewed.wipe = true
|
||||||
|
if t.termSize.PxHeight > 0 {
|
||||||
|
rows := util.Max(0, strings.Count(passThrough, "-")-1)
|
||||||
|
requiredLines = int(math.Ceil(float64(rows*6*t.termSize.Lines) / float64(t.termSize.PxHeight)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overflow
|
||||||
|
if requiredLines > 0 && y+requiredLines > height {
|
||||||
|
top := true
|
||||||
|
for ; y < height; y++ {
|
||||||
|
t.pwindow.MoveAndClear(y, 0)
|
||||||
|
t.pwindow.CFill(tui.ColPreview.Fg(), tui.ColPreview.Bg(), tui.AttrRegular, t.makeImageBorder(maxWidth, top))
|
||||||
|
top = false
|
||||||
|
}
|
||||||
|
t.previewed.wireframe = true
|
||||||
|
t.previewed.filled = true
|
||||||
|
t.previewer.scrollable = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.previewed.wireframe {
|
||||||
|
t.previewed.wireframe = false
|
||||||
|
for i := y + 1; i < height; i++ {
|
||||||
|
t.pwindow.MoveAndClear(i, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.pwindow.MoveAndClear(y, x)
|
||||||
t.tui.PassThrough(passThrough)
|
t.tui.PassThrough(passThrough)
|
||||||
|
|
||||||
|
if requiredLines > 0 {
|
||||||
|
if y+requiredLines == height {
|
||||||
|
t.pwindow.Move(y+requiredLines, 0)
|
||||||
|
t.previewed.filled = true
|
||||||
|
t.previewer.scrollable = true
|
||||||
|
break Loop
|
||||||
|
} else {
|
||||||
|
t.pwindow.MoveAndClear(y+requiredLines, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(passThroughs) > 0 && len(line) == 0 {
|
if len(passThroughs) > 0 && len(line) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -2100,6 +2162,7 @@ func (t *Terminal) printPreview() {
|
||||||
t.previewed.numLines = numLines
|
t.previewed.numLines = numLines
|
||||||
t.previewed.version = t.previewer.version
|
t.previewed.version = t.previewer.version
|
||||||
t.previewed.offset = t.previewer.offset
|
t.previewed.offset = t.previewer.offset
|
||||||
|
t.previewed.wipe = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) printPreviewDelayed() {
|
func (t *Terminal) printPreviewDelayed() {
|
||||||
|
@ -2580,6 +2643,19 @@ func (t *Terminal) cancelPreview() {
|
||||||
t.killPreview(exitCancel)
|
t.killPreview(exitCancel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) pwindowSize() tui.TermSize {
|
||||||
|
if t.pwindow == nil {
|
||||||
|
return tui.TermSize{}
|
||||||
|
}
|
||||||
|
size := tui.TermSize{Lines: t.pwindow.Height(), Columns: t.pwindow.Width()}
|
||||||
|
|
||||||
|
if t.termSize.PxWidth > 0 {
|
||||||
|
size.PxWidth = size.Columns * t.termSize.PxWidth / t.termSize.Columns
|
||||||
|
size.PxHeight = size.Lines * t.termSize.PxHeight / t.termSize.Lines
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
// Loop is called to start Terminal I/O
|
// Loop is called to start Terminal I/O
|
||||||
func (t *Terminal) Loop() {
|
func (t *Terminal) Loop() {
|
||||||
// prof := profile.Start(profile.ProfilePath("/tmp/"))
|
// prof := profile.Start(profile.ProfilePath("/tmp/"))
|
||||||
|
@ -2631,12 +2707,13 @@ func (t *Terminal) Loop() {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
<-resizeChan
|
<-resizeChan
|
||||||
t.reqBox.Set(reqFullRedraw, nil)
|
t.reqBox.Set(reqResize, nil)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
t.initFunc()
|
t.initFunc()
|
||||||
|
t.termSize = t.tui.Size()
|
||||||
t.resizeWindows(false)
|
t.resizeWindows(false)
|
||||||
t.printPrompt()
|
t.printPrompt()
|
||||||
t.printInfo()
|
t.printInfo()
|
||||||
|
@ -2669,7 +2746,7 @@ func (t *Terminal) Loop() {
|
||||||
for {
|
for {
|
||||||
var items []*Item
|
var items []*Item
|
||||||
var commandTemplate string
|
var commandTemplate string
|
||||||
var pwindow tui.Window
|
var pwindowSize tui.TermSize
|
||||||
initialOffset := 0
|
initialOffset := 0
|
||||||
t.previewBox.Wait(func(events *util.Events) {
|
t.previewBox.Wait(func(events *util.Events) {
|
||||||
for req, value := range *events {
|
for req, value := range *events {
|
||||||
|
@ -2679,7 +2756,7 @@ func (t *Terminal) Loop() {
|
||||||
commandTemplate = request.template
|
commandTemplate = request.template
|
||||||
initialOffset = request.scrollOffset
|
initialOffset = request.scrollOffset
|
||||||
items = request.list
|
items = request.list
|
||||||
pwindow = request.pwindow
|
pwindowSize = request.pwindowSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
events.Clear()
|
events.Clear()
|
||||||
|
@ -2691,18 +2768,16 @@ func (t *Terminal) Loop() {
|
||||||
command := t.replacePlaceholder(commandTemplate, false, string(query), items)
|
command := t.replacePlaceholder(commandTemplate, false, string(query), items)
|
||||||
cmd := util.ExecCommand(command, true)
|
cmd := util.ExecCommand(command, true)
|
||||||
env := t.environ()
|
env := t.environ()
|
||||||
if pwindow != nil {
|
if pwindowSize.Lines > 0 {
|
||||||
height := pwindow.Height()
|
lines := fmt.Sprintf("LINES=%d", pwindowSize.Lines)
|
||||||
lines := fmt.Sprintf("LINES=%d", height)
|
columns := fmt.Sprintf("COLUMNS=%d", pwindowSize.Columns)
|
||||||
columns := fmt.Sprintf("COLUMNS=%d", pwindow.Width())
|
|
||||||
env = append(env, lines)
|
env = append(env, lines)
|
||||||
env = append(env, "FZF_PREVIEW_"+lines)
|
env = append(env, "FZF_PREVIEW_"+lines)
|
||||||
env = append(env, columns)
|
env = append(env, columns)
|
||||||
env = append(env, "FZF_PREVIEW_"+columns)
|
env = append(env, "FZF_PREVIEW_"+columns)
|
||||||
size, err := t.tui.Size()
|
if pwindowSize.PxWidth > 0 {
|
||||||
if err == nil {
|
env = append(env, fmt.Sprintf("FZF_PREVIEW_PIXEL_WIDTH=%d", pwindowSize.PxWidth))
|
||||||
env = append(env, fmt.Sprintf("FZF_PREVIEW_WIDTH=%d", pwindow.Width()*size.Width/size.Columns))
|
env = append(env, fmt.Sprintf("FZF_PREVIEW_PIXEL_HEIGHT=%d", pwindowSize.PxHeight))
|
||||||
env = append(env, fmt.Sprintf("FZF_PREVIEW_HEIGHT=%d", height*size.Height/size.Lines))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd.Env = env
|
cmd.Env = env
|
||||||
|
@ -2831,7 +2906,7 @@ func (t *Terminal) Loop() {
|
||||||
if len(command) > 0 && t.canPreview() {
|
if len(command) > 0 && t.canPreview() {
|
||||||
_, list := t.buildPlusList(command, false)
|
_, list := t.buildPlusList(command, false)
|
||||||
t.cancelPreview()
|
t.cancelPreview()
|
||||||
t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.pwindow, t.evaluateScrollOffset(), list})
|
t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.pwindowSize(), t.evaluateScrollOffset(), list})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2899,7 +2974,10 @@ func (t *Terminal) Loop() {
|
||||||
case reqReinit:
|
case reqReinit:
|
||||||
t.tui.Resume(t.fullscreen, t.sigstop)
|
t.tui.Resume(t.fullscreen, t.sigstop)
|
||||||
t.redraw()
|
t.redraw()
|
||||||
case reqFullRedraw:
|
case reqResize, reqFullRedraw:
|
||||||
|
if req == reqResize {
|
||||||
|
t.termSize = t.tui.Size()
|
||||||
|
}
|
||||||
wasHidden := t.pwindow == nil
|
wasHidden := t.pwindow == nil
|
||||||
t.redraw()
|
t.redraw()
|
||||||
if wasHidden && t.hasPreviewWindow() {
|
if wasHidden && t.hasPreviewWindow() {
|
||||||
|
@ -3116,7 +3194,7 @@ func (t *Terminal) Loop() {
|
||||||
if valid {
|
if valid {
|
||||||
t.cancelPreview()
|
t.cancelPreview()
|
||||||
t.previewBox.Set(reqPreviewEnqueue,
|
t.previewBox.Set(reqPreviewEnqueue,
|
||||||
previewRequest{t.previewOpts.command, t.pwindow, t.evaluateScrollOffset(), list})
|
previewRequest{t.previewOpts.command, t.pwindowSize(), t.evaluateScrollOffset(), list})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Discard the preview content so that it won't accidentally appear
|
// Discard the preview content so that it won't accidentally appear
|
||||||
|
|
|
@ -38,9 +38,7 @@ func (r *FullscreenRenderer) Clear() {}
|
||||||
func (r *FullscreenRenderer) NeedScrollbarRedraw() bool { return false }
|
func (r *FullscreenRenderer) NeedScrollbarRedraw() bool { return false }
|
||||||
func (r *FullscreenRenderer) Refresh() {}
|
func (r *FullscreenRenderer) Refresh() {}
|
||||||
func (r *FullscreenRenderer) Close() {}
|
func (r *FullscreenRenderer) Close() {}
|
||||||
func (r *FullscreenRenderer) Size() (termSize, error) {
|
func (r *FullscreenRenderer) Size() TermSize { return TermSize{} }
|
||||||
return termSize{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *FullscreenRenderer) GetChar() Event { return Event{} }
|
func (r *FullscreenRenderer) GetChar() Event { return Event{} }
|
||||||
func (r *FullscreenRenderer) MaxX() int { return 0 }
|
func (r *FullscreenRenderer) MaxX() int { return 0 }
|
||||||
|
|
|
@ -1092,7 +1092,9 @@ func (w *LightWindow) CFill(fg Color, bg Color, attr Attr, text string) FillRetu
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *LightWindow) FinishFill() {
|
func (w *LightWindow) FinishFill() {
|
||||||
w.MoveAndClear(w.posy, w.posx)
|
if w.posy < w.height {
|
||||||
|
w.MoveAndClear(w.posy, w.posx)
|
||||||
|
}
|
||||||
for y := w.posy + 1; y < w.height; y++ {
|
for y := w.posy + 1; y < w.height; y++ {
|
||||||
w.MoveAndClear(y, 0)
|
w.MoveAndClear(y, 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,10 +110,10 @@ func (r *LightRenderer) getch(nonblock bool) (int, bool) {
|
||||||
return int(b[0]), true
|
return int(b[0]), true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LightRenderer) Size() (termSize, error) {
|
func (r *LightRenderer) Size() TermSize {
|
||||||
ws, err := unix.IoctlGetWinsize(int(r.ttyin.Fd()), unix.TIOCGWINSZ)
|
ws, err := unix.IoctlGetWinsize(int(r.ttyin.Fd()), unix.TIOCGWINSZ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return termSize{}, err
|
return TermSize{}
|
||||||
}
|
}
|
||||||
return termSize{int(ws.Row), int(ws.Col), int(ws.Xpixel), int(ws.Ypixel)}, nil
|
return TermSize{int(ws.Row), int(ws.Col), int(ws.Xpixel), int(ws.Ypixel)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,9 +203,10 @@ func (r *FullscreenRenderer) Refresh() {
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FullscreenRenderer) Size() (termSize, error) {
|
// TODO: Pixel width and height not implemented
|
||||||
|
func (r *FullscreenRenderer) Size() TermSize {
|
||||||
cols, lines := _screen.Size()
|
cols, lines := _screen.Size()
|
||||||
return termSize{lines, cols, 0, 0}, error("Not implemented")
|
return TermSize{lines, cols, 0, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FullscreenRenderer) GetChar() Event {
|
func (r *FullscreenRenderer) GetChar() Event {
|
||||||
|
|
|
@ -473,11 +473,11 @@ func MakeTransparentBorder() BorderStyle {
|
||||||
bottomRight: ' '}
|
bottomRight: ' '}
|
||||||
}
|
}
|
||||||
|
|
||||||
type termSize struct {
|
type TermSize struct {
|
||||||
Lines int
|
Lines int
|
||||||
Columns int
|
Columns int
|
||||||
Width int
|
PxWidth int
|
||||||
Height int
|
PxHeight int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Renderer interface {
|
type Renderer interface {
|
||||||
|
@ -497,7 +497,7 @@ type Renderer interface {
|
||||||
MaxX() int
|
MaxX() int
|
||||||
MaxY() int
|
MaxY() int
|
||||||
|
|
||||||
Size() (termSize, error)
|
Size() TermSize
|
||||||
|
|
||||||
NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window
|
NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user