summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/terminal.go79
-rw-r--r--src/terminal_test.go28
2 files changed, 101 insertions, 6 deletions
diff --git a/src/terminal.go b/src/terminal.go
index b456e123..58c244e8 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -51,7 +51,8 @@ var placeholder *regexp.Regexp
var whiteSuffix *regexp.Regexp
var offsetComponentRegex *regexp.Regexp
var offsetTrimCharsRegex *regexp.Regexp
-var passThroughRegex *regexp.Regexp
+var passThroughBeginRegex *regexp.Regexp
+var passThroughEndTmuxRegex *regexp.Regexp
var ttyin *os.File
const clearCode string = "\x1b[2J"
@@ -74,7 +75,15 @@ func init() {
// * https://sw.kovidgoyal.net/kitty/graphics-protocol
// * https://en.wikipedia.org/wiki/Sixel
// * 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
@@ -2622,6 +2631,67 @@ func (t *Terminal) makeImageBorder(width int, top bool) string {
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) {
maxWidth := t.pwindow.Width()
var ansi *ansiState
@@ -2636,10 +2706,7 @@ Loop:
ansi.lbg = -1
}
- passThroughs := passThroughRegex.FindAllString(line, -1)
- if passThroughs != nil {
- line = passThroughRegex.ReplaceAllString(line, "")
- }
+ passThroughs, line := extractPassThroughs(line)
line = strings.TrimLeft(strings.TrimRight(line, "\r\n"), "\r")
if lineNo >= height || t.pwindow.Y() == height-1 && t.pwindow.X() > 0 {
diff --git a/src/terminal_test.go b/src/terminal_test.go
index 317cd5f9..44da2bcf 100644
--- a/src/terminal_test.go
+++ b/src/terminal_test.go
@@ -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 */
// Item represents one line in fzf UI. Usually it is relative path to files and folders.