From e86f7bf382ee3987e7b63566013cb748e097e7d9 Mon Sep 17 00:00:00 2001 From: David Dworken Date: Sun, 7 Jan 2024 18:56:30 -0800 Subject: [PATCH] Add support for quotes around colons when searching (#162) --- client/client_test.go | 22 +++++++++++++- client/lib/lib.go | 3 ++ client/lib/lib_test.go | 8 +++-- .../TestTui-ExportWithEvenMoreEntries | 6 ++++ .../testdata/TestTui-SearchColonDoubleQuoted | 27 +++++++++++++++++ client/testdata/TestTui-SearchColonError | 29 +++++++++++++++++++ client/testdata/TestTui-SearchColonEscaped | 27 +++++++++++++++++ 7 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 client/testdata/TestTui-ExportWithEvenMoreEntries create mode 100644 client/testdata/TestTui-SearchColonDoubleQuoted create mode 100644 client/testdata/TestTui-SearchColonError create mode 100644 client/testdata/TestTui-SearchColonEscaped diff --git a/client/client_test.go b/client/client_test.go index 880d928..9ad7ad6 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -1923,7 +1923,27 @@ func testTui_search(t *testing.T, onlineStatus OnlineStatus) { })) testutils.CompareGoldens(t, out, "TestTui-SearchBackslash") - // TODO: Add a test for the behavior when quoting something containing a colon + // Add another entry for testing quoting a colon + require.NoError(t, db.Create(testutils.MakeFakeHistoryEntry("foo:bar")).Error) + out = tester.RunInteractiveShell(t, `hishtory export`) + testutils.CompareGoldens(t, out, "TestTui-ExportWithEvenMoreEntries") + + // And check that we can quote colons + out = stripTuiCommandPrefix(t, captureTerminalOutput(t, tester, []string{ + "hishtory SPACE tquery ENTER", + "foo:bar", + })) + testutils.CompareGoldens(t, out, "TestTui-SearchColonError") + out = stripTuiCommandPrefix(t, captureTerminalOutput(t, tester, []string{ + "hishtory SPACE tquery ENTER", + "foo\\\\:bar", + })) + testutils.CompareGoldens(t, out, "TestTui-SearchColonEscaped") + out = stripTuiCommandPrefix(t, captureTerminalOutput(t, tester, []string{ + "hishtory SPACE tquery ENTER", + "'\"'foo:bar'\"'", + })) + testutils.CompareGoldens(t, out, "TestTui-SearchColonDoubleQuoted") } func testTui_general(t *testing.T, onlineStatus OnlineStatus) { diff --git a/client/lib/lib.go b/client/lib/lib.go index b2c69cb..6c85e3f 100644 --- a/client/lib/lib.go +++ b/client/lib/lib.go @@ -1005,6 +1005,9 @@ func splitEscaped(query string, separator rune, maxSplit int) []string { } else if runeQuery[i] == '\'' && !isInDoubleQuotedString && !heuristicIgnoreUnclosedQuote(isInSingleQuotedString, '\'', runeQuery, i) { isInSingleQuotedString = !isInSingleQuotedString } else { + if (isInSingleQuotedString || isInDoubleQuotedString) && separator == ' ' && runeQuery[i] == ':' { + token = append(token, '\\') + } token = append(token, runeQuery[i]) } } diff --git a/client/lib/lib_test.go b/client/lib/lib_test.go index dbc644b..68f91e3 100644 --- a/client/lib/lib_test.go +++ b/client/lib/lib_test.go @@ -288,7 +288,7 @@ func TestSplitEscaped(t *testing.T) { {"'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'"}}, + {"cwd:'foo bar :baz\\''", ' ', -1, []string{"cwd:foo bar \\:baz'"}}, // Tests for double quotes {"\"foo bar\"", ' ', -1, []string{"foo bar"}}, {"\"foo bar\" \" \"", ' ', -1, []string{"foo bar", " "}}, @@ -296,7 +296,7 @@ func TestSplitEscaped(t *testing.T) { {"\"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\""}}, + {"cwd:\"foo bar :baz\\\"\"", ' ', -1, []string{"cwd:foo bar \\:baz\""}}, // Tests for complex quotes {"\"foo'bar\"", ' ', -1, []string{"foo'bar"}}, {"'foo\"bar'", ' ', -1, []string{"foo\"bar"}}, @@ -318,6 +318,10 @@ func TestSplitEscaped(t *testing.T) { {"foo:bar", ' ', -1, []string{"foo:bar"}}, {"foo\\:bar", ':', -1, []string{"foo\\:bar"}}, {"foo\\:bar", ' ', -1, []string{"foo\\:bar"}}, + // Tests for quoting colons + {"foo:bar", ' ', -1, []string{"foo:bar"}}, + {"'foo:bar'", ' ', -1, []string{"foo\\:bar"}}, + {"\"foo:bar\"", ' ', -1, []string{"foo\\:bar"}}, } for _, tc := range testcases { actual := splitEscaped(tc.input, tc.char, tc.limit) diff --git a/client/testdata/TestTui-ExportWithEvenMoreEntries b/client/testdata/TestTui-ExportWithEvenMoreEntries new file mode 100644 index 0000000..6309ccc --- /dev/null +++ b/client/testdata/TestTui-ExportWithEvenMoreEntries @@ -0,0 +1,6 @@ +ls ~/ +echo 'aaaaaa bbbb' +for i in 1 +for i in 2 +i for in +foo:bar diff --git a/client/testdata/TestTui-SearchColonDoubleQuoted b/client/testdata/TestTui-SearchColonDoubleQuoted new file mode 100644 index 0000000..abdc1d5 --- /dev/null +++ b/client/testdata/TestTui-SearchColonDoubleQuoted @@ -0,0 +1,27 @@ +Search Query: > "foo:bar" + +┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Hostname CWD Timestamp Runtime Exit Code Command │ +│────────────────────────────────────────────────────────────────────────────────────────────────────────│ +│ localhost /tmp/ Oct 17 2022 21:43:41 PDT 3s 2 foo:bar │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +hiSHtory: Search your shell history • ctrl+h help \ No newline at end of file diff --git a/client/testdata/TestTui-SearchColonError b/client/testdata/TestTui-SearchColonError new file mode 100644 index 0000000..d03ed44 --- /dev/null +++ b/client/testdata/TestTui-SearchColonError @@ -0,0 +1,29 @@ +Warning: failed to search: search query contains unknown search atom 'foo' that doesn't match any column names + +Search Query: > foo:bar + +┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Hostname CWD Timestamp Runtime Exit Code Command │ +│────────────────────────────────────────────────────────────────────────────────────────────────────────│ +│ localhost /tmp/ Oct 17 2022 21:43:41 PDT 3s 2 foo:bar │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +hiSHtory: Search your shell history • ctrl+h help \ No newline at end of file diff --git a/client/testdata/TestTui-SearchColonEscaped b/client/testdata/TestTui-SearchColonEscaped new file mode 100644 index 0000000..590beff --- /dev/null +++ b/client/testdata/TestTui-SearchColonEscaped @@ -0,0 +1,27 @@ +Search Query: > foo\:bar + +┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Hostname CWD Timestamp Runtime Exit Code Command │ +│────────────────────────────────────────────────────────────────────────────────────────────────────────│ +│ localhost /tmp/ Oct 17 2022 21:43:41 PDT 3s 2 foo:bar │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +hiSHtory: Search your shell history • ctrl+h help \ No newline at end of file