mirror of
https://github.com/junegunn/fzf.git
synced 2025-08-09 00:22:02 -07:00
@@ -6,6 +6,7 @@ CHANGELOG
|
|||||||
- Built-in walker improvements
|
- Built-in walker improvements
|
||||||
- `--walker-root` can take multiple directory arguments. e.g. `--walker-root include src lib`
|
- `--walker-root` can take multiple directory arguments. e.g. `--walker-root include src lib`
|
||||||
- `--walker-skip` can handle multi-component patterns. e.g. `--walker-skip target/build`
|
- `--walker-skip` can handle multi-component patterns. e.g. `--walker-skip target/build`
|
||||||
|
- Removed long processing delay when displaying images in the preview window
|
||||||
- `FZF_PREVIEW_*` environment variables are exported to all child processes (#4098)
|
- `FZF_PREVIEW_*` environment variables are exported to all child processes (#4098)
|
||||||
- Bug fixes in fish scripts
|
- Bug fixes in fish scripts
|
||||||
|
|
||||||
|
@@ -51,7 +51,8 @@ var placeholder *regexp.Regexp
|
|||||||
var whiteSuffix *regexp.Regexp
|
var whiteSuffix *regexp.Regexp
|
||||||
var offsetComponentRegex *regexp.Regexp
|
var offsetComponentRegex *regexp.Regexp
|
||||||
var offsetTrimCharsRegex *regexp.Regexp
|
var offsetTrimCharsRegex *regexp.Regexp
|
||||||
var passThroughRegex *regexp.Regexp
|
var passThroughBeginRegex *regexp.Regexp
|
||||||
|
var passThroughEndTmuxRegex *regexp.Regexp
|
||||||
var ttyin *os.File
|
var ttyin *os.File
|
||||||
|
|
||||||
const clearCode string = "\x1b[2J"
|
const clearCode string = "\x1b[2J"
|
||||||
@@ -74,7 +75,15 @@ func init() {
|
|||||||
// * https://sw.kovidgoyal.net/kitty/graphics-protocol
|
// * https://sw.kovidgoyal.net/kitty/graphics-protocol
|
||||||
// * https://en.wikipedia.org/wiki/Sixel
|
// * https://en.wikipedia.org/wiki/Sixel
|
||||||
// * https://iterm2.com/documentation-images.html
|
// * https://iterm2.com/documentation-images.html
|
||||||
passThroughRegex = regexp.MustCompile(`\x1bPtmux;\x1b\x1b.*?[^\x1b]\x1b\\|\x1b(_G|P[0-9;]*q).*?\x1b\\\r?|\x1b]1337;.*?(\a|\x1b\\)`)
|
/*
|
||||||
|
passThroughRegex = regexp.MustCompile(`
|
||||||
|
\x1bPtmux;\x1b\x1b .*? [^\x1b]\x1b\\
|
||||||
|
| \x1b(_G|P[0-9;]*q) .*? \x1b\\\r?
|
||||||
|
| \x1b]1337; .*? (\a|\x1b\\)
|
||||||
|
`)
|
||||||
|
*/
|
||||||
|
passThroughBeginRegex = regexp.MustCompile(`\x1bPtmux;\x1b\x1b|\x1b(_G|P[0-9;]*q)|\x1b]1337;`)
|
||||||
|
passThroughEndTmuxRegex = regexp.MustCompile(`[^\x1b]\x1b\\`)
|
||||||
}
|
}
|
||||||
|
|
||||||
type jumpMode int
|
type jumpMode int
|
||||||
@@ -2622,6 +2631,67 @@ func (t *Terminal) makeImageBorder(width int, top bool) string {
|
|||||||
return v + strings.Repeat(" ", repeat) + v
|
return v + strings.Repeat(" ", repeat) + v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findPassThrough(line string) []int {
|
||||||
|
loc := passThroughBeginRegex.FindStringIndex(line)
|
||||||
|
if loc == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rest := line[loc[0]:]
|
||||||
|
after := line[loc[1]:]
|
||||||
|
if strings.HasPrefix(rest, "\x1bPtmux") { // Tmux
|
||||||
|
eloc := passThroughEndTmuxRegex.FindStringIndex(after)
|
||||||
|
if eloc == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []int{loc[0], loc[1] + eloc[1]}
|
||||||
|
} else if strings.HasPrefix(rest, "\x1b]1337;") { // iTerm2
|
||||||
|
index := loc[1]
|
||||||
|
for {
|
||||||
|
after := line[index:]
|
||||||
|
pos := strings.IndexAny(after, "\x1b\a")
|
||||||
|
if pos < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if after[pos] == '\a' {
|
||||||
|
return []int{loc[0], index + pos + 1}
|
||||||
|
}
|
||||||
|
if pos < len(after)-1 && after[pos+1] == '\\' {
|
||||||
|
return []int{loc[0], index + pos + 2}
|
||||||
|
}
|
||||||
|
index += pos + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Kitty
|
||||||
|
pos := strings.Index(after, "\x1b\\")
|
||||||
|
if pos < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if pos < len(after)-2 && after[pos+2] == '\r' {
|
||||||
|
return []int{loc[0], loc[1] + pos + 3}
|
||||||
|
}
|
||||||
|
return []int{loc[0], loc[1] + pos + 2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractPassThroughs(line string) ([]string, string) {
|
||||||
|
passThroughs := []string{}
|
||||||
|
transformed := ""
|
||||||
|
index := 0
|
||||||
|
for {
|
||||||
|
rest := line[index:]
|
||||||
|
loc := findPassThrough(rest)
|
||||||
|
if loc == nil {
|
||||||
|
transformed += rest
|
||||||
|
break
|
||||||
|
}
|
||||||
|
passThroughs = append(passThroughs, rest[loc[0]:loc[1]])
|
||||||
|
transformed += line[index : index+loc[0]]
|
||||||
|
index += loc[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return passThroughs, transformed
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
@@ -2636,10 +2706,7 @@ Loop:
|
|||||||
ansi.lbg = -1
|
ansi.lbg = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
passThroughs := passThroughRegex.FindAllString(line, -1)
|
passThroughs, line := extractPassThroughs(line)
|
||||||
if passThroughs != nil {
|
|
||||||
line = passThroughRegex.ReplaceAllString(line, "")
|
|
||||||
}
|
|
||||||
line = strings.TrimLeft(strings.TrimRight(line, "\r\n"), "\r")
|
line = strings.TrimLeft(strings.TrimRight(line, "\r\n"), "\r")
|
||||||
|
|
||||||
if lineNo >= height || t.pwindow.Y() == height-1 && t.pwindow.X() > 0 {
|
if lineNo >= height || t.pwindow.Y() == height-1 && t.pwindow.X() > 0 {
|
||||||
|
@@ -507,6 +507,34 @@ func TestParsePlaceholder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExtractPassthroughs(t *testing.T) {
|
||||||
|
for _, middle := range []string{
|
||||||
|
"\x1bPtmux;\x1b\x1bbar\x1b\\",
|
||||||
|
"\x1bPtmux;\x1b\x1bbar\x1bbar\x1b\\",
|
||||||
|
"\x1b]1337;bar\x1b\\",
|
||||||
|
"\x1b]1337;bar\x1bbar\x1b\\",
|
||||||
|
"\x1b]1337;bar\a",
|
||||||
|
"\x1b_Ga=T,f=32,s=1258,v=1295,c=74,r=35,m=1\x1b\\",
|
||||||
|
"\x1b_Ga=T,f=32,s=1258,v=1295,c=74,r=35,m=1\x1b\\\r",
|
||||||
|
"\x1b_Ga=T,f=32,s=1258,v=1295,c=74,r=35,m=1\x1bbar\x1b\\\r",
|
||||||
|
"\x1b_Gm=1;AAAAAAAAA=\x1b\\",
|
||||||
|
"\x1b_Gm=1;AAAAAAAAA=\x1b\\\r",
|
||||||
|
"\x1b_Gm=1;\x1bAAAAAAAAA=\x1b\\\r",
|
||||||
|
} {
|
||||||
|
line := "foo" + middle + "baz"
|
||||||
|
loc := findPassThrough(line)
|
||||||
|
if loc == nil || line[0:loc[0]] != "foo" || line[loc[1]:] != "baz" {
|
||||||
|
t.Error("failed to find passthrough")
|
||||||
|
}
|
||||||
|
garbage := "\x1bPtmux;\x1b]1337;\x1b_Ga=\x1b]1337;bar\x1b."
|
||||||
|
line = strings.Repeat("foo"+middle+middle+"baz", 3) + garbage
|
||||||
|
passthroughs, result := extractPassThroughs(line)
|
||||||
|
if result != "foobazfoobazfoobaz"+garbage || len(passthroughs) != 6 {
|
||||||
|
t.Error("failed to extract passthroughs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* utilities section */
|
/* utilities section */
|
||||||
|
|
||||||
// Item represents one line in fzf UI. Usually it is relative path to files and folders.
|
// Item represents one line in fzf UI. Usually it is relative path to files and folders.
|
||||||
|
Reference in New Issue
Block a user