Skip to content

Commit

Permalink
Merge pull request #30 from decathorpe/master
Browse files Browse the repository at this point in the history
Update dependencies
  • Loading branch information
SoptikHa2 authored Oct 15, 2024
2 parents 59c0fa4 + 79b506e commit bb83348
Show file tree
Hide file tree
Showing 8 changed files with 434 additions and 315 deletions.
565 changes: 344 additions & 221 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ edition = "2018"

[dependencies]
# Parsing CLI arguments
clap = { version = "3.0.14", features = ["cargo"] }
clap = { version = "4", features = ["cargo"] }
# TUI
crossterm = "0.25.0"
tui = { version = "0.19.0", default-features = false, features = ["crossterm"] }
crossterm = "0.28.0"
tui = { package = "ratatui", version = "0.28.0", default-features = false, features = ["crossterm"] }
# Flexible error handling
anyhow = "1.0.65"
# For easier handling of conditional compilation
Expand All @@ -26,5 +26,5 @@ cfg-if = "1.0.0"
[target.'cfg(target_os = "linux")'.dependencies]
inotify = "0.10.0" # Watch files and auto-reload on changes

[target.'cfg(any(target_os="darwin", target_os="dragonfly", target_os="freebsd", target_os="netbsd", target_os="openbsd"))'.dependencies]
[target.'cfg(any(target_os="macos", target_os="dragonfly", target_os="freebsd", target_os="netbsd", target_os="openbsd"))'.dependencies]
kqueue = "1.0.6" # Watch files and auto-reload on changes
50 changes: 24 additions & 26 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,52 @@
use anyhow::{Context, Result};
use clap::{crate_version, App, Arg, ArgMatches};
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
use std::path::PathBuf;
use std::str::FromStr;

