mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-04 04:56:49 +00:00
fix(commands): make flags not match if param was in quotes
This commit is contained in:
parent
a21210f3ce
commit
413b8c1915
3 changed files with 38 additions and 17 deletions
|
|
@ -69,7 +69,7 @@ pub fn parse_command(prefix: String, input: String) -> CommandResult {
|
|||
loop {
|
||||
let possible_tokens = local_tree.possible_tokens().cloned().collect::<Vec<_>>();
|
||||
println!("possible: {:?}", possible_tokens);
|
||||
let next = next_token(possible_tokens.clone(), input.clone(), current_pos);
|
||||
let next = next_token(possible_tokens.clone(), &input, current_pos);
|
||||
println!("next: {:?}", next);
|
||||
match next {
|
||||
Some(Ok((found_token, arg, new_pos))) => {
|
||||
|
|
@ -157,39 +157,40 @@ pub fn parse_command(prefix: String, input: String) -> CommandResult {
|
|||
/// - error when matching
|
||||
fn next_token(
|
||||
possible_tokens: Vec<Token>,
|
||||
input: SmolStr,
|
||||
input: &str,
|
||||
current_pos: usize,
|
||||
) -> Option<Result<(Token, Option<TokenMatchedValue>, usize), (Token, TokenMatchError)>> {
|
||||
// get next parameter, matching quotes
|
||||
let param = crate::string::next_param(input.clone(), current_pos);
|
||||
println!("matched: {param:?}\n---");
|
||||
let matched = crate::string::next_param(&input, current_pos);
|
||||
println!("matched: {matched:?}\n---");
|
||||
|
||||
// try checking if this is a flag
|
||||
// todo!: this breaks full text matching if the full text starts with a flag
|
||||
// (but that's kinda already broken anyway)
|
||||
if let Some((value, new_pos)) = param.clone()
|
||||
&& value.starts_with('-')
|
||||
if let Some(param) = matched.as_ref()
|
||||
&& param.in_quotes.not()
|
||||
&& param.value.starts_with('-')
|
||||
{
|
||||
return Some(Ok((
|
||||
Token::Flag,
|
||||
Some(TokenMatchedValue {
|
||||
raw: value,
|
||||
raw: param.value.into(),
|
||||
param: None,
|
||||
}),
|
||||
new_pos,
|
||||
param.next_pos,
|
||||
)));
|
||||
}
|
||||
|
||||
// iterate over tokens and run try_match
|
||||
for token in possible_tokens {
|
||||
// for FullString just send the whole string
|
||||
let input_to_match = param.clone().map(|v| v.0);
|
||||
let input_to_match = matched.as_ref().map(|v| v.value);
|
||||
match token.try_match(input_to_match) {
|
||||
Some(Ok(value)) => {
|
||||
return Some(Ok((
|
||||
token,
|
||||
value,
|
||||
param.map(|v| v.1).unwrap_or(current_pos),
|
||||
matched.map(|v| v.next_pos).unwrap_or(current_pos),
|
||||
)))
|
||||
}
|
||||
Some(Err(err)) => {
|
||||
|
|
|
|||
|
|
@ -42,17 +42,24 @@ lazy_static::lazy_static! {
|
|||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct MatchedParam<'a> {
|
||||
pub(super) value: &'a str,
|
||||
pub(super) next_pos: usize,
|
||||
pub(super) in_quotes: bool,
|
||||
}
|
||||
|
||||
// very very simple quote matching
|
||||
// quotes need to be at start/end of words, and are ignored if a closing quote is not present
|
||||
// WTB POSIX quoting: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html
|
||||
pub(super) fn next_param(input: SmolStr, current_pos: usize) -> Option<(SmolStr, usize)> {
|
||||
pub(super) fn next_param<'a>(input: &'a str, current_pos: usize) -> Option<MatchedParam<'a>> {
|
||||
if input.len() == current_pos {
|
||||
return None;
|
||||
}
|
||||
|
||||
let leading_whitespace_count =
|
||||
input[..current_pos].len() - input[..current_pos].trim_start().len();
|
||||
let substr_to_match: SmolStr = input[current_pos + leading_whitespace_count..].into();
|
||||
let substr_to_match = &input[current_pos + leading_whitespace_count..];
|
||||
println!("stuff: {input} {current_pos} {leading_whitespace_count}");
|
||||
println!("to match: {substr_to_match}");
|
||||
|
||||
|
|
@ -68,20 +75,32 @@ pub(super) fn next_param(input: SmolStr, current_pos: usize) -> Option<(SmolStr,
|
|||
.is_whitespace()
|
||||
{
|
||||
// return quoted string, without quotes
|
||||
return Some((substr_to_match[1..pos - 1].into(), current_pos + pos + 1));
|
||||
return Some(MatchedParam {
|
||||
value: &substr_to_match[1..pos - 1],
|
||||
next_pos: current_pos + pos + 1,
|
||||
in_quotes: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find next whitespace character
|
||||
for (pos, char) in substr_to_match.clone().char_indices() {
|
||||
for (pos, char) in substr_to_match.char_indices() {
|
||||
if char.is_whitespace() {
|
||||
return Some((substr_to_match[..pos].into(), current_pos + pos + 1));
|
||||
return Some(MatchedParam {
|
||||
value: &substr_to_match[..pos],
|
||||
next_pos: current_pos + pos + 1,
|
||||
in_quotes: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// if we're here, we went to EOF and didn't match any whitespace
|
||||
// so we return the whole string
|
||||
Some((substr_to_match.clone(), current_pos + substr_to_match.len()))
|
||||
Some(MatchedParam {
|
||||
value: substr_to_match,
|
||||
next_pos: current_pos + substr_to_match.len(),
|
||||
in_quotes: false,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ impl TokenMatchedValue {
|
|||
type TryMatchResult = Option<Result<Option<TokenMatchedValue>, TokenMatchError>>;
|
||||
|
||||
impl Token {
|
||||
pub fn try_match(&self, input: Option<SmolStr>) -> TryMatchResult {
|
||||
pub fn try_match(&self, input: Option<&str>) -> TryMatchResult {
|
||||
let input = match input {
|
||||
Some(input) => input,
|
||||
None => {
|
||||
|
|
@ -305,6 +305,7 @@ impl FromStr for MemberPrivacyTarget {
|
|||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
// todo: this doesnt parse all the possible ways
|
||||
match s.to_lowercase().as_str() {
|
||||
"visibility" => Ok(Self::Visibility),
|
||||
"name" => Ok(Self::Name),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue