feat: enhanced execution format

This commit is contained in:
sxyazi 2023-08-10 22:40:01 +08:00
parent a5eed70872
commit d476b30df9
No known key found for this signature in database
5 changed files with 189 additions and 2 deletions

View file

@ -19,6 +19,7 @@
- cd: Change the current directory.
- `path`: the path to change to.
- `--interactive`: Use an interactive UI to input the path.
### Selection

View file

@ -33,7 +33,7 @@ audio = [
]
fallback = [
{ cmd = "open", args = [ "$*" ], display_name = "Open" },
{ cmd = "open", args = [ "-R", "$*" ], display_name = "Reveal in Finder" },
{ cmd = "open", args = [ "-R", "$*" ], display_name = "Reveal in Finder" },
]
[open]

185
config/src/exec_new.rs Normal file
View file

@ -0,0 +1,185 @@
use std::fmt::{Debug, Formatter};
#[derive(Debug)]
pub struct ExecNew {
items: Vec<ExecItem>,
}
pub enum ExecItem {
Word(String),
Arg(String, bool),
Str(String, usize),
}
impl ExecItem {
#[inline]
fn push(&mut self, c: char) {
match self {
ExecItem::Word(s) => s.push(c),
ExecItem::Arg(s, _) => s.push(c),
ExecItem::Str(s, _) => s.push(c),
}
}
#[inline]
fn is_empty(&self) -> bool {
match self {
ExecItem::Word(s) => s.is_empty(),
ExecItem::Arg(..) => false,
ExecItem::Str(s, _) => s.is_empty(),
}
}
}
impl Debug for ExecItem {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ExecItem::Word(s) => write!(f, "Word({s})"),
ExecItem::Arg(s, _) => write!(f, "Arg({s})"),
ExecItem::Str(s, n) => write!(f, "Str{n}({s})"),
}
}
}
impl ToString for ExecItem {
fn to_string(&self) -> String {
match self {
ExecItem::Word(s) => s.clone(),
ExecItem::Arg(s, b) => format!("-{}{s}", if *b { "-" } else { "" }),
ExecItem::Str(s, n) => {
if *n == 0 {
return s.to_string();
}
let rep = "\\\\".repeat(*n);
let rep = rep[..rep.len() - 1].to_string();
if s == "'" || s == "\"" {
return format!("{rep}{s}");
}
let mut s = s.clone();
if let Some(ss) = s.strip_prefix('"') {
s = format!("{rep}\"{ss}");
}
if let Some(ss) = s.strip_suffix('"') {
s = format!("{ss}{rep}\"");
}
if let Some(ss) = s.strip_prefix('\'') {
s = format!("{rep}'{ss}");
}
if let Some(ss) = s.strip_suffix('\'') {
s = format!("{ss}{rep}'");
}
s
}
}
}
}
impl ExecNew {
pub fn parse(s: &str) -> Self {
let mut item = ExecItem::Word(Default::default());
let mut last = b'\0';
let mut esc = 0;
let mut items = vec![];
#[inline]
fn add(items: &mut Vec<ExecItem>, item: ExecItem) {
if !item.is_empty() {
items.push(item);
}
}
for c in s.trim().chars() {
if last == b'\\' && !matches!(c, '\\' | '"' | '\'') {
item.push('\\');
esc = 0;
last = b'\0';
}
match c {
' ' => match item {
ExecItem::Str(ref mut s, ..) => s.push(c),
ExecItem::Word(ref mut s) if last == b'\\' => {
s.push('\\');
s.push(c);
}
_ => {
item.push(c);
add(&mut items, item);
item = ExecItem::Word(Default::default());
}
},
'-' => match item {
ExecItem::Word(ref mut w) => {
if w.is_empty() {
item = ExecItem::Arg(Default::default(), false);
} else {
w.push(c);
}
}
ExecItem::Arg(_, ref mut b) => *b = true,
ExecItem::Str(ref mut s, ..) => s.push(c),
},
'\\' => {
if last == b'\\' {
esc += 1;
last = b'\0';
} else {
last = b'\\';
}
}
'"' | '\'' => {
if last == b'\\' {
esc += 1;
last = b'\0';
}
if matches!(item, ExecItem::Str(_, e) if e == esc) {
item.push(c);
add(&mut items, item);
item = ExecItem::Str(Default::default(), esc);
} else {
add(&mut items, item);
item = ExecItem::Str(c.to_string(), esc);
}
esc = 0;
}
c => {
item.push(c);
}
}
}
add(&mut items, item);
Self { items }
}
}
impl ToString for ExecNew {
fn to_string(&self) -> String {
self.items.iter().map(|i| i.to_string()).collect::<Vec<_>>().join("")
}
}
#[test]
fn test() {
fn assert(a: &str) {
let exec = ExecNew::parse(a);
let a = a.trim();
let b = exec.to_string().trim().to_string();
println!("{:?}", exec);
if a != b {
println!("A: {}", a);
println!("B: {}", b);
}
}
assert(r#" echo 123 "foo" 'bar' "#);
assert(r#" sh -c "sh -c \"\";" "#);
assert(r#" aaa - "bbb --opt \"ccc \\\"Meow\\\"\"" "#);
assert(r#" python4 --code 'bash -c "echo \'\\\'\'"'; "#);
assert(r#" sh -c "sh -c \"exiftool $0; echo \\\"\nPress enter to exit: \\\"; read\"" "#);
}

View file

@ -3,6 +3,7 @@
use once_cell::sync::Lazy;
mod boot;
mod exec_new;
pub mod keymap;
mod log;
pub mod manager;

View file

@ -9,4 +9,4 @@ crossterm = "^0"
libc = "^0"
parking_lot = "^0"
ratatui = { version = "^0" }
tokio = { version = "^1", features = [ "parking_lot" ] }
tokio = { version = "^1", features = [ "parking_lot", "macros", "rt-multi-thread", "sync", "time", "fs" ] }