fix(history): substring fuzzy search (#74)

closes #73

<img width="1434" height="302" alt="image"
src="https://github.com/user-attachments/assets/87bb8431-40c7-4ee8-ad58-79c4fea6efa7"
/>

I used use prefix match
imagine you have a long command ENOUGH that you used to use (like
image), with fuzzy search + substring, it will always show suggestion
about that command in the list but in the bottom
and I see this very annoying

but now I limit the score from fuzzy search, if the command is too long
(which means fuzzy score is extremely weak), skip it right away

<img width="1296" height="437" alt="image"
src="https://github.com/user-attachments/assets/77d807a2-ddce-4c37-9f5b-a02cd44de325"
/>

it now has substring support
This commit is contained in:
VERSE
2026-07-30 21:11:34 +07:00
committed by GitHub
parent 0049256844
commit 37182f7212
3 changed files with 76 additions and 77 deletions
+2 -2
View File
@@ -335,7 +335,7 @@ func (f *FrecencyStore) QueryLocal(ctx context.Context, cwd, prefix string, limi
var rows *sql.Rows
var err error
if prefix != "" {
rows, err = f.db.QueryContext(ctxTimeout, `SELECT cmd, cwd, count, last_used FROM history_entries WHERE cwd = ? AND cmd LIKE ?`, cwd, prefix+"%")
rows, err = f.db.QueryContext(ctxTimeout, `SELECT cmd, cwd, count, last_used FROM history_entries WHERE cwd = ? AND cmd LIKE ?`, cwd, "%"+prefix+"%")
} else {
rows, err = f.db.QueryContext(ctxTimeout, `SELECT cmd, cwd, count, last_used FROM history_entries WHERE cwd = ?`, cwd)
}
@@ -397,7 +397,7 @@ func (f *FrecencyStore) QueryGlobal(ctx context.Context, prefix string, limit in
var rows *sql.Rows
var err error
if prefix != "" {
rows, err = f.db.QueryContext(ctxTimeout, `SELECT cmd, cwd, count, last_used FROM history_entries WHERE cmd LIKE ?`, prefix+"%")
rows, err = f.db.QueryContext(ctxTimeout, `SELECT cmd, cwd, count, last_used FROM history_entries WHERE cmd LIKE ?`, "%"+prefix+"%")
} else {
rows, err = f.db.QueryContext(ctxTimeout, `SELECT cmd, cwd, count, last_used FROM history_entries`)
}
+49
View File
@@ -145,6 +145,55 @@ func TestFrecencyStore_SQLiteConfigurationAndContext(t *testing.T) {
}
}
func TestFrecencyStore_SubstringMatch(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "history.db")
store, err := NewFrecencyStore(dbPath)
if err != nil {
t.Fatalf("NewFrecencyStore failed: %v", err)
}
defer store.Close()
cwd := "/home/user/project"
_ = store.Record(context.Background(), "sudo chown -R www-data:www-data /var/www/html", cwd, 0)
_ = store.Record(context.Background(), "sudo systemctl restart nginx", cwd, 0)
_ = store.Record(context.Background(), "chmod +x script.sh", cwd, 0)
_ = store.Record(context.Background(), "echo hello world", cwd, 0)
// Test QueryLocal with substring
entries, err := store.QueryLocal(context.Background(), cwd, "cho", 10)
if err != nil {
t.Fatalf("QueryLocal failed: %v", err)
}
if len(entries) != 2 { // should match 'sudo chown...' and 'echo...' (has 'cho')
t.Fatalf("expected 2 entries for 'cho', got %d", len(entries))
}
foundChown := false
for _, e := range entries {
if e.Cmd == "sudo chown -R www-data:www-data /var/www/html" {
foundChown = true
break
}
}
if !foundChown {
t.Errorf("expected 'sudo chown...' to be found with substring 'cho'")
}
// Test QueryGlobal with substring
entriesGlobal, err := store.QueryGlobal(context.Background(), "chown", 10)
if err != nil {
t.Fatalf("QueryGlobal failed: %v", err)
}
if len(entriesGlobal) != 1 {
t.Fatalf("expected 1 entry for 'chown', got %d", len(entriesGlobal))
}
if entriesGlobal[0].Cmd != "sudo chown -R www-data:www-data /var/www/html" {
t.Errorf("expected 'sudo chown...' to be found with substring 'chown', got %s", entriesGlobal[0].Cmd)
}
}
func TestFrecencyStore_NilReceiver(t *testing.T) {
var nilStore *FrecencyStore
if err := nilStore.Record(context.Background(), "cmd", "cwd", 0); err != nil {