From 9d862344e648b91be774e8ca633dc39990abc8fa Mon Sep 17 00:00:00 2001 From: Denis Isidoro Date: Fri, 29 Jul 2022 19:25:36 -0300 Subject: [PATCH] Minor code base improvements (#767) --- src/clients/tldr.rs | 2 +- src/commands/core/actor.rs | 28 +++++--- src/commands/core/extractor.rs | 27 -------- src/commands/core/mod.rs | 8 +-- src/commands/func/mod.rs | 11 ++- src/commands/info.rs | 11 ++- src/commands/preview/mod.rs | 6 +- src/commands/preview/var.rs | 9 +-- src/commands/shell.rs | 11 ++- src/commands/temp.rs | 8 +-- src/config/cli.rs | 41 +---------- src/deser/mod.rs | 34 +++++++++ src/deser/raycast.rs | 51 ++++++++++++++ src/deser/terminal.rs | 79 +++++++++++++++++++++ src/finder/mod.rs | 14 +++- src/lib.rs | 3 +- src/parser.rs | 10 +-- src/serializer.rs | 121 --------------------------------- src/terminal.rs | 1 - 19 files changed, 242 insertions(+), 233 deletions(-) delete mode 100644 src/commands/core/extractor.rs create mode 100644 src/deser/mod.rs create mode 100644 src/deser/raycast.rs create mode 100644 src/deser/terminal.rs delete mode 100644 src/serializer.rs delete mode 100644 src/terminal.rs diff --git a/src/clients/tldr.rs b/src/clients/tldr.rs index 6783fdc3..81e827f1 100644 --- a/src/clients/tldr.rs +++ b/src/clients/tldr.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use std::process::{self, Command, Stdio}; +use std::process::{Command, Stdio}; lazy_static! { pub static ref VAR_TLDR_REGEX: Regex = Regex::new(r"\{\{(.*?)\}\}").expect("Invalid regex"); diff --git a/src/commands/core/actor.rs b/src/commands/core/actor.rs index e423afee..6e1fd443 100644 --- a/src/commands/core/actor.rs +++ b/src/commands/core/actor.rs @@ -1,14 +1,14 @@ -use super::extractor; use crate::common::clipboard; use crate::common::fs; use crate::common::shell; use crate::common::shell::ShellSpawnError; use crate::config::Action; +use crate::deser; use crate::env_var; use crate::finder::structures::{Opts as FinderOpts, SuggestionType}; use crate::prelude::*; -use crate::serializer; use crate::structures::cheat::{Suggestion, VariableMap}; +use crate::structures::item::Item; use shell::EOF; use std::process::Stdio; @@ -145,10 +145,7 @@ fn unique_result_count(results: &[&str]) -> usize { fn replace_variables_from_snippet(snippet: &str, tags: &str, variables: VariableMap) -> Result { let mut interpolated_snippet = String::from(snippet); - let variables_found: Vec<&str> = serializer::VAR_REGEX - .find_iter(snippet) - .map(|m| m.as_str()) - .collect(); + let variables_found: Vec<&str> = deser::VAR_REGEX.find_iter(snippet).map(|m| m.as_str()).collect(); let variable_count = unique_result_count(&variables_found); for bracketed_variable_name in variables_found { @@ -187,11 +184,20 @@ pub fn with_absolute_path(snippet: String) -> String { } pub fn act( - extractions: Result, + extractions: Result<(&str, Item)>, files: Vec, variables: Option, ) -> Result<()> { - let (key, tags, comment, snippet, file_index) = extractions.unwrap(); + let ( + key, + Item { + tags, + comment, + snippet, + file_index, + .. + }, + ) = extractions.unwrap(); if key == "ctrl-o" { edit::edit_file(Path::new(&files[file_index.expect("No files found")])) @@ -205,13 +211,13 @@ pub fn act( let interpolated_snippet = { let mut s = replace_variables_from_snippet( - snippet, - tags, + &snippet, + &tags, variables.expect("No variables received from finder"), ) .context("Failed to replace variables from snippet")?; s = with_absolute_path(s); - s = serializer::with_new_lines(s); + s = deser::with_new_lines(s); s }; diff --git a/src/commands/core/extractor.rs b/src/commands/core/extractor.rs deleted file mode 100644 index 56758e85..00000000 --- a/src/commands/core/extractor.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::prelude::*; -use crate::serializer; - -pub type Output<'a> = (&'a str, &'a str, &'a str, &'a str, Option); - -pub fn extract_from_selections(raw_snippet: &str, is_single: bool) -> Result { - let mut lines = raw_snippet.split('\n'); - let key = if is_single { - "enter" - } else { - lines - .next() - .context("Key was promised but not present in `selections`")? - }; - - let mut parts = lines - .next() - .context("No more parts in `selections`")? - .split(serializer::DELIMITER) - .skip(3); - - let tags = parts.next().unwrap_or(""); - let comment = parts.next().unwrap_or(""); - let snippet = parts.next().unwrap_or(""); - let file_index = parts.next().unwrap_or("").parse().ok(); - Ok((key, tags, comment, snippet, file_index)) -} diff --git a/src/commands/core/mod.rs b/src/commands/core/mod.rs index 74e28527..ded24f1f 100644 --- a/src/commands/core/mod.rs +++ b/src/commands/core/mod.rs @@ -1,8 +1,8 @@ mod actor; -mod extractor; -use crate::clients::cheatsh; +use crate::clients::{cheatsh, tldr}; use crate::config::Source; +use crate::deser; use crate::filesystem; use crate::finder::structures::Opts as FinderOpts; use crate::parser::Parser; @@ -32,7 +32,7 @@ pub fn init(fetcher: Box) -> Result<()> { }) .context("Failed getting selection and variables from finder")?; - let extractions = extractor::extract_from_selections(&raw_selection, config.best_match()); + let extractions = deser::terminal::read(&raw_selection, config.best_match()); if extractions.is_err() { return init(fetcher); @@ -51,7 +51,7 @@ pub fn get_fetcher() -> Result> { Ok(fetcher) } Source::Tldr(query) => { - let lines = cheatsh::call(&query)?; + let lines = tldr::call(&query)?; let fetcher = Box::new(StaticFetcher::new(lines)); Ok(fetcher) } diff --git a/src/commands/func/mod.rs b/src/commands/func/mod.rs index 383b636b..03a55f8e 100644 --- a/src/commands/func/mod.rs +++ b/src/commands/func/mod.rs @@ -8,7 +8,7 @@ use crate::prelude::*; use clap::Args; use clap::Parser; -const FUNC_POSSIBLE_VALUES: &[&str] = &[ +const POSSIBLE_VALUES: &[&str] = &[ "url::open", "welcome", "widget::last_command", @@ -43,7 +43,7 @@ pub enum Func { #[derive(Debug, Clone, Args)] pub struct Input { /// Function name (example: "url::open") - #[clap(possible_values = FUNC_POSSIBLE_VALUES, ignore_case = true)] + #[clap(possible_values = POSSIBLE_VALUES, ignore_case = true)] pub func: Func, /// List of arguments (example: "https://google.com") pub args: Vec, @@ -63,3 +63,10 @@ impl Runnable for Input { } } } + +#[test] +fn test_possible_values() { + for v in POSSIBLE_VALUES { + assert!(Func::from_str(v).is_ok()) + } +} diff --git a/src/commands/info.rs b/src/commands/info.rs index 6b69f809..9061462a 100644 --- a/src/commands/info.rs +++ b/src/commands/info.rs @@ -3,7 +3,7 @@ use clap::Args; use crate::filesystem; use crate::prelude::*; -const INFO_POSSIBLE_VALUES: &[&str] = &["cheats-example", "cheats-path", "config-path", "config-example"]; +const POSSIBLE_VALUES: &[&str] = &["cheats-example", "cheats-path", "config-path", "config-example"]; impl FromStr for Info { type Err = &'static str; @@ -21,7 +21,7 @@ impl FromStr for Info { #[derive(Debug, Clone, Args)] pub struct Input { - #[clap(possible_values = INFO_POSSIBLE_VALUES, ignore_case = true)] + #[clap(possible_values = POSSIBLE_VALUES, ignore_case = true)] pub info: Info, } @@ -46,3 +46,10 @@ impl Runnable for Input { Ok(()) } } + +#[test] +fn test_possible_values() { + for v in POSSIBLE_VALUES { + assert!(Info::from_str(v).is_ok()) + } +} diff --git a/src/commands/preview/mod.rs b/src/commands/preview/mod.rs index 11fa1fcd..dfd6d37b 100644 --- a/src/commands/preview/mod.rs +++ b/src/commands/preview/mod.rs @@ -1,5 +1,5 @@ +use crate::deser; use crate::prelude::*; -use crate::serializer; use clap::Args; use crossterm::style::{style, Stylize}; use std::process; @@ -14,7 +14,7 @@ pub struct Input { } fn extract_elements(argstr: &str) -> Result<(&str, &str, &str)> { - let mut parts = argstr.split(serializer::DELIMITER).skip(3); + let mut parts = argstr.split(deser::terminal::DELIMITER).skip(3); let tags = parts.next().context("No `tags` element provided.")?; let comment = parts.next().context("No `comment` element provided.")?; let snippet = parts.next().context("No `snippet` element provided.")?; @@ -31,7 +31,7 @@ impl Runnable for Input { "{comment} {tags} \n{snippet}", comment = style(comment).with(CONFIG.comment_color()), tags = style(format!("[{}]", tags)).with(CONFIG.tag_color()), - snippet = style(serializer::fix_newlines(snippet)).with(CONFIG.snippet_color()), + snippet = style(deser::fix_newlines(snippet)).with(CONFIG.snippet_color()), ); process::exit(0) diff --git a/src/commands/preview/var.rs b/src/commands/preview/var.rs index e99dcce9..8dd809bc 100644 --- a/src/commands/preview/var.rs +++ b/src/commands/preview/var.rs @@ -1,7 +1,7 @@ +use crate::deser; use crate::env_var; use crate::finder; use crate::prelude::*; -use crate::serializer; use clap::Args; use crossterm::style::style; use crossterm::style::Stylize; @@ -49,10 +49,7 @@ impl Runnable for Input { let bracketed_variables: Vec<&str> = { if snippet.contains(&bracketed_current_variable) { - serializer::VAR_REGEX - .find_iter(&snippet) - .map(|m| m.as_str()) - .collect() + deser::VAR_REGEX.find_iter(&snippet).map(|m| m.as_str()).collect() } else { iter::once(&bracketed_current_variable) .map(|s| s.as_str()) @@ -98,7 +95,7 @@ impl Runnable for Input { ); } - println!("{snippet}", snippet = serializer::fix_newlines(&colored_snippet)); + println!("{snippet}", snippet = deser::fix_newlines(&colored_snippet)); println!("{variables}", variables = variables); process::exit(0) diff --git a/src/commands/shell.rs b/src/commands/shell.rs index 60d70b28..2d7ba3e0 100644 --- a/src/commands/shell.rs +++ b/src/commands/shell.rs @@ -3,7 +3,7 @@ use clap::Args; use crate::common::shell::Shell; use crate::prelude::*; -const WIDGET_POSSIBLE_VALUES: &[&str] = &["bash", "zsh", "fish", "elvish"]; +const POSSIBLE_VALUES: &[&str] = &["bash", "zsh", "fish", "elvish"]; impl FromStr for Shell { type Err = &'static str; @@ -21,7 +21,7 @@ impl FromStr for Shell { #[derive(Debug, Clone, Args)] pub struct Input { - #[clap(possible_values = WIDGET_POSSIBLE_VALUES, ignore_case = true, default_value = "bash")] + #[clap(possible_values = POSSIBLE_VALUES, ignore_case = true, default_value = "bash")] pub shell: Shell, } @@ -41,3 +41,10 @@ impl Runnable for Input { Ok(()) } } + +#[test] +fn test_possible_values() { + for v in POSSIBLE_VALUES { + assert!(Shell::from_str(v).is_ok()) + } +} diff --git a/src/commands/temp.rs b/src/commands/temp.rs index efcdd16c..dab41921 100644 --- a/src/commands/temp.rs +++ b/src/commands/temp.rs @@ -2,11 +2,11 @@ use crate::commands::core::get_fetcher; use crate::common::shell::{self, ShellSpawnError}; use crate::finder::structures::Opts as FinderOpts; use crate::parser::Parser; -use crate::{prelude::*, serializer}; +use crate::{deser, prelude::*}; use std::io::{self, Write}; pub fn main() -> Result<()> { - let config = &CONFIG; + let _config = &CONFIG; let _opts = FinderOpts::snippet_default(); let fetcher = get_fetcher()?; @@ -22,7 +22,7 @@ pub fn main() -> Result<()> { let variables = parser.variables; let item_str = String::from_utf8(buf)?; - let item = serializer::raycast_deser(&item_str)?; + let item = deser::raycast::read(&item_str)?; dbg!(&item); let x = variables.get_suggestion(&item.tags, "local_branch").expect("foo"); @@ -49,7 +49,7 @@ pub fn main() -> Result<()> { } pub fn _main0() -> Result<()> { - let config = &CONFIG; + let _config = &CONFIG; let fetcher = get_fetcher()?; diff --git a/src/config/cli.rs b/src/config/cli.rs index 9a8c4db1..ab07e7af 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -1,10 +1,8 @@ use crate::commands; -use crate::finder::FinderChoice; +use crate::finder::{self, FinderChoice}; use crate::prelude::*; use clap::{crate_version, AppSettings, Parser, Subcommand}; -const FINDER_POSSIBLE_VALUES: &[&str] = &["fzf", "skim"]; - #[derive(Debug, Parser)] #[clap(after_help = "\x1b[0;33mMORE INFO:\x1b[0;0m Please refer to \x1b[0;32mhttps://github.com/denisidoro/navi\x1b[0;0m @@ -80,7 +78,7 @@ pub(super) struct ClapConfig { pub fzf_overrides_var: Option, /// Finder application to use - #[clap(long, possible_values = FINDER_POSSIBLE_VALUES, ignore_case = true)] + #[clap(long, possible_values = finder::POSSIBLE_VALUES, ignore_case = true)] pub finder: Option, #[clap(subcommand)] @@ -127,38 +125,3 @@ pub enum Action { Print, Execute, } - -/* -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_widget_possible_values() { - for v in WIDGET_POSSIBLE_VALUES { - assert!(Shell::from_str(v).is_ok()) - } - } - - #[test] - fn test_info_possible_values() { - for v in INFO_POSSIBLE_VALUES { - assert!(Info::from_str(v).is_ok()) - } - } - - #[test] - fn test_func_possible_values() { - for v in FUNC_POSSIBLE_VALUES { - assert!(Func::from_str(v).is_ok()) - } - } - - #[test] - fn test_finder_possible_values() { - for v in FINDER_POSSIBLE_VALUES { - assert!(FinderChoice::from_str(v).is_ok()) - } - } -} -*/ diff --git a/src/deser/mod.rs b/src/deser/mod.rs new file mode 100644 index 00000000..c97f7f20 --- /dev/null +++ b/src/deser/mod.rs @@ -0,0 +1,34 @@ +use crate::prelude::*; + +pub mod raycast; +pub mod terminal; + +const NEWLINE_ESCAPE_CHAR: char = '\x15'; +pub const LINE_SEPARATOR: &str = " \x15 "; + +lazy_static! { + pub static ref NEWLINE_REGEX: Regex = Regex::new(r"\\\s+").expect("Invalid regex"); + pub static ref VAR_REGEX: Regex = Regex::new(r"\\?<(\w[\w\d\-_]*)>").expect("Invalid regex"); +} + +pub fn with_new_lines(txt: String) -> String { + txt.replace(LINE_SEPARATOR, "\n") +} + +pub fn fix_newlines(txt: &str) -> String { + if txt.contains(NEWLINE_ESCAPE_CHAR) { + (*NEWLINE_REGEX) + .replace_all(txt.replace(LINE_SEPARATOR, " ").as_str(), "") + .to_string() + } else { + txt.to_string() + } +} + +fn limit_str(text: &str, length: usize) -> String { + if text.len() > length { + format!("{}…", text.chars().take(length - 1).collect::()) + } else { + format!("{:width$}", text, width = length) + } +} diff --git a/src/deser/raycast.rs b/src/deser/raycast.rs new file mode 100644 index 00000000..a738c015 --- /dev/null +++ b/src/deser/raycast.rs @@ -0,0 +1,51 @@ +use super::*; +use crate::structures::item::Item; + +const FIELD_SEP_ESCAPE_CHAR: char = '\x16'; + +pub fn write(item: &Item) -> String { + format!( + "{hash}{delimiter}{tags}{delimiter}{comment}{delimiter}{icon}{delimiter}{snippet}\n", + hash = item.hash(), + tags = item.tags, + comment = item.comment, + delimiter = FIELD_SEP_ESCAPE_CHAR, + icon = item.icon.clone().unwrap_or_default(), + snippet = &item.snippet.trim_end_matches(LINE_SEPARATOR), + ) +} + +pub fn read(line: &str) -> Result { + let mut parts = line.split(FIELD_SEP_ESCAPE_CHAR); + let hash: u64 = parts + .next() + .context("no hash")? + .parse() + .context("hash not a u64")?; + let tags = parts.next().context("no tags")?.into(); + let comment = parts.next().context("no comment")?.into(); + let icon_str = parts.next().context("no icon")?; + let snippet = parts.next().context("no snippet")?.into(); + + let icon = if icon_str.is_empty() { + None + } else { + Some(icon_str.into()) + }; + + let item = Item { + tags, + comment, + icon, + snippet, + ..Default::default() + }; + + if item.hash() != hash { + dbg!(&item.hash()); + dbg!(hash); + Err(anyhow!("Incorrect hash")) + } else { + Ok(item) + } +} diff --git a/src/deser/terminal.rs b/src/deser/terminal.rs new file mode 100644 index 00000000..3408ff1c --- /dev/null +++ b/src/deser/terminal.rs @@ -0,0 +1,79 @@ +use super::*; +use crate::common::terminal; +use crate::structures::item::Item; +use crossterm::style::{style, Stylize}; +use std::cmp::max; + +pub fn get_widths() -> (usize, usize, usize) { + let width = terminal::width(); + let tag_width_percentage = max( + CONFIG.tag_min_width(), + width * CONFIG.tag_width_percentage() / 100, + ); + let comment_width_percentage = max( + CONFIG.comment_min_width(), + width * CONFIG.comment_width_percentage() / 100, + ); + let snippet_width_percentage = max( + CONFIG.snippet_min_width(), + width * CONFIG.snippet_width_percentage() / 100, + ); + ( + usize::from(tag_width_percentage), + usize::from(comment_width_percentage), + usize::from(snippet_width_percentage), + ) +} + +pub const DELIMITER: &str = r" ⠀"; + +lazy_static! { + pub static ref COLUMN_WIDTHS: (usize, usize, usize) = get_widths(); +} + +pub fn write(item: &Item) -> String { + let (tag_width_percentage, comment_width_percentage, snippet_width_percentage) = *COLUMN_WIDTHS; + format!( + "{tags_short}{delimiter}{comment_short}{delimiter}{snippet_short}{delimiter}{tags}{delimiter}{comment}{delimiter}{snippet}{delimiter}{file_index}{delimiter}\n", + tags_short = style(limit_str(&item.tags, tag_width_percentage)).with(CONFIG.tag_color()), + comment_short = style(limit_str(&item.comment, comment_width_percentage)).with(CONFIG.comment_color()), + snippet_short = style(limit_str(&fix_newlines(&item.snippet), snippet_width_percentage)).with(CONFIG.snippet_color()), + tags = item.tags, + comment = item.comment, + delimiter = DELIMITER, + snippet = &item.snippet.trim_end_matches(LINE_SEPARATOR), + file_index = item.file_index.unwrap_or(0), + ) +} + +pub fn read(raw_snippet: &str, is_single: bool) -> Result<(&str, Item)> { + let mut lines = raw_snippet.split('\n'); + let key = if is_single { + "enter" + } else { + lines + .next() + .context("Key was promised but not present in `selections`")? + }; + + let mut parts = lines + .next() + .context("No more parts in `selections`")? + .split(DELIMITER) + .skip(3); + + let tags = parts.next().unwrap_or("").into(); + let comment = parts.next().unwrap_or("").into(); + let snippet = parts.next().unwrap_or("").into(); + let file_index = parts.next().unwrap_or("").parse().ok(); + + let item = Item { + tags, + comment, + snippet, + file_index, + ..Default::default() + }; + + Ok((key, item)) +} diff --git a/src/finder/mod.rs b/src/finder/mod.rs index 455342fc..2b33e6bf 100644 --- a/src/finder/mod.rs +++ b/src/finder/mod.rs @@ -1,6 +1,5 @@ +use crate::deser; use crate::prelude::*; -use crate::serializer; - use std::io::Write; use std::process::{self, Output}; use std::process::{Command, Stdio}; @@ -17,6 +16,8 @@ pub enum FinderChoice { Skim, } +pub const POSSIBLE_VALUES: &[&str] = &["fzf", "skim"]; + impl FromStr for FinderChoice { type Err = &'static str; @@ -78,7 +79,7 @@ impl FinderChoice { "--with-nth", "1,2,3", "--delimiter", - serializer::DELIMITER.to_string().as_str(), + deser::terminal::DELIMITER.to_string().as_str(), "--ansi", "--bind", format!("ctrl-j:down,ctrl-k:up{}", bindings).as_str(), @@ -189,3 +190,10 @@ impl FinderChoice { Ok((output, return_value)) } } + +#[test] +fn test_possible_values() { + for v in POSSIBLE_VALUES { + assert!(FinderChoice::from_str(v).is_ok()) + } +} diff --git a/src/lib.rs b/src/lib.rs index af261085..cbae52d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,14 +7,13 @@ mod clients; mod commands; mod common; mod config; +mod deser; mod env_var; mod filesystem; mod finder; mod parser; mod prelude; -mod serializer; mod structures; -mod terminal; mod welcome; pub use commands::handle; diff --git a/src/parser.rs b/src/parser.rs index 557b6a56..085c990e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ use crate::common::fs; +use crate::deser; use crate::finder::structures::{Opts as FinderOpts, SuggestionType}; use crate::prelude::*; -use crate::serializer; use crate::structures::cheat::VariableMap; use crate::structures::item::Item; use std::io::Write; @@ -162,9 +162,9 @@ fn gen_lists(tag_rules: &str) -> FilterOpts { impl<'a> Parser<'a> { pub fn new(writer: &'a mut dyn Write, is_terminal: bool) -> Self { let write_fn = if is_terminal { - serializer::write + deser::terminal::write } else { - serializer::write_raw + deser::raycast::write }; let filter = match CONFIG.tag_rules() { @@ -256,7 +256,7 @@ impl<'a> Parser<'a> { // blank if line.is_empty() { if !(&item.snippet).is_empty() { - item.snippet.push_str(serializer::LINE_SEPARATOR); + item.snippet.push_str(deser::LINE_SEPARATOR); } } // tag @@ -309,7 +309,7 @@ impl<'a> Parser<'a> { // snippet else { if !(&item.snippet).is_empty() { - item.snippet.push_str(serializer::LINE_SEPARATOR); + item.snippet.push_str(deser::LINE_SEPARATOR); } item.snippet.push_str(&line); } diff --git a/src/serializer.rs b/src/serializer.rs deleted file mode 100644 index 7f0cbaf1..00000000 --- a/src/serializer.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::common::terminal; -use crate::prelude::*; -use crate::structures::item::Item; -use crossterm::style::{style, Stylize}; -use std::cmp::max; - -pub fn get_widths() -> (usize, usize, usize) { - let width = terminal::width(); - let tag_width_percentage = max( - CONFIG.tag_min_width(), - width * CONFIG.tag_width_percentage() / 100, - ); - let comment_width_percentage = max( - CONFIG.comment_min_width(), - width * CONFIG.comment_width_percentage() / 100, - ); - let snippet_width_percentage = max( - CONFIG.snippet_min_width(), - width * CONFIG.snippet_width_percentage() / 100, - ); - ( - usize::from(tag_width_percentage), - usize::from(comment_width_percentage), - usize::from(snippet_width_percentage), - ) -} - -const NEWLINE_ESCAPE_CHAR: char = '\x15'; -const FIELD_SEP_ESCAPE_CHAR: char = '\x16'; -pub const LINE_SEPARATOR: &str = " \x15 "; -pub const DELIMITER: &str = r" ⠀"; - -lazy_static! { - pub static ref NEWLINE_REGEX: Regex = Regex::new(r"\\\s+").expect("Invalid regex"); - pub static ref VAR_REGEX: Regex = Regex::new(r"\\?<(\w[\w\d\-_]*)>").expect("Invalid regex"); - pub static ref COLUMN_WIDTHS: (usize, usize, usize) = get_widths(); -} - -pub fn with_new_lines(txt: String) -> String { - txt.replace(LINE_SEPARATOR, "\n") -} - -pub fn fix_newlines(txt: &str) -> String { - if txt.contains(NEWLINE_ESCAPE_CHAR) { - (*NEWLINE_REGEX) - .replace_all(txt.replace(LINE_SEPARATOR, " ").as_str(), "") - .to_string() - } else { - txt.to_string() - } -} - -fn limit_str(text: &str, length: usize) -> String { - if text.len() > length { - format!("{}…", text.chars().take(length - 1).collect::()) - } else { - format!("{:width$}", text, width = length) - } -} - -pub fn write(item: &Item) -> String { - let (tag_width_percentage, comment_width_percentage, snippet_width_percentage) = *COLUMN_WIDTHS; - format!( - "{tags_short}{delimiter}{comment_short}{delimiter}{snippet_short}{delimiter}{tags}{delimiter}{comment}{delimiter}{snippet}{delimiter}{file_index}{delimiter}\n", - tags_short = style(limit_str(&item.tags, tag_width_percentage)).with(CONFIG.tag_color()), - comment_short = style(limit_str(&item.comment, comment_width_percentage)).with(CONFIG.comment_color()), - snippet_short = style(limit_str(&fix_newlines(&item.snippet), snippet_width_percentage)).with(CONFIG.snippet_color()), - tags = item.tags, - comment = item.comment, - delimiter = DELIMITER, - snippet = &item.snippet.trim_end_matches(LINE_SEPARATOR), - file_index = item.file_index.unwrap_or(0), - ) -} - -pub fn write_raw(item: &Item) -> String { - format!( - "{hash}{delimiter}{tags}{delimiter}{comment}{delimiter}{icon}{delimiter}{snippet}\n", - hash = item.hash(), - tags = item.tags, - comment = item.comment, - delimiter = FIELD_SEP_ESCAPE_CHAR, - icon = item.icon.clone().unwrap_or_default(), - snippet = &item.snippet.trim_end_matches(LINE_SEPARATOR), - ) -} - -pub fn raycast_deser(line: &str) -> Result { - let mut parts = line.split(FIELD_SEP_ESCAPE_CHAR); - let hash: u64 = parts - .next() - .context("no hash")? - .parse() - .context("hash not a u64")?; - let tags = parts.next().context("no tags")?.into(); - let comment = parts.next().context("no comment")?.into(); - let icon_str = parts.next().context("no icon")?; - let snippet = parts.next().context("no snippet")?.into(); - - let icon = if icon_str.is_empty() { - None - } else { - Some(icon_str.into()) - }; - - let item = Item { - tags, - comment, - icon, - snippet, - ..Default::default() - }; - - if item.hash() != hash { - dbg!(&item.hash()); - dbg!(hash); - Err(anyhow!("Incorrect hash")) - } else { - Ok(item) - } -} diff --git a/src/terminal.rs b/src/terminal.rs deleted file mode 100644 index 8b137891..00000000 --- a/src/terminal.rs +++ /dev/null @@ -1 +0,0 @@ -