added function to wrap debug messages in an echo command

implemented formatted printing of stack and bookmarks
This commit is contained in:
2024-12-15 00:35:09 +01:00
parent c27089124e
commit 77cd64dd60
9 changed files with 234 additions and 95 deletions
+2
View File
@@ -5,5 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
clap = { version = "4.5.0", features = ["derive"] } clap = { version = "4.5.0", features = ["derive"] }
dirs = "5.0.1"
serde = { version = "1.0.216", features = [ "std", "derive" ] }
sysinfo = "0.32.0" sysinfo = "0.32.0"
toml = "0.8.19" toml = "0.8.19"
+3 -4
View File
@@ -1,3 +1,6 @@
#![allow(dead_code)]
#![allow(non_camel_case_types)]
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use std::path::PathBuf; use std::path::PathBuf;
@@ -15,7 +18,6 @@ pub struct Arguments {
} }
#[derive(Debug, Clone, Subcommand)] #[derive(Debug, Clone, Subcommand)]
#[allow(non_camel_case_types)]
pub enum Action { pub enum Action {
/// navigate to path and add current path to the stack /// navigate to path and add current path to the stack
push(PushArgs), push(PushArgs),
@@ -55,7 +57,6 @@ pub struct PopArgs {
} }
#[derive(Debug, Clone, Subcommand)] #[derive(Debug, Clone, Subcommand)]
#[allow(non_camel_case_types)]
pub enum PopAction { pub enum PopAction {
/// pop all entries and move to first entry in stack /// pop all entries and move to first entry in stack
all, all,
@@ -77,7 +78,6 @@ pub struct StackArgs {
} }
#[derive(Debug, Clone, Subcommand)] #[derive(Debug, Clone, Subcommand)]
#[allow(non_camel_case_types)]
pub enum StackAction { pub enum StackAction {
/// clear stack /// clear stack
clear(EmptyArgs), clear(EmptyArgs),
@@ -94,7 +94,6 @@ pub struct BookmarkArgs {
} }
#[derive(Debug, Clone, Subcommand)] #[derive(Debug, Clone, Subcommand)]
#[allow(non_camel_case_types)]
pub enum BookmarkAction { pub enum BookmarkAction {
/// list all bookmarks /// list all bookmarks
list(EmptyArgs), list(EmptyArgs),
+54 -17
View File
@@ -9,7 +9,9 @@ use std::io::{Error, Result};
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use crate::{RESET_SEQ, STYLES}; use crate::make_padding_string;
use super::{apply_format, config::*};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Bookmarks { pub struct Bookmarks {
@@ -80,23 +82,15 @@ impl Bookmarks {
Ok(()) Ok(())
} }
/// writes the bookmarks file /// returns path of bookmark if it exists
fn write_bookmark_file(&self) -> Result<()> { pub fn get_path_by_name(&mut self, name: &str) -> Result<PathBuf> {
let mut file_content = String::new(); match self.bookmarks.get(name) {
for (mark, path) in self.bookmarks.iter() { Some(value) => Ok(value.to_owned()),
file_content.push_str(&format!("{}={}\n", mark, path.to_str().unwrap())); None => Err(Error::other(format!(
"-- bookmark with name `{}` does not exist",
name
))),
} }
let mut path = self.conf_dir.clone();
path.push(Self::BOOKMARK_FILE_NAME);
fs::write(path, file_content)?;
Ok(())
}
/// returns a mutable reference to self.bookmarks
pub fn get_bookmarks(&mut self) -> &mut HashMap<String, PathBuf> {
&mut self.bookmarks
} }
/// adds a key/value pair to bookmarks and writes the bookmarks file /// adds a key/value pair to bookmarks and writes the bookmarks file
@@ -124,4 +118,47 @@ impl Bookmarks {
} }
Ok(()) Ok(())
} }
/// formats and prints bookmarks to string
pub fn to_formatted_string(&self, config: &Settings) -> Result<String> {
let mut buffer = String::new();
if self.bookmarks.is_empty() {
buffer.push_str("-- there are no bookmarks defined");
} else {
let max_name_len = match self.bookmarks.keys().map(String::len).max() {
Some(value) => value,
None => return Err(Error::other("-- failed to determine maximum bookmark name length")),
};
for (mark, path) in &self.bookmarks {
let padding = make_padding_string(max_name_len - mark.len());
let name = apply_format(mark, &config.styles.bookmarks_name);
let separator = apply_format(
&config.format.bookmarks_separator,
&config.styles.bookmarks_seperator,
);
let path = apply_format(path.to_str().unwrap(), &config.styles.bookmarks_path);
if config.format.align_separators {
buffer.push_str(&format!("{}{}{}{}\n", name, padding, separator, path));
} else {
buffer.push_str(&format!("{}{}{}{}\n", name, separator, padding, path));
}
}
}
Ok(buffer)
}
/// writes the bookmarks file
fn write_bookmark_file(&self) -> Result<()> {
let mut file_content = String::new();
for (mark, path) in self.bookmarks.iter() {
file_content.push_str(&format!("{}={}\n", mark, path.to_str().unwrap()));
}
let mut path = self.conf_dir.clone();
path.push(Self::BOOKMARK_FILE_NAME);
fs::write(path, file_content)?;
Ok(())
}
} }
+105 -41
View File
@@ -1,54 +1,54 @@
#![allow(dead_code)]
//! handle the config file and bookmarks stored //! handle the config file and bookmarks stored
//! in said config file //! in said config file
use crate::format::*;
use dirs::config_dir;
use serde::{Deserialize, Serialize};
use std::fs;
use std::io::{Error, Result}; use std::io::{Error, Result};
use std::path::PathBuf; use std::path::PathBuf;
use std::env::var;
use std::fs;
use std::str::FromStr;
use toml::{from_str, Table};
use crate::{RESET_SEQ, STYLES};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
conf_dir: PathBuf, conf_file: PathBuf,
pub settings: Settings, pub settings: Settings,
} }
#[allow(dead_code)] #[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[derive(Debug, Clone)] #[serde(default)]
pub struct Settings { pub struct Settings {
pub general: GeneralSettings, pub general: GeneralSettings,
pub format: FormatSettings, pub format: FormatSettings,
pub styles: StyleSettings, pub styles: StyleSettings,
} }
#[allow(dead_code)] #[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[derive(Debug, Clone)] #[serde(default)]
pub struct GeneralSettings { pub struct GeneralSettings {
pub show_stack_on_push: bool, pub show_stack_on_push: bool,
pub show_stack_on_pop: bool, pub show_stack_on_pop: bool,
pub show_stack_on_bookmark: bool, pub show_stack_on_bookmark: bool,
} }
#[allow(dead_code)] #[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[derive(Debug, Clone)] #[serde(default)]
pub struct FormatSettings { pub struct FormatSettings {
pub stack_separator: String, pub stack_separator: String,
pub bookmarks_separator: String, pub bookmarks_separator: String,
pub align_separators: bool,
} }
#[allow(dead_code)] #[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[derive(Debug, Clone)] #[serde(default)]
pub struct StyleSettings { pub struct StyleSettings {
pub stack_number: String, pub stack_number: String,
pub stack_separator: String, pub stack_separator: String,
pub stack_path: String, pub stack_path: String,
pub bookmarks_key: String, pub bookmarks_name: String,
pub bookmarks_seperator: String, pub bookmarks_seperator: String,
pub bookmarks_path: String, pub bookmarks_path: String,
pub reset: String,
} }
impl Config { impl Config {
@@ -57,7 +57,7 @@ impl Config {
/// generates and populates a new instance of Config /// generates and populates a new instance of Config
pub fn new() -> Result<Self> { pub fn new() -> Result<Self> {
let mut config = Config { let mut config = Config {
conf_dir: PathBuf::new(), conf_file: PathBuf::new(),
settings: Settings { settings: Settings {
general: GeneralSettings { general: GeneralSettings {
show_stack_on_push: false, show_stack_on_push: false,
@@ -65,47 +65,111 @@ impl Config {
show_stack_on_bookmark: false, show_stack_on_bookmark: false,
}, },
format: FormatSettings { format: FormatSettings {
bookmarks_separator: " - ".to_owned(), bookmarks_separator: String::new(),
stack_separator: " - ".to_owned(), stack_separator: String::new(),
align_separators: false,
}, },
styles: StyleSettings { styles: StyleSettings {
stack_number: "".to_owned(), stack_number: String::new(),
stack_separator: "".to_owned(), stack_separator: String::new(),
stack_path: "".to_owned(), stack_path: String::new(),
bookmarks_key: "".to_owned(), bookmarks_name: String::new(),
bookmarks_seperator: "".to_owned(), bookmarks_seperator: String::new(),
bookmarks_path: "".to_owned(), bookmarks_path: String::new(),
reset: RESET_SEQ.to_owned(),
}, },
}, },
}; };
// get home directory path // get configuration directory
let home_dir = match var("HOME") { config.conf_file = match config_dir() {
Ok(value) => value, Some(value) => value,
Err(error) => return Err(Error::other(error.to_string())), None => {
return Err(Error::other(
"-- failed to retrieve configuration directory",
))
}
}; };
// create PathBuf object from home dir path // expand path to configuration file
config.conf_dir = match PathBuf::from_str(&home_dir) { config
Ok(value) => value, .conf_file
Err(error) => return Err(Error::other(error.to_string())), .push(format!("navigate/{}", Self::CONFIG_FILE_NAME));
};
// expand home directory path to get configuration directory path // parse configuration file and populate config struct
config.build_config()?; config.build_settings()?;
config.set_default_settings()?;
config.write_config_file()?;
Ok(config) Ok(config)
} }
/// formats and prints config to string
pub fn to_formatted_string(&self) -> Result<String> {
let mut buffer = String::new();
buffer = format!("{:#?}", self.settings);
Ok(buffer)
}
/// write configuration file to save changed settings
pub fn write_config_file(&self) -> Result<()> {
let conf_str = match toml::to_string(&self.settings) {
Ok(value) => value,
Err(error) => return Err(Error::other(error.to_string())),
};
fs::write(self.conf_file.clone(), conf_str)
}
/// reads and parses the configuration file /// reads and parses the configuration file
fn build_config(&mut self) -> Result<()> { fn build_settings(&mut self) -> Result<()> {
let config_file = match fs::read_to_string(&self.conf_dir) { if !self.conf_file.is_file() {
return Ok(());
}
let config_str = match fs::read_to_string(&self.conf_file) {
Ok(value) => value, Ok(value) => value,
Err(error) => return Err(error), Err(error) => return Err(error),
}; };
let conf_table = match config_file.parse::<Table>() { self.settings = match toml::from_str(&config_str) {
Ok(value) => value, Ok(value) => value,
Err(error) => return Err(Error::other(error.to_string())), Err(error) => return Err(Error::other(error.to_string())),
}; };
Ok(()) Ok(())
} }
/// sets defaults for settings not found in the configuration file
fn set_default_settings(&mut self) -> Result<()> {
let default_separator = " - ".to_owned();
let default_number_color =
generate_style_sequence(None, Some(COLORS.fg.default), Some(COLORS.bg.default));
let default_separator_color =
generate_style_sequence(None, Some(COLORS.fg.cyan), Some(COLORS.bg.default));
let default_path_color =
generate_style_sequence(None, Some(COLORS.fg.default), Some(COLORS.bg.default));
if self.settings.format.stack_separator.is_empty() {
self.settings.format.stack_separator = default_separator.clone();
}
if self.settings.format.bookmarks_separator.is_empty() {
self.settings.format.bookmarks_separator = default_separator.clone();
}
if self.settings.styles.stack_number.is_empty() {
self.settings.styles.stack_number = default_number_color.clone();
}
if self.settings.styles.stack_separator.is_empty() {
self.settings.styles.stack_separator = default_separator_color.clone();
}
if self.settings.styles.stack_path.is_empty() {
self.settings.styles.stack_path = default_path_color.clone();
}
if self.settings.styles.bookmarks_name.is_empty() {
self.settings.styles.bookmarks_name = default_number_color.clone();
}
if self.settings.styles.bookmarks_seperator.is_empty() {
self.settings.styles.bookmarks_seperator = default_separator_color.clone();
}
if self.settings.styles.bookmarks_path.is_empty() {
self.settings.styles.bookmarks_path = default_path_color.clone();
}
Ok(())
}
} }
+4
View File
@@ -0,0 +1,4 @@
pub fn debug_print(string: &str) {
println!("echo '{}' && ", string);
}
+13
View File
@@ -1,3 +1,5 @@
#![allow(dead_code)]
pub const ESC: &str = "\x1B"; pub const ESC: &str = "\x1B";
pub const PREFIX: &str = "\x1B["; pub const PREFIX: &str = "\x1B[";
pub const RESET_ARG: &str = "0"; pub const RESET_ARG: &str = "0";
@@ -105,6 +107,11 @@ pub enum ColorContext {
Background, Background,
} }
/// prepends input with style string and appends the reset sequence at the end
pub fn apply_format(input: &str, style: &str) -> String {
format!("{}{}{}", style, input, RESET_SEQ)
}
/// generates a common style sequence of format /// generates a common style sequence of format
/// `\x1B[<styles>;<foreground-color>;<background-color>m` /// `\x1B[<styles>;<foreground-color>;<background-color>m`
/// all elements are optional, if none is supplied the function returns an error /// all elements are optional, if none is supplied the function returns an error
@@ -174,3 +181,9 @@ pub fn generate_rgb_sequence(context: ColorContext, red: u8, green: u8, blue: u8
sequence.push_str(&format!("{red};{green};{blue}m")); sequence.push_str(&format!("{red};{green};{blue}m"));
sequence sequence
} }
/// generates a padding string for numbers in a list
pub fn make_padding_string(len: usize) -> String {
// determine padding needed to align the paths
String::from_utf8(vec![b' '; len]).unwrap()
}
+16 -13
View File
@@ -3,6 +3,7 @@ mod format;
mod config; mod config;
mod bookmarks; mod bookmarks;
mod stack; mod stack;
mod debug;
use arguments::*; use arguments::*;
use clap::Parser; use clap::Parser;
@@ -54,6 +55,7 @@ fn main() -> Result<()> {
Action::pop(pop_args) => handle_pop(&pop_args, &config, &mut stack), Action::pop(pop_args) => handle_pop(&pop_args, &config, &mut stack),
Action::stack(stack_args) => handle_stack(&stack_args, &config, &mut stack), Action::stack(stack_args) => handle_stack(&stack_args, &config, &mut stack),
Action::bookmark(bookmark_args) => handle_bookmark(&bookmark_args, &config, &mut bookmarks, &mut stack), Action::bookmark(bookmark_args) => handle_bookmark(&bookmark_args, &config, &mut bookmarks, &mut stack),
// Action::config(config_args) => handle_config(&config_args, &config),
}; };
if res.is_err() { if res.is_err() {
@@ -108,11 +110,11 @@ fn handle_pop(args: &PopArgs, _config: &Config, stack: &mut Stack) -> Result<()>
fn handle_stack(args: &StackArgs, config: &Config, stack: &mut Stack) -> Result<()> { fn handle_stack(args: &StackArgs, config: &Config, stack: &mut Stack) -> Result<()> {
if args.stack_action.is_some() { if args.stack_action.is_some() {
match args.stack_action.clone().unwrap() { match args.stack_action.clone().unwrap() {
StackAction::clear(_) => return stack.clear_stack(config), StackAction::clear(_) => return stack.clear_stack(&config.settings),
} }
} }
// retrieve stack // retrieve stack
let output: String = stack.to_string(None)?; let output: String = stack.to_formatted_string(&config.settings)?;
print!("echo '{}'", output); print!("echo '{}'", output);
Ok(()) Ok(())
} }
@@ -125,12 +127,9 @@ fn handle_bookmark(args: &BookmarkArgs, config: &Config, bookmarks: &mut Bookmar
BookmarkAction::add(args) => add_bookmarks(args, config, bookmarks)?, BookmarkAction::add(args) => add_bookmarks(args, config, bookmarks)?,
BookmarkAction::remove(args) => remove_bookmarks(args, config, bookmarks)?, BookmarkAction::remove(args) => remove_bookmarks(args, config, bookmarks)?,
}; };
} else if args.name.is_some() { } else if args.name.is_some() { // handle `change to bookmark`
let path = match bookmarks.get_bookmarks().get(args.name.as_ref().unwrap()) { let path = bookmarks.get_path_by_name(args.name.as_ref().unwrap())?;
Some(value) => value, push_path(&path, stack)?;
None => return Err(Error::other("-- requested bookmark does not exist")),
};
push_path(path, stack)?;
} else { } else {
return Err(Error::other( return Err(Error::other(
"-- provide either a `subcommand` or a `bookmark name`", "-- provide either a `subcommand` or a `bookmark name`",
@@ -139,12 +138,16 @@ fn handle_bookmark(args: &BookmarkArgs, config: &Config, bookmarks: &mut Bookmar
Ok(()) Ok(())
} }
// fn handle_config(args: &ConfigArgs, config: &Config) -> Result<()> {
// match args {
// ConfigAction::show => println!("echo '{}'", config.to_formatted_string()),
// }
// Ok(())
// }
fn list_bookmarks(config: &Config, bookmarks: &mut Bookmarks) -> Result<()> { fn list_bookmarks(config: &Config, bookmarks: &mut Bookmarks) -> Result<()> {
let mut buffer = String::new(); let output = bookmarks.to_formatted_string(&config.settings)?;
for (mark, path) in bookmarks.get_bookmarks() { println!("echo '{}'", output);
buffer.push_str(&format!("{} : {}\n", mark, path.to_str().unwrap()));
}
println!("echo '{}'", buffer);
Ok(()) Ok(())
} }
+30 -13
View File
@@ -1,4 +1,5 @@
use super::config::*; #![allow(dead_code)]
use std::fs; use std::fs;
use std::fs::File; use std::fs::File;
use std::io::{Error, Result}; use std::io::{Error, Result};
@@ -6,6 +7,10 @@ use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use sysinfo::{Pid, System}; use sysinfo::{Pid, System};
use crate::make_padding_string;
use super::{apply_format, config::*};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Stack { pub struct Stack {
pid: u32, pid: u32,
@@ -25,25 +30,37 @@ impl Stack {
Ok(stack) Ok(stack)
} }
// return stack // formats and prints stack to string
pub fn to_string(&self, _settings: Option<Settings>) -> Result<String> { pub fn to_formatted_string(&self, config: &Settings) -> Result<String> {
let mut buffer: String = "".to_string();
if self.stack.is_empty() { if self.stack.is_empty() {
return Err(Error::other("-- the stack is empty")); buffer.push_str("-- the stack is empty");
} } else {
// print stack to string // print stack to string
let mut output: String = "".to_string(); let max_num_len = self.stack.len().to_string().len();
for (n, item) in self.stack.iter().rev().enumerate() { for (n, item) in self.stack.iter().rev().enumerate() {
output.push_str(&format!("'{} - {}'\n", n, item.to_str().unwrap())); let padding = make_padding_string(max_num_len - n.to_string().len());
let number = apply_format(&n.to_string(), &config.styles.stack_number);
let separator = apply_format(
&config.format.stack_separator,
&config.styles.stack_separator,
);
let path = apply_format(item.to_str().unwrap(), &config.styles.stack_path);
if config.format.align_separators {
buffer.push_str(&format!("{}{}{}{}\n", number, padding, separator, path));
} else {
buffer.push_str(&format!("{}{}{}{}\n", number, separator, padding, path));
} }
Ok(output) }
}
Ok(buffer)
} }
/// clear stack by deleting the associated stack file /// clear stack by deleting the associated stack file
pub fn clear_stack(&mut self, _config: &Config) -> Result<()> { pub fn clear_stack(&mut self, config: &Settings) -> Result<()> {
fs::remove_file(self.path.clone())?; fs::remove_file(self.path.clone())?;
print!( print!("echo 'stack cleared successfully.'");
"echo stack cleared successfully.'"
);
Ok(()) Ok(())
} }
@@ -172,4 +189,4 @@ impl Stack {
Ok(()) Ok(())
} }
} // end `impl database` }
+3 -3
View File
@@ -5,8 +5,8 @@
- [x] drop stack - [x] drop stack
- [ ] config file - [ ] config file
- [ ] dedup stack option - [ ] dedup stack option
- [ ] parse config file - [ ] parse config file -- partially done, handling of colors to be fixed
- [ ] apply config - [ ] apply config -- partially done
- [ ] colored output > make it configurable through config file - [ ] colored output > make it configurable through config file
- [ ] setting for separator string when displaying stack/bookmarks - [x] setting for separator string when displaying stack/bookmarks
- [x] bookmarks - [x] bookmarks