first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
@@ -1,19 +1,19 @@
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use std::fs::DirEntry;
use std::sync::Arc;
use galaxy_util::path::HOME_DIR_ENV_VAR_PREFIX;
use async_trait::async_trait;
use itertools::{iproduct, Itertools};
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use typed_path::{TypedPath, TypedPathBuf};
use warp_command_signatures::{IconType, PathSuggestionType};
use galaxy_util::path::{ShellFamily, HOME_DIR_ENV_VAR_PREFIX};
use crate::completer::suggest::Priority;
use crate::completer::{
context::PathCompletionContext,
matchers::MatchStrategy,
suggest::{MatchedSuggestion, Suggestion, SuggestionType},
};
use crate::completer::context::{PathCompletionContext, PathSeparators};
use crate::completer::matchers::MatchStrategy;
use crate::completer::suggest::{MatchedSuggestion, Priority, Suggestion, SuggestionType};
use crate::parsers::ParsedToken;
/// TODO(CORE-3074): This only applies to Unix.
@@ -136,6 +136,127 @@ pub(crate) async fn sorted_directories_relative_to(
.collect()
}
/// Like `sorted_directories_relative_to`, but iterates `$CDPATH` in shell
/// order (empty/`.` entry = pwd at that position; pwd appended as fallback if
/// no such entry) so completions surface in the order `cd` would resolve them.
pub(crate) async fn sorted_cd_directories(
path: &ParsedToken,
matcher: MatchStrategy,
ctx: &dyn PathCompletionContext,
) -> Vec<MatchedSuggestion> {
if !is_cdpath_eligible_token(path.as_str()) {
return sorted_directories_relative_to(path, matcher, ctx).await;
}
let Some(cdpath) = ctx.cdpath() else {
return sorted_directories_relative_to(path, matcher, ctx).await;
};
let mut results: Vec<MatchedSuggestion> = Vec::new();
let mut seen: HashSet<String> = HashSet::new();
let mut pwd_searched = false;
let push_unique = |suggestions: Vec<MatchedSuggestion>,
results: &mut Vec<MatchedSuggestion>,
seen: &mut HashSet<String>| {
for s in suggestions {
if seen.insert(s.suggestion.display.to_string()) {
results.push(s);
}
}
};
for entry in cdpath.split(':') {
if entry.is_empty() || entry == "." {
if pwd_searched {
continue;
}
let pwd = sorted_directories_relative_to(path, matcher, ctx).await;
push_unique(pwd, &mut results, &mut seen);
pwd_searched = true;
} else {
let override_ctx = CdpathOverrideContext {
inner: ctx,
cdpath_pwd: resolve_cdpath_entry(entry, ctx),
};
let extra = sorted_directories_relative_to(path, matcher, &override_ctx).await;
push_unique(extra, &mut results, &mut seen);
}
}
// Shell falls back to pwd when no `$CDPATH` entry matches. If no `.`/empty
// entry positioned pwd already, append pwd matches now.
if !pwd_searched {
let pwd = sorted_directories_relative_to(path, matcher, ctx).await;
push_unique(pwd, &mut results, &mut seen);
}
results
}
/// Tilde-expand a `$CDPATH` entry against the shell's home dir, then resolve
/// relative entries against the shell's pwd so `cd` matches shell behavior.
fn resolve_cdpath_entry(entry: &str, ctx: &dyn PathCompletionContext) -> TypedPathBuf {
let expanded = if entry == "~" {
ctx.home_directory().unwrap_or_default().to_owned()
} else if let Some(rest) = entry.strip_prefix("~/") {
format!("{}/{}", ctx.home_directory().unwrap_or_default(), rest)
} else {
entry.to_owned()
};
let resolved = TypedPathBuf::from(expanded.as_str());
if resolved.is_absolute() {
resolved
} else {
ctx.pwd().join(expanded)
}
}
fn is_cdpath_eligible_token(token: &str) -> bool {
!(token.starts_with('/')
|| token.starts_with('~')
|| token.starts_with("./")
|| token.starts_with("../")
|| token == "."
|| token == "..")
}
/// Wraps a `PathCompletionContext` and overrides only `pwd()` so we can reuse
/// the existing engine to list directories under a `$CDPATH` entry.
struct CdpathOverrideContext<'a> {
inner: &'a dyn PathCompletionContext,
cdpath_pwd: TypedPathBuf,
}
#[async_trait]
impl<'a> PathCompletionContext for CdpathOverrideContext<'a> {
async fn list_directory_entries(&self, directory: TypedPathBuf) -> Arc<Vec<EngineDirEntry>> {
self.inner.list_directory_entries(directory).await
}
fn home_directory(&self) -> Option<&str> {
self.inner.home_directory()
}
fn cdpath(&self) -> Option<&str> {
// Avoid recursing — the outer call already iterates entries.
None
}
fn shell_family(&self) -> ShellFamily {
self.inner.shell_family()
}
fn pwd(&self) -> TypedPath<'_> {
self.cdpath_pwd.to_path()
}
fn path_separators(&self) -> PathSeparators {
self.inner.path_separators()
}
}
pub async fn sorted_paths_relative_to(
path: &ParsedToken,
matcher: MatchStrategy,
@@ -307,5 +428,5 @@ impl SplitPath {
}
#[cfg(test)]
#[path = "path_test.rs"]
#[path = "path_tests.rs"]
mod tests;