diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e18411..3614beb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,19 @@ CHANGELOG 0.43.0 ------ +- Experimental, partial support for Kitty image protocol in the preview window + ```sh + fzf --preview=' + if file --mime-type {} | grep -qF 'image/'; then + # --transfer-mode=memory is the fastest option but if you want fzf to be able + # to redraw the image on terminal resize or on 'change-preview-window', + # you need to use --transfer-mode=stream. + kitty icat --clear --transfer-mode=memory --stdin=no --place=${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}@0x0 {} + else + bat --color=always {} + fi + ' + ``` - `--listen` server can report program state in JSON format (`GET /`) ```sh # fzf server started in "headless" mode diff --git a/src/terminal.go b/src/terminal.go index 3a8c773..07525de 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -51,6 +51,7 @@ var whiteSuffix *regexp.Regexp var offsetComponentRegex *regexp.Regexp var offsetTrimCharsRegex *regexp.Regexp var activeTempFiles []string +var passThroughRegex *regexp.Regexp const clearCode string = "\x1b[2J" @@ -60,6 +61,11 @@ func init() { offsetComponentRegex = regexp.MustCompile(`([+-][0-9]+)|(-?/[1-9][0-9]*)`) offsetTrimCharsRegex = regexp.MustCompile(`[^0-9/+-]`) activeTempFiles = []string{} + + // Parts of the preview output that should be passed through to the terminal + // * https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it + // * https://sw.kovidgoyal.net/kitty/graphics-protocol + passThroughRegex = regexp.MustCompile(`\x1bPtmux;\x1b\x1b.*?[^\x1b]\x1b\\|\x1b_G.*?\x1b\\`) } type jumpMode int @@ -1958,7 +1964,13 @@ func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unc if ansi != nil { ansi.lbg = -1 } - line = strings.TrimRight(line, "\r\n") + + passThroughs := passThroughRegex.FindAllString(line, -1) + if passThroughs != nil { + line = passThroughRegex.ReplaceAllString(line, "") + } + line = strings.TrimLeft(strings.TrimRight(line, "\r\n"), "\r") + if lineNo >= height || t.pwindow.Y() == height-1 && t.pwindow.X() > 0 { t.previewed.filled = true t.previewer.scrollable = true @@ -1971,6 +1983,9 @@ func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unc t.renderPreviewSpinner() t.pwindow.Move(y, x) } + for _, passThrough := range passThroughs { + t.tui.PassThrough(passThrough) + } var fillRet tui.FillReturn prefixWidth := 0 _, _, ansi = extractColor(line, ansi, func(str string, ansi *ansiState) bool { diff --git a/src/tui/dummy.go b/src/tui/dummy.go index 7a02a8a..352e2b0 100644 --- a/src/tui/dummy.go +++ b/src/tui/dummy.go @@ -33,6 +33,7 @@ func (r *FullscreenRenderer) Init() {} func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {} func (r *FullscreenRenderer) Pause(bool) {} func (r *FullscreenRenderer) Resume(bool, bool) {} +func (r *FullscreenRenderer) PassThrough(string) {} func (r *FullscreenRenderer) Clear() {} func (r *FullscreenRenderer) NeedScrollbarRedraw() bool { return false } func (r *FullscreenRenderer) Refresh() {} diff --git a/src/tui/light.go b/src/tui/light.go index cff59c9..cc828fa 100644 --- a/src/tui/light.go +++ b/src/tui/light.go @@ -31,6 +31,11 @@ const consoleDevice string = "/dev/tty" var offsetRegexp *regexp.Regexp = regexp.MustCompile("(.*)\x1b\\[([0-9]+);([0-9]+)R") var offsetRegexpBegin *regexp.Regexp = regexp.MustCompile("^\x1b\\[[0-9]+;[0-9]+R") +func (r *LightRenderer) PassThrough(str string) { + r.queued.WriteString(str) + r.flush() +} + func (r *LightRenderer) stderr(str string) { r.stderrInternal(str, true, "") } diff --git a/src/tui/tcell.go b/src/tui/tcell.go index 8f6806d..0c3d469 100644 --- a/src/tui/tcell.go +++ b/src/tui/tcell.go @@ -98,6 +98,11 @@ const ( AttrClear = Attr(1 << 8) ) +func (r *FullscreenRenderer) PassThrough(str string) { + // No-op + // https://github.com/gdamore/tcell/issues/363#issuecomment-680665073 +} + func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {} func (r *FullscreenRenderer) defaultTheme() *ColorTheme { diff --git a/src/tui/tui.go b/src/tui/tui.go index 9a88c45..4039565 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -474,6 +474,7 @@ type Renderer interface { RefreshWindows(windows []Window) Refresh() Close() + PassThrough(string) NeedScrollbarRedraw() bool GetChar() Event