summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/terminal.go58
-rw-r--r--src/terminal_test.go31
2 files changed, 72 insertions, 17 deletions
diff --git a/src/terminal.go b/src/terminal.go
index e91b3834..2daad273 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -24,7 +24,7 @@ import (
var placeholder *regexp.Regexp
func init() {
- placeholder = regexp.MustCompile("\\\\?(?:{\\+?[0-9,-.]*}|{q})")
+ placeholder = regexp.MustCompile("\\\\?(?:{[+s]*[0-9,-.]*}|{q})")
}
type jumpMode int
@@ -221,6 +221,11 @@ const (
actTop
)
+type placeholderFlags struct {
+ plus bool
+ preserveSpace bool
+}
+
func toActions(types ...actionType) []action {
actions := make([]action, len(types))
for idx, t := range types {
@@ -1130,12 +1135,37 @@ func quoteEntry(entry string) string {
return "'" + strings.Replace(entry, "'", "'\\''", -1) + "'"
}
+func parsePlaceholder(match string) (bool, string, placeholderFlags) {
+ flags := placeholderFlags{}
+
+ if match[0] == '\\' {
+ // Escaped placeholder pattern
+ return true, match[1:], flags
+ }
+
+ skipChars := 1
+ for _, char := range match[1:] {
+ switch char {
+ case '+':
+ flags.plus = true
+ skipChars++
+ case 's':
+ flags.preserveSpace = true
+ skipChars++
+ default:
+ break
+ }
+ }
+
+ matchWithoutFlags := "{" + match[skipChars:]
+
+ return false, matchWithoutFlags, flags
+}
+
func hasPlusFlag(template string) bool {
for _, match := range placeholder.FindAllString(template, -1) {
- if match[0] == '\\' {
- continue
- }
- if match[1] == '+' {
+ _, _, flags := parsePlaceholder(match)
+ if flags.plus {
return true
}
}
@@ -1152,9 +1182,10 @@ func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, fo
selected = []*Item{}
}
return placeholder.ReplaceAllStringFunc(template, func(match string) string {
- // Escaped pattern
- if match[0] == '\\' {
- return match[1:]
+ escaped, match, flags := parsePlaceholder(match)
+
+ if escaped {
+ return match
}
// Current query
@@ -1162,13 +1193,8 @@ func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, fo
return quoteEntry(query)
}
- plusFlag := forcePlus
- if match[1] == '+' {
- match = "{" + match[2:]
- plusFlag = true
- }
items := current
- if plusFlag {
+ if flags.plus || forcePlus {
items = selected
}
@@ -1204,7 +1230,9 @@ func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, fo
str = str[:delims[len(delims)-1][0]]
}
}
- str = strings.TrimSpace(str)
+ if !flags.preserveSpace {
+ str = strings.TrimSpace(str)
+ }
replacements[idx] = quoteEntry(str)
}
return strings.Join(replacements, " ")
diff --git a/src/terminal_test.go b/src/terminal_test.go
index 60f2b1ad..62b20c45 100644
--- a/src/terminal_test.go
+++ b/src/terminal_test.go
@@ -21,6 +21,9 @@ func TestReplacePlaceholder(t *testing.T) {
newItem("foo'bar \x1b[31mbaz\x1b[m"),
newItem("FOO'BAR \x1b[31mBAZ\x1b[m")}
+ delim := "'"
+ var regex *regexp.Regexp
+
var result string
check := func(expected string) {
if result != expected {
@@ -72,6 +75,31 @@ func TestReplacePlaceholder(t *testing.T) {
result = replacePlaceholder("echo {1}/{2}/{-1}/{-2}/{..}/{n.t}/\\{}/\\{1}/\\{q}/{3}", true, Delimiter{}, true, "query", items2)
check("echo 'foo'\\''bar' 'FOO'\\''BAR'/'baz' 'BAZ'/'baz' 'BAZ'/'foo'\\''bar' 'FOO'\\''BAR'/'foo'\\''bar baz' 'FOO'\\''BAR BAZ'/{n.t}/{}/{1}/{q}/'' ''")
+ // Whitespace preserving flag with "'" delimiter
+ result = replacePlaceholder("echo {s1}", true, Delimiter{str: &delim}, false, "query", items1)
+ check("echo ' foo'")
+
+ result = replacePlaceholder("echo {s2}", true, Delimiter{str: &delim}, false, "query", items1)
+ check("echo 'bar baz'")
+
+ result = replacePlaceholder("echo {s}", true, Delimiter{str: &delim}, false, "query", items1)
+ check("echo ' foo'\\''bar baz'")
+
+ result = replacePlaceholder("echo {s..}", true, Delimiter{str: &delim}, false, "query", items1)
+ check("echo ' foo'\\''bar baz'")
+
+ // Whitespace preserving flag with regex delimiter
+ regex = regexp.MustCompile("\\w+")
+
+ result = replacePlaceholder("echo {s1}", true, Delimiter{regex: regex}, false, "query", items1)
+ check("echo ' '")
+
+ result = replacePlaceholder("echo {s2}", true, Delimiter{regex: regex}, false, "query", items1)
+ check("echo ''\\'''")
+
+ result = replacePlaceholder("echo {s3}", true, Delimiter{regex: regex}, false, "query", items1)
+ check("echo ' '")
+
// No match
result = replacePlaceholder("echo {}/{+}", true, Delimiter{}, false, "query", []*Item{nil, nil})
check("echo /")
@@ -81,12 +109,11 @@ func TestReplacePlaceholder(t *testing.T) {
check("echo /' foo'\\''bar baz'")
// String delimiter
- delim := "'"
result = replacePlaceholder("echo {}/{1}/{2}", true, Delimiter{str: &delim}, false, "query", items1)
check("echo ' foo'\\''bar baz'/'foo'/'bar baz'")
// Regex delimiter
- regex := regexp.MustCompile("[oa]+")
+ regex = regexp.MustCompile("[oa]+")
// foo'bar baz
result = replacePlaceholder("echo {}/{1}/{3}/{2..3}", true, Delimiter{regex: regex}, false, "query", items1)
check("echo ' foo'\\''bar baz'/'f'/'r b'/''\\''bar b'")