Skip to content

Commit

Permalink
escape generated marks
Browse files Browse the repository at this point in the history
  • Loading branch information
drdo committed Jul 7, 2024
1 parent d52c650 commit 6d1f5e2
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 11 deletions.
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#![feature(char_min)]
#![feature(exit_status_error)]
#![feature(step_trait)]
#![feature(try_blocks)]
#![feature(iter_intersperse)]

Expand Down
12 changes: 6 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use ratatui::{
};
use redu::{
cache::{self, filetree::SizeTree, Cache, Migrator},
restic::{self, Restic, Snapshot},
restic::{self, escape_for_exclude, Restic, Snapshot},
};
use scopeguard::defer;
use thiserror::Error;
Expand Down Expand Up @@ -216,7 +216,7 @@ fn main() -> anyhow::Result<()> {
)
};

let mut output_lines = vec![];
let mut output_paths = vec![];

render(&mut terminal, &app)?;
'outer: loop {
Expand All @@ -229,8 +229,8 @@ fn main() -> anyhow::Result<()> {
None
}
Action::Quit => break 'outer,
Action::Generate(lines) => {
output_lines = lines;
Action::Generate(paths) => {
output_paths = paths;
break 'outer;
}
Action::GetParentEntries(path_id) => {
Expand Down Expand Up @@ -264,8 +264,8 @@ fn main() -> anyhow::Result<()> {
disable_raw_mode()?;
stderr().execute(LeaveAlternateScreen)?;

for line in output_lines {
println!("{line}");
for line in output_paths {
println!("{}", escape_for_exclude(line.as_str()));
}
Ok(())
}
Expand Down
70 changes: 70 additions & 0 deletions src/restic.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::{
borrow::Cow,
ffi::OsStr,
fmt::{Display, Formatter},
io::{BufRead, BufReader, Lines, Read},
iter::Step,
marker::PhantomData,
os::unix::process::CommandExt,
process::{Child, ChildStdout, Command, ExitStatusError, Stdio},
Expand Down Expand Up @@ -299,3 +301,71 @@ pub struct File {
pub path: Utf8PathBuf,
pub size: usize,
}

pub fn escape_for_exclude(path: &str) -> Cow<str> {
fn is_special(c: char) -> bool {
['*', '?', '[', '\\', '\r', '\n'].contains(&c)
}

fn push_as_inverse_range(buf: &mut String, c: char) {
#[rustfmt::skip]
let cs = [
'[', '^',
char::MIN, '-', char::backward(c, 1),
char::forward(c, 1), '-', char::MAX,
']',
];
for d in cs {
buf.push(d);
}
}

match path.find(is_special) {
None => Cow::Borrowed(path),
Some(index) => {
let (left, right) = path.split_at(index);
let mut escaped = String::with_capacity(path.len() + 1); // the +1 is for the extra \
escaped.push_str(left);
for c in right.chars() {
match c {
'*' => escaped.push_str("[*]"),
'?' => escaped.push_str("[?]"),
'[' => escaped.push_str("[[]"),
'\\' => {
#[cfg(target_os = "windows")]
escaped.push('\\');
#[cfg(not(target_os = "windows"))]
escaped.push_str("\\\\");
}
'\r' => push_as_inverse_range(&mut escaped, '\r'),
'\n' => push_as_inverse_range(&mut escaped, '\n'),
c => escaped.push(c),
}
}
Cow::Owned(escaped)
}
}
}

#[cfg(test)]
mod test {
use super::escape_for_exclude;

#[cfg(not(target_os = "windows"))]
#[test]
fn escape_for_exclude_test() {
assert_eq!(
escape_for_exclude("foo* bar?[somethin\\g]]]\r\n"),
"foo[*] bar[?][[]somethin\\\\g]]][^\0-\u{000C}\u{000E}-\u{10FFFF}][^\0-\u{0009}\u{000B}-\u{10FFFF}]"
);
}

#[cfg(target_os = "windows")]
#[test]
fn escape_for_exclude_test() {
assert_eq!(
escape_for_exclude("foo* bar?[somethin\\g]]]\r\n"),
"foo[*] bar[?][[]somethin\\g]]][^\0-\u{000C}\u{000E}-\u{10FFFF}][^\0-\u{0009}\u{000B}-\u{10FFFF}]"
);
}
}
12 changes: 7 additions & 5 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,8 @@ fn render_name(
escaped.to_mut().push('/');
}
let span =
Span::raw(shorten_to(&escaped, available_width).into_owned()).bold();
Span::raw(shorten_to(&escaped, available_width).into_owned())
.bold();
if selected {
span.dark_gray()
} else {
Expand All @@ -499,7 +500,7 @@ fn escape_name(name: &str) -> Cow<str> {
None => Cow::Borrowed(name),
Some(index) => {
let (left, right) = name.split_at(index);
let mut escaped = String::with_capacity(name.len()+1); // the +1 is for the extra \
let mut escaped = String::with_capacity(name.len() + 1); // the +1 is for the extra \
escaped.push_str(left);
for c in right.chars() {
if c.is_control() {
Expand Down Expand Up @@ -683,8 +684,6 @@ fn grapheme_len(s: &str) -> usize {
/// Tests //////////////////////////////////////////////////////////////////////
#[cfg(test)]
mod tests {
use std::borrow::Cow;

use super::{shorten_to, *};

#[test]
Expand All @@ -710,7 +709,10 @@ mod tests {

#[test]
fn escape_name_test() {
assert_eq!(escape_name("f\no\\tóà 学校\r"), Cow::Borrowed("f\\no\\tóà 学校\\r"));
assert_eq!(
escape_name("f\no\\tóà 学校\r"),
Cow::Borrowed("f\\no\\tóà 学校\\r")
);
}

#[test]
Expand Down

0 comments on commit 6d1f5e2

Please sign in to comment.