Skip to content

Commit

Permalink
Add support for quoted searchs for exact matches, for #135
Browse files Browse the repository at this point in the history
  • Loading branch information
ddworken committed Dec 12, 2023
1 parent 1be8e2c commit 434965c
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 11 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Both support the same query format, see the below annotated queries:
|---|---|
| `psql` | Find all commands containing `psql` |
| `psql db.example.com` | Find all commands containing `psql` and `db.example.com` |
| `docker hostname:my-server` | Find all commands containing `docker` that were run on the computer with hostname `my-server` |
| `"docker run" hostname:my-server` | Find all commands containing `docker run` that were run on the computer with hostname `my-server` |
| `nano user:root` | Find all commands containing `nano` that were run as `root` |
| `exit_code:127` | Find all commands that exited with code `127` |
| `service before:2022-02-01` | Find all commands containing `service` run before February 1st 2022 |
Expand Down Expand Up @@ -74,7 +74,6 @@ If you would like to:

</details>


<details>
<summary>TUI key bindings</summary>
The TUI (opened via `Control+R`) supports a number of key bindings:
Expand Down
8 changes: 6 additions & 2 deletions client/lib/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -978,19 +978,23 @@ func tokenize(query string) []string {
return splitEscaped(query, ' ', -1)
}

// TODO: Maybe add support for searching for the backslash character itself?
func splitEscaped(query string, separator rune, maxSplit int) []string {
var token []rune
var tokens []string
splits := 1
runeQuery := []rune(query)
isInQuotedString := false
for i := 0; i < len(runeQuery); i++ {
if (maxSplit < 0 || splits < maxSplit) && runeQuery[i] == separator {
if (maxSplit < 0 || splits < maxSplit) && runeQuery[i] == separator && !isInQuotedString {
tokens = append(tokens, string(token))
token = token[:0]
splits++
} else if runeQuery[i] == '\\' && i+1 < len(runeQuery) {
token = append(token, runeQuery[i], runeQuery[i+1])
i++
token = append(token, runeQuery[i])
} else if runeQuery[i] == '"' {
isInQuotedString = !isInQuotedString
} else {
token = append(token, runeQuery[i])
}
Expand Down
22 changes: 15 additions & 7 deletions client/lib/lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ func TestContainsUnescaped(t *testing.T) {
for _, tc := range testcases {
actual := containsUnescaped(tc.input, tc.token)
if !reflect.DeepEqual(actual, tc.expected) {
t.Fatalf("containsUnescaped failure for containsUnescaped(%#v, %#v), actual=%#v", tc.input, tc.token, actual)
t.Fatalf("failure for containsUnescaped(%#v, %#v), actual=%#v", tc.input, tc.token, actual)
}
}
}
Expand All @@ -274,16 +274,24 @@ func TestSplitEscaped(t *testing.T) {
{"foo bar baz", ' ', 3, []string{"foo", "bar", "baz"}},
{"foo bar baz", ' ', 1, []string{"foo bar baz"}},
{"foo bar baz", ' ', -1, []string{"foo", "bar", "baz"}},
{"foo\\ bar baz", ' ', -1, []string{"foo\\ bar", "baz"}},
{"foo\\bar baz", ' ', -1, []string{"foo\\bar", "baz"}},
{"foo\\bar baz foob", ' ', 2, []string{"foo\\bar", "baz foob"}},
{"foo\\ bar\\ baz", ' ', -1, []string{"foo\\ bar\\ baz"}},
{"foo\\ bar\\ baz", ' ', -1, []string{"foo\\ bar\\ ", "baz"}},
{"foo\\ bar baz", ' ', -1, []string{"foo bar", "baz"}},
{"foo\\bar baz", ' ', -1, []string{"foobar", "baz"}},
{"foo\\bar baz foob", ' ', 2, []string{"foobar", "baz foob"}},
{"foo\\ bar\\ baz", ' ', -1, []string{"foo bar baz"}},
{"foo\\ bar\\ baz", ' ', -1, []string{"foo bar ", "baz"}},
{"\"foo bar\"", ' ', -1, []string{"foo bar"}},
{"\"foo bar\" \" \"", ' ', -1, []string{"foo bar", " "}},
{"\"foo bar baz\" and", ' ', -1, []string{"foo bar baz", "and"}},
{"\"foo bar baz\" and", ' ', -1, []string{"foo bar baz", "and"}},
{"\"foo bar baz", ' ', -1, []string{"foo bar baz"}},
{"\"foo bar baz\\\"\"", ' ', -1, []string{"foo bar baz\""}},
{"cwd:\"foo bar :baz\\\"\"", ':', -1, []string{"cwd", "foo bar :baz\""}},
{"cwd:\"foo bar :baz\\\"\"", ' ', -1, []string{"cwd:foo bar :baz\""}},
}
for _, tc := range testcases {
actual := splitEscaped(tc.input, tc.char, tc.limit)
if !reflect.DeepEqual(actual, tc.expected) {
t.Fatalf("containsUnescaped failure for splitEscaped(%#v, %#v, %#v), actual=%#v", tc.input, string(tc.char), tc.limit, actual)
t.Fatalf("failure for splitEscaped(%#v, %#v, %#v), actual=%#v", tc.input, string(tc.char), tc.limit, actual)
}
}
}

0 comments on commit 434965c

Please sign in to comment.