From b4057529a115b1cdc41d73bd2666491fb6a50d02 Mon Sep 17 00:00:00 2001 From: Puneet Dixit <236133619+puneetdixit200@users.noreply.github.com> Date: Fri, 22 May 2026 07:28:35 +0530 Subject: [PATCH] Accept existing paths in interactive query --- CHANGELOG.md | 1 + src/cmd/query.rs | 36 +++++++++++++++++++++++++++++++++++- tests/query.rs | 20 ++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/query.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 37a8226..029dbe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- `zoxide query --interactive` now accepts a single existing path directly. - PowerShell: use fully qualified names when invoking cmdlets. - Bash/Fish/POSIX/Zsh: resolve symlinks on Windows. diff --git a/src/cmd/query.rs b/src/cmd/query.rs index 6539c2e..211b96f 100644 --- a/src/cmd/query.rs +++ b/src/cmd/query.rs @@ -1,4 +1,5 @@ use std::io::{self, Write}; +use std::path::Path; use anyhow::{Context, Result}; @@ -18,17 +19,50 @@ impl Run for Query { impl Query { fn query(&self, db: &mut Database) -> Result<()> { let now = util::current_time()?; - let mut stream = self.get_stream(db, now)?; if self.interactive { + if let Some(path) = self.existing_path()? { + println!("{path}"); + return Ok(()); + } + + let mut stream = self.get_stream(db, now)?; self.query_interactive(&mut stream, now) } else if self.list { + let mut stream = self.get_stream(db, now)?; self.query_list(&mut stream, now) } else { + let mut stream = self.get_stream(db, now)?; self.query_first(&mut stream, now) } } + fn existing_path(&self) -> Result> { + if self.score || self.keywords.len() != 1 { + return Ok(None); + } + + let path = Path::new(&self.keywords[0]); + if !path.is_dir() { + return Ok(None); + } + + let path = util::resolve_path(path)?; + let path = util::path_to_str(&path)?; + + if Some(path) == self.exclude.as_deref() { + return Ok(None); + } + + if let Some(base_dir) = &self.base_dir + && !Path::new(path).starts_with(base_dir) + { + return Ok(None); + } + + Ok(Some(path.to_owned())) + } + fn query_interactive(&self, stream: &mut Stream, now: Epoch) -> Result<()> { let mut fzf = Self::get_fzf()?; let selection = loop { diff --git a/tests/query.rs b/tests/query.rs new file mode 100644 index 0000000..7efdd28 --- /dev/null +++ b/tests/query.rs @@ -0,0 +1,20 @@ +use assert_cmd::Command; + +#[test] +fn interactive_query_accepts_existing_path() { + let data_dir = tempfile::tempdir().unwrap(); + let target_parent = tempfile::tempdir().unwrap(); + let target = target_parent.path().join("project"); + std::fs::create_dir(&target).unwrap(); + + let expected = target.to_string_lossy(); + + Command::cargo_bin("zoxide") + .unwrap() + .env("_ZO_DATA_DIR", data_dir.path()) + .args(["query", "--interactive", "--", expected.as_ref()]) + .assert() + .success() + .stdout(format!("{expected}\n")) + .stderr(""); +}