pub fn parse_arguments<'a, 'b>() -> Result<Options> {
let matches = App::new("Desed")
pub fn parse_arguments() -> Result<Options> {
let matches = Command::new("Desed")
.version(crate_version!())
.author("Petr Šťastný <[email protected]>")
.about("Sed script debugger. Debug and demystify your sed scripts with TUI debugger.")
.arg(Arg::with_name("sed_n")
.arg(Arg::new("sed_n")
.action(ArgAction::SetTrue)
.short('n')
.long("quiet")
.long("silent")
.help("sed: suppress automatic printing of pattern space")
.takes_value(false)
.required(false))
.arg(Arg::with_name("sed_E")
.arg(Arg::new("sed_E")
.action(ArgAction::SetTrue)
.short('E')
.long("regexp-extended")
.help("sed: use extended regular expressions in the script")
.takes_value(false)
.required(false))
.arg(Arg::with_name("sed_sandbox")
.arg(Arg::new("sed_sandbox")
.action(ArgAction::SetTrue)
.long("sandbox")
.help("sed: operate in sandbox mode (disable e/r/w commands).")
.takes_value(false)
.required(false))
.arg(Arg::with_name("sed_z")
.arg(Arg::new("sed_z")
.action(ArgAction::SetTrue)
.long("null-data")
.short('z')
.help("sed: separate lines by NUL characters")
.takes_value(false)
.required(false))
.arg(Arg::with_name("verbose")
.arg(Arg::new("verbose")
.action(ArgAction::SetTrue)
.long("verbose")
.short('v')
.help("This will enable various debug printing to stderr.")
.takes_value(false)
.required(false))
.arg(Arg::with_name("sed-path")
.arg(Arg::new("sed-path")
.long("sed-path")
.help("Specify path to sed that should be used. If omitted, gsed/sed from your $PATH will run.")
.takes_value(true)
.required(false))
.arg(Arg::with_name("sed-script")
.arg(Arg::new("sed-script")
.help("Input file with sed script")
.required(true)
.multiple(false)
.index(1))
.arg(Arg::with_name("input-file")
.arg(Arg::new("input-file")
.help("File with data for sed to process.")
.required(true)
.index(2))
Expand Down Expand Up @@ -80,30 +78,30 @@ pub struct Options {
impl Options {
pub fn from_matches(matches: ArgMatches) -> Result<Options> {
// UNWRAP: It's safe because we define sed-script in the CLI code above, so we are certain it exists.
let sed_script: PathBuf = PathBuf::from_str(matches.value_of("sed-script").unwrap())
let sed_script: PathBuf = PathBuf::from_str(matches.get_one::<String>("sed-script").unwrap())
.with_context(|| "Failed to load sed script path")?;
// UNWRAP: It's safe because we define input-file in the CLI code above, so we are certain it exists.
let input_file: PathBuf = PathBuf::from_str(matches.value_of("input-file").unwrap())
let input_file: PathBuf = PathBuf::from_str(matches.get_one::<String>("input-file").unwrap())
.with_context(|| "Failed to load input file path.")?;

let sed_path: Option<String> = matches.value_of("sed-path").map(|s| String::from(s));
let sed_path: Option<String> = matches.get_one::<String>("sed-path").map(ToOwned::to_owned);

let mut sed_parameters: Vec<String> = Vec::with_capacity(4);
let mut debug = false;

if matches.is_present("sed_n") {
if matches.get_flag("sed_n") {
sed_parameters.push(String::from("-n"));
}
if matches.is_present("sed_E") {
if matches.get_flag("sed_E") {
sed_parameters.push(String::from("-E"));
}
if matches.is_present("sed_sandbox") {
if matches.get_flag("sed_sandbox") {
sed_parameters.push(String::from("--sandbox"));
}
if matches.is_present("sed_z") {
if matches.get_flag("sed_z") {
sed_parameters.push(String::from("-z"));
}
if matches.is_present("verbose") {
if matches.get_flag("verbose") {
debug = true;
}

Expand Down
20 changes: 10 additions & 10 deletions src/file_watcher/inotify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ impl FileWatcherImpl {
Err(msg) => return Result::Err(msg),
};

return Result::Ok(FileWatcherImpl {
Result::Ok(FileWatcherImpl {
inotify: ino,
watches: vec![]
});
})
}

pub fn add_watch(&mut self, file_path: &PathBuf) -> Result<&FileWatchImpl> {
let mask: inotify::WatchMask = inotify::WatchMask::MODIFY;

let watch = match self.inotify.add_watch(file_path, mask) {
let watch = match self.inotify.watches().add(file_path, mask) {
Ok(w) => w,
Err(msg) => return Result::Err(msg),
};
Expand All @@ -40,35 +40,35 @@ impl FileWatcherImpl {
};

self.watches.push(fw);
return Result::Ok(&self.watches.last().unwrap());
return Result::Ok(self.watches.last().unwrap());
}

pub fn rm_watch(&mut self, fw: &FileWatchImpl) -> Result<()> {
for i in 0..self.watches.len() {
let item_ref = self.watches.get(i).unwrap();
if item_ref.descriptor == fw.descriptor {
let item = self.watches.remove(i);
return self.inotify.rm_watch(item.descriptor);
return self.inotify.watches().remove(item.descriptor);
}
}

return Result::Err(Error::new(
Result::Err(Error::new(
ErrorKind::InvalidInput,
"Passed FileWatch does not belong to this FileWatcher instance"
));
))
}

pub fn start(&mut self) -> Result<()> {
return Result::Ok(());
Result::Ok(())
}

pub fn any_events(&mut self) -> Result<bool> {
let mut buffer = [0; 1024];
let events = match self.inotify.read_events(&mut buffer) {
Result::Ok(ev) => ev,
Result::Err(err) => return Result::Err(Error::from(err)),
Result::Err(err) => return Result::Err(err),
};

return Result::Ok(events.count() > 0);
Result::Ok(events.count() > 0)
}
}
4 changes: 3 additions & 1 deletion src/file_watcher/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#![allow(dead_code)]

extern crate cfg_if;

cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
mod inotify;
pub type FileWatcher = crate::file_watcher::inotify::FileWatcherImpl;
pub type FileWatch = crate::file_watcher::inotify::FileWatchImpl;
} else if #[cfg(any(target_os="darwin", target_os="dragonfly", target_os="freebsd", target_os="netbsd", target_os="openbsd"))] {
} else if #[cfg(any(target_os="macos", target_os="dragonfly", target_os="freebsd", target_os="netbsd", target_os="openbsd"))] {
mod kqueue;
pub type FileWatcher = crate::file_watcher::kqueue::FileWatcherImpl;
pub type FileWatch = crate::file_watcher::kqueue::FileWatchImpl;
Expand Down
6 changes: 3 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fn watch_files(settings: &Options) -> Result<FileWatcher> {
fw.add_watch(&settings.input_file)?;
fw.start()?;

return Result::Ok(fw);
Result::Ok(fw)
}

/// Debug application and start at specified
Expand All @@ -42,10 +42,10 @@ fn run(target_state_number: usize) -> Result<()> {
let tui = Tui::new(&debugger, watcher, target_state_number)?;
match tui.start()? {
ApplicationExitReason::UserExit => {
return Ok(());
Ok(())
}
ApplicationExitReason::Reload(instruction_number) => {
return run(instruction_number);
run(instruction_number)
}
}
}
30 changes: 14 additions & 16 deletions src/sed/communication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,34 @@ impl SedCommunicator {
let program_source = self.parse_program_source(&output);
let label_jump_map = self.build_jump_map(&program_source);
let frames = self.parse_state_frames(&output, &label_jump_map, program_source.len());
return Ok(DebugInfoFromSed {
Ok(DebugInfoFromSed {
program_source,
states: frames.0,
last_output: frames.1,
});
})
}
fn get_sed_output(&mut self) -> Result<String> {
let mut path_to_be_used: &String = &String::from("sed");
if let Some(path) = &self.options.sed_path {
path_to_be_used = path;
}

let mandatory_parameters = vec![
"--debug",
let mandatory_parameters = ["--debug",
"-f",
self.options
.sed_script
.to_str()
.with_context(|| format!("Invalid sed script path. Is it valid UTF-8?"))?,
.with_context(|| "Invalid sed script path. Is it valid UTF-8?".to_string())?,
self.options
.input_file
.to_str()
.with_context(|| format!("Invalid input path. Is it valid UTF-8?"))?,
];
.with_context(|| "Invalid input path. Is it valid UTF-8?".to_string())?];
let constructed_cmd_line = self
.options
.sed_parameters
.iter()
.map(|s| s.as_str())
.chain(mandatory_parameters.iter().map(|s| *s))
.chain(mandatory_parameters.iter().copied())
.collect::<Vec<&str>>();
let sed_debug_command = Command::new(path_to_be_used)
.args(&constructed_cmd_line)
Expand All @@ -58,7 +56,7 @@ impl SedCommunicator {
.ok()
.with_context(
|| format!("Sed failed to return output. Shouldn't you use -E option? Are you using GNU sed? Is there sed/gsed in $PATH?{}" ,
if self.options.verbose{ format!("\n[Info] Sed was called using \"{} {}\"", &path_to_be_used, constructed_cmd_line.join(" ")) } else { format!("") }
if self.options.verbose{ format!("\n[Info] Sed was called using \"{} {}\"", &path_to_be_used, constructed_cmd_line.join(" ")) } else { String::new() }
))?
.stdout;

Expand All @@ -74,7 +72,7 @@ impl SedCommunicator {
// If sed returned no output (so it failed) and sed
// path wasn't specified by user,
// change executing path to "gsed" and try again.
if self.options.sed_path.is_none() && sed_debug_command.len() == 0 {
if self.options.sed_path.is_none() && sed_debug_command.is_empty() {
self.options.sed_path = Some(String::from("gsed"));
if self.options.verbose {
eprintln!(
Expand All @@ -85,7 +83,7 @@ impl SedCommunicator {
return self.get_sed_output();
}

Ok(String::from_utf8(sed_debug_command).with_context(|| "String received from sed doesn't seem to be UTF-8. If this continues to happen, please report a bug.")?)
String::from_utf8(sed_debug_command).with_context(|| "String received from sed doesn't seem to be UTF-8. If this continues to happen, please report a bug.")
}

/// Wait for line that looks like "SED PROGRAM:"
Expand All @@ -94,7 +92,7 @@ impl SedCommunicator {
/// into output vector.
///
/// When we meet a line that doesn't start with two spaces, stop reading and return.
fn parse_program_source(&self, sed_output: &String) -> Vec<String> {
fn parse_program_source(&self, sed_output: &str) -> Vec<String> {
sed_output
.lines()
.skip_while(|line| *line != "SED PROGRAM:")
Expand Down Expand Up @@ -154,7 +152,7 @@ impl SedCommunicator {
/// This returns individual frames *and* output of the last segement of the sed script.
fn parse_state_frames(
&self,
sed_output: &String,
sed_output: &str,
label_jump_map: &HashMap<String, usize>,
lines_of_code: usize,
) -> (Vec<DebuggingState>, Option<Vec<String>>) {
Expand Down Expand Up @@ -334,7 +332,7 @@ impl SedCommunicator {
// Unconditional jump
x if x.starts_with("b") => {
let rest = x[1..].trim();
if rest == "" {
if rest.is_empty() {
// Jump to end of script
lines_of_code
} else if let Some(target) = label_jump_map.get(rest) {
Expand All @@ -353,7 +351,7 @@ impl SedCommunicator {
|| (x.starts_with("T") && !last_match_successful)
{
let rest = x[1..].trim();
if rest == "" {
if rest.is_empty() {
// jump to end of script
lines_of_code
} else if let Some(target) = label_jump_map.get(rest) {
Expand All @@ -375,7 +373,7 @@ impl SedCommunicator {
}

/// Build label jump map
fn build_jump_map(&self, source_code: &Vec<String>) -> HashMap<String, usize> {
fn build_jump_map(&self, source_code: &[String]) -> HashMap<String, usize> {
let mut map: HashMap<String, usize> = HashMap::new();
for (i, line) in source_code.iter().enumerate() {
let trimmed = line.trim();
Expand Down
Loading

0 comments on commit bb83348

Please sign in to comment.