mirror of
https://github.com/sxyazi/yazi.git
synced 2026-05-13 08:16:40 +00:00
fix: keep repeated ! negations in a condition right-associative (#3946)
Co-authored-by: sxyazi <sxyazi@gmail.com>
This commit is contained in:
parent
92b9ea3794
commit
22fb9e0d09
1 changed files with 33 additions and 4 deletions
|
|
@ -1,4 +1,4 @@
|
|||
use std::str::FromStr;
|
||||
use std::{cmp::Ordering, str::FromStr};
|
||||
|
||||
use anyhow::bail;
|
||||
use serde_with::DeserializeFromStr;
|
||||
|
|
@ -33,8 +33,7 @@ impl ConditionOp {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn prec(&self) -> u8 {
|
||||
fn prec(&self) -> u8 {
|
||||
match self {
|
||||
Self::Or => 1,
|
||||
Self::And => 2,
|
||||
|
|
@ -44,6 +43,18 @@ impl ConditionOp {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ConditionOp {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
use Ordering::*;
|
||||
|
||||
match self.prec().cmp(&other.prec()) {
|
||||
// Keep repeated `!` right-associative by making `! >= !` false.
|
||||
Equal if matches!((self, other), (Self::Not, Self::Not)) => None,
|
||||
ordering => Some(ordering),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, DeserializeFromStr)]
|
||||
pub struct Condition {
|
||||
ops: Vec<ConditionOp>,
|
||||
|
|
@ -72,7 +83,7 @@ impl Condition {
|
|||
let op = ConditionOp::new(token);
|
||||
match op {
|
||||
ConditionOp::Or | ConditionOp::And | ConditionOp::Not => {
|
||||
while matches!(stack.last(), Some(last) if last.prec() >= op.prec()) {
|
||||
while matches!(stack.last(), Some(last) if last >= &op) {
|
||||
output.push(stack.pop().unwrap());
|
||||
}
|
||||
stack.push(op);
|
||||
|
|
@ -129,3 +140,21 @@ impl Condition {
|
|||
if stack.len() == 1 { Some(stack[0]) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_condition_not() -> anyhow::Result<()> {
|
||||
let cond: Condition = "!dir".parse()?;
|
||||
assert!(!cond.eval(|s| s == "dir").unwrap());
|
||||
assert!(cond.eval(|_| false).unwrap());
|
||||
|
||||
let cond: Condition = "!!dir".parse()?;
|
||||
assert!(cond.eval(|s| s == "dir").unwrap());
|
||||
assert!(!cond.eval(|_| false).unwrap());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue