diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-04-12 01:06:24 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-04-12 01:06:24 +0800 |
| commit | 7c496151f571b872da523f4c46369751be6f4ca1 (patch) | |
| tree | e71d2aeb7a16f38996b9d68fe77259269ef25c8f /mingling_core | |
| parent | 5e10b03acb0312155d0d76e06d366bcf76cb9f27 (diff) | |
Add ShellContext helper methods for completion logic
Diffstat (limited to 'mingling_core')
| -rw-r--r-- | mingling_core/src/asset/comp/shell_ctx.rs | 141 | ||||
| -rw-r--r-- | mingling_core/src/asset/comp/suggest.rs | 7 | ||||
| -rw-r--r-- | mingling_core/src/program/flag.rs | 6 |
3 files changed, 153 insertions, 1 deletions
diff --git a/mingling_core/src/asset/comp/shell_ctx.rs b/mingling_core/src/asset/comp/shell_ctx.rs index 5ab0514..e5d095c 100644 --- a/mingling_core/src/asset/comp/shell_ctx.rs +++ b/mingling_core/src/asset/comp/shell_ctx.rs @@ -1,4 +1,6 @@ -use crate::ShellFlag; +use std::collections::HashSet; + +use crate::{Flag, ShellFlag, Suggest}; /// Context passed from the shell to the completion system, /// providing information about the current command line state @@ -92,6 +94,143 @@ impl TryFrom<Vec<String>> for ShellContext { } } +impl ShellContext { + /// Checks if a flag appears exactly once in the command line arguments. + /// + /// This method is useful for determining whether a flag should be processed + /// when it should only be applied once, even if it appears multiple times + /// in the command line. It returns `true` if the flag is present and + /// appears exactly once among all words in the shell context. + /// + /// # Example + /// + /// ``` + /// # use mingling_core::ShellContext; + /// # use mingling_macros::suggest; + /// # use mingling::comp_tools::ShellContextHelper; + /// + /// let ctx = ShellContext::default(); + /// let helper = ShellContextHelper::from(ctx); + /// + /// // Check if either "--insert" or "-i" appears exactly once + /// if helper.filling_argument_first(["--insert", "-i"]) { + /// // Perform action that should only happen once, example: + /// // return suggest! { + /// // "A", "B", "C" + /// // } + /// } + /// ``` + pub fn filling_argument_first(&self, flag: impl Into<Flag>) -> bool { + let flag = flag.into(); + if self.filling_argument(&flag) { + let mut flag_appears = 0; + for w in self.all_words.iter() { + for f in flag.iter() { + if *f == w { + flag_appears += 1; + } + } + } + if flag_appears < 2 { + return true; + } + } + return false; + } + + /// Checks if the previous word in the command line arguments matches any of the given flags. + /// + /// This method determines whether a flag is currently being processed + /// by checking the word immediately before the cursor position. It returns + /// `true` if the previous word matches any of the provided flag strings. + /// + /// # Example + /// + /// ``` + /// # use mingling_core::ShellContext; + /// # use mingling_macros::suggest; + /// # use mingling::comp_tools::ShellContextHelper; + /// + /// let ctx = ShellContext::default(); + /// let helper = ShellContextHelper::from(ctx); + /// + /// // Check if the previous word is either "--file" or "-f" + /// if helper.filling_argument(["--file", "-f"]) { + /// // The user is likely expecting a file argument next, example: + /// // return suggest! { + /// // "src/main.rs", "Cargo.toml", "README.md" + /// // } + /// } + /// ``` + pub fn filling_argument(&self, flag: impl Into<Flag>) -> bool { + for f in flag.into().iter() { + if self.previous_word == **f { + return true; + } + } + return false; + } + + /// Checks if the user is currently typing a flag argument. + /// + /// This method determines whether the current word being typed starts with + /// a dash (`-`), indicating that the user is likely in the process of + /// entering a command-line flag. It returns `true` if the current word + /// begins with a dash character. + /// + /// # Example + /// + /// ``` + /// # use mingling_core::ShellContext; + /// # use mingling_macros::suggest; + /// # use mingling::comp_tools::ShellContextHelper; + /// + /// let ctx = ShellContext::default(); + /// let helper = ShellContextHelper::from(ctx); + /// + /// // Check if the user is typing a flag + /// if helper.typing_argument() { + /// // The user is likely entering a flag, example: + /// // return suggest! { + /// // "--help", "--version", "--verbose" + /// // } + /// } + /// ``` + pub fn typing_argument(&self) -> bool { + self.current_word.starts_with("-") + } + + /// Filters out already typed flag arguments from suggestion results. + /// + /// This method removes any suggestions that match flag arguments already present + /// in the command line. It is useful for preventing duplicate flag suggestions + /// when the user has already typed certain flags. The method processes both + /// regular suggestion sets and file completion suggestions differently. + pub fn strip_typed_argument(&self, suggest: Suggest) -> Suggest { + let typed = Self::get_typed_arguments(&self); + match suggest { + Suggest::Suggest(mut set) => { + set.retain(|item| !typed.contains(item.suggest())); + Suggest::Suggest(set) + } + Suggest::FileCompletion => Suggest::FileCompletion, + } + } + + /// Retrieves all flag arguments from the command line. + /// + /// This method collects all words in the shell context that start with a dash (`-`), + /// which typically represent command-line flags or options. It returns a vector + /// containing these flag strings, converted to owned `String` values. + pub fn get_typed_arguments(&self) -> HashSet<String> { + self.all_words + .iter() + .filter(|word| word.starts_with("-")) + .map(|word| word.to_string()) + .collect() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/mingling_core/src/asset/comp/suggest.rs b/mingling_core/src/asset/comp/suggest.rs index 81000d5..62844a7 100644 --- a/mingling_core/src/asset/comp/suggest.rs +++ b/mingling_core/src/asset/comp/suggest.rs @@ -1,5 +1,7 @@ use std::collections::BTreeSet; +use crate::ShellContext; + /// A completion suggestion that tells the shell how to perform completion. /// This can be either a set of specific suggestion items or a request for file completion. #[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] @@ -23,6 +25,11 @@ impl Suggest { pub fn file_comp() -> Self { Self::FileCompletion } + + /// Filters out already typed flag arguments from suggestion results. + pub fn strip_typed_argument(self, ctx: &ShellContext) -> Self { + ctx.strip_typed_argument(self) + } } impl<T> From<T> for Suggest diff --git a/mingling_core/src/program/flag.rs b/mingling_core/src/program/flag.rs index ed89c2a..ba3376c 100644 --- a/mingling_core/src/program/flag.rs +++ b/mingling_core/src/program/flag.rs @@ -46,6 +46,12 @@ pub struct Flag { vec: Vec<&'static str>, } +impl From<&Flag> for Flag { + fn from(value: &Flag) -> Self { + value.clone() + } +} + impl From<()> for Flag { fn from(_: ()) -> Self { Flag { vec: vec![] } |
