tenseleyflow/gump / 832aa68

Browse files

add fuzzy CWD matching before database lookup

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
832aa68f40ff43b2102cc24530e9d67367479759
Parents
ef9f6f0
Tree
5090072

5 changed files

StatusFile+-
M README.md 17 1
M src/cli.rs 4 0
M src/cmd/init.rs 43 8
M src/cmd/query.rs 44 2
M src/main.rs 1 1
README.mdmodified
@@ -44,14 +44,30 @@ Restart shell or source the file.
4444
 
4545
 ## Usage
4646
 
47
+Just type where you want to go:
48
+
49
+```bash
50
+projects           # jumps to ~/code/projects
51
+doc                # jumps to ./Documents (fuzzy CWD match)
52
+gmp                # jumps to ~/code/gump (fuzzy database match)
53
+conf fish          # jumps to ~/.config/fish (multi-term)
54
+```
55
+
56
+Or use the `g` command:
57
+
4758
 ```bash
4859
 g foo              # jump to best match for "foo"
49
-g foo bar          # jump to path matching "foo" then "bar"
5060
 g                  # go home
5161
 g -                # go back
5262
 gi foo             # interactive selection with fzf
5363
 ```
5464
 
65
+Resolution order:
66
+1. Existing commands/aliases/builtins
67
+2. Exact directory in CWD
68
+3. Fuzzy match against CWD contents
69
+4. Fuzzy match against database
70
+
5571
 Directories are learned automatically as you `cd` around.
5672
 
5773
 ## Commands
src/cli.rsmodified
@@ -32,6 +32,10 @@ pub enum Commands {
3232
         /// Show all matches instead of just the best
3333
         #[arg(short, long)]
3434
         all: bool,
35
+
36
+        /// Match against current directory contents instead of database
37
+        #[arg(long)]
38
+        cwd: bool,
3539
     },
3640
 
3741
     /// Remove a directory from the database
src/cmd/init.rsmodified
@@ -64,7 +64,11 @@ fi
6464
         builtin cd - && __gump_hook
6565
     else
6666
         local result
67
-        result=$(command gump query -- "$@")
67
+        # Try CWD first, then database
68
+        result=$(command gump query --cwd -- "$@" 2>/dev/null)
69
+        if [[ -z "$result" ]]; then
70
+            result=$(command gump query -- "$@" 2>/dev/null)
71
+        fi
6872
         if [[ -n "$result" ]]; then
6973
             builtin cd -- "$result" && __gump_hook
7074
         else
@@ -91,14 +95,21 @@ fi
9195
     output.push_str(r#"
9296
 # No-prefix directory jumping
9397
 command_not_found_handle() {
94
-    # Check if it's a local directory first
98
+    # Check if it's a local directory first (exact match)
9599
     if [[ -d "$1" ]]; then
96100
         builtin cd -- "$1" && __gump_hook
97101
         return 0
98102
     fi
99103
 
100
-    # Query gump database
104
+    # Fuzzy match against current directory contents
101105
     local result
106
+    result=$(command gump query --cwd -- "$@" 2>/dev/null)
107
+    if [[ -n "$result" ]]; then
108
+        builtin cd -- "$result" && __gump_hook
109
+        return 0
110
+    fi
111
+
112
+    # Query gump database
102113
     result=$(command gump query -- "$@" 2>/dev/null)
103114
     if [[ -n "$result" ]]; then
104115
         builtin cd -- "$result" && __gump_hook
@@ -153,7 +164,11 @@ __gump_hook() {
153164
         builtin cd -
154165
     else
155166
         local result
156
-        result=$(command gump query -- "$@")
167
+        # Try CWD first, then database
168
+        result=$(command gump query --cwd -- "$@" 2>/dev/null)
169
+        if [[ -z "$result" ]]; then
170
+            result=$(command gump query -- "$@" 2>/dev/null)
171
+        fi
157172
         if [[ -n "$result" ]]; then
158173
             builtin cd -- "$result"
159174
         else
@@ -202,15 +217,23 @@ __gump_accept_line() {
202217
         return
203218
     fi
204219
 
205
-    # Check if it's a local directory
220
+    # Check if it's a local directory (exact match)
206221
     if [[ -d "$first_word" ]]; then
207222
         BUFFER="cd ${(q)first_word}"
208223
         zle .accept-line
209224
         return
210225
     fi
211226
 
212
-    # Query gump database
227
+    # Fuzzy match against current directory contents
213228
     local result
229
+    result=$(command gump query --cwd -- $=BUFFER 2>/dev/null)
230
+    if [[ -n "$result" ]]; then
231
+        BUFFER="cd ${(q)result}"
232
+        zle .accept-line
233
+        return
234
+    fi
235
+
236
+    # Query gump database
214237
     result=$(command gump query -- $=BUFFER 2>/dev/null)
215238
     if [[ -n "$result" ]]; then
216239
         BUFFER="cd ${(q)result}"
@@ -259,7 +282,11 @@ function {cmd} --description "Jump to a directory"
259282
     else if test (count $argv) -eq 1 -a "$argv[1]" = "-"
260283
         cd -
261284
     else
262
-        set -l result (command gump query -- $argv)
285
+        # Try CWD first, then database
286
+        set -l result (command gump query --cwd -- $argv 2>/dev/null)
287
+        if test -z "$result"
288
+            set result (command gump query -- $argv 2>/dev/null)
289
+        end
263290
         if test -n "$result"
264291
             cd $result
265292
         else
@@ -306,13 +333,21 @@ function __gump_execute
306333
         return
307334
     end
308335
 
309
-    # Check if it's a local directory
336
+    # Check if it's a local directory (exact match)
310337
     if test -d "$first_word"
311338
         commandline -r "cd $first_word"
312339
         commandline -f execute
313340
         return
314341
     end
315342
 
343
+    # Fuzzy match against current directory contents
344
+    set -l result (command gump query --cwd -- $cmd 2>/dev/null)
345
+    if test -n "$result"
346
+        commandline -r "cd \"$result\""
347
+        commandline -f execute
348
+        return
349
+    end
350
+
316351
     # Query gump database
317352
     set -l result (command gump query -- $cmd 2>/dev/null)
318353
     if test -n "$result"
src/cmd/query.rsmodified
@@ -1,3 +1,5 @@
1
+use std::path::PathBuf;
2
+
13
 use crate::db::Database;
24
 use crate::matcher::Matcher;
35
 
@@ -7,10 +9,15 @@ use super::Result;
79
 ///
810
 /// Returns the best match by default, or all matches with --all.
911
 /// Matches are ranked by combined frecency + fuzzy score.
10
-pub fn run(terms: Vec<String>, show_score: bool, show_all: bool) -> Result<()> {
11
-    let db = Database::open()?;
12
+pub fn run(terms: Vec<String>, show_score: bool, show_all: bool, cwd_mode: bool) -> Result<()> {
1213
     let mut matcher = Matcher::new();
1314
 
15
+    if cwd_mode {
16
+        return run_cwd_mode(&mut matcher, &terms, show_all);
17
+    }
18
+
19
+    let db = Database::open()?;
20
+
1421
     // Collect paths with their frecency scores
1522
     let paths = db.entries().map(|(path, entry)| (path.as_path(), entry.frecency()));
1623
 
@@ -42,3 +49,38 @@ pub fn run(terms: Vec<String>, show_score: bool, show_all: bool) -> Result<()> {
4249
 
4350
     Ok(())
4451
 }
52
+
53
+/// Match against directories in the current working directory.
54
+fn run_cwd_mode(matcher: &mut Matcher, terms: &[String], show_all: bool) -> Result<()> {
55
+    let cwd = std::env::current_dir()?;
56
+
57
+    // Read directory entries, filter to directories only
58
+    let dirs: Vec<PathBuf> = std::fs::read_dir(&cwd)?
59
+        .filter_map(|entry| entry.ok())
60
+        .filter(|entry| entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false))
61
+        .map(|entry| entry.path())
62
+        .collect();
63
+
64
+    if dirs.is_empty() {
65
+        std::process::exit(1);
66
+    }
67
+
68
+    // Use equal frecency (1.0) for all CWD entries - fuzzy score determines ranking
69
+    let paths = dirs.iter().map(|p| (p.as_path(), 1.0));
70
+
71
+    let matches = matcher.rank(paths, terms);
72
+
73
+    if matches.is_empty() {
74
+        std::process::exit(1);
75
+    }
76
+
77
+    if show_all {
78
+        for m in &matches {
79
+            println!("{}", m.path.display());
80
+        }
81
+    } else {
82
+        println!("{}", matches[0].path.display());
83
+    }
84
+
85
+    Ok(())
86
+}
src/main.rsmodified
@@ -11,7 +11,7 @@ fn main() {
1111
 
1212
     let result = match cli.command {
1313
         Commands::Add { path } => cmd::add::run(path),
14
-        Commands::Query { terms, score, all } => cmd::query::run(terms, score, all),
14
+        Commands::Query { terms, score, all, cwd } => cmd::query::run(terms, score, all, cwd),
1515
         Commands::Remove { path } => cmd::remove::run(path),
1616
         Commands::List { score } => cmd::list::run(score),
1717
         Commands::Clean => cmd::clean::run(),