aboutsummaryrefslogtreecommitdiff
path: root/mingling_core
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-04-12 01:06:24 +0800
committer魏曹先生 <1992414357@qq.com>2026-04-12 01:06:24 +0800
commit7c496151f571b872da523f4c46369751be6f4ca1 (patch)
treee71d2aeb7a16f38996b9d68fe77259269ef25c8f /mingling_core
parent5e10b03acb0312155d0d76e06d366bcf76cb9f27 (diff)
Add ShellContext helper methods for completion logic
Diffstat (limited to 'mingling_core')
-rw-r--r--mingling_core/src/asset/comp/shell_ctx.rs141
-rw-r--r--mingling_core/src/asset/comp/suggest.rs7
-rw-r--r--mingling_core/src/program/flag.rs6
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![] }