diff --git a/Cargo.lock b/Cargo.lock index 4cced7e..9c1a115 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,7 +174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "navi" -version = "2.6.0" +version = "2.6.1" dependencies = [ "anyhow 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 78f519a..368d50d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "navi" -version = "2.6.0" +version = "2.6.1" authors = ["Denis Isidoro "] edition = "2018" description = "An interactive cheatsheet tool for the command-line" diff --git a/alfred/alfred.bash b/alfred/alfred.bash index 1fe2cf9..7ab181f 100755 --- a/alfred/alfred.bash +++ b/alfred/alfred.bash @@ -2,8 +2,8 @@ source "${HOME}/.bashrc" -if [ -n "${snippet:-}" ]; then - navi alfred suggestions +if [ -n "${snippet:-}" ]; then + navi alfred suggestions else - navi alfred start + navi alfred start fi diff --git a/alfred/alfred2.bash b/alfred/alfred2.bash index 16e38f1..9b50c7a 100755 --- a/alfred/alfred2.bash +++ b/alfred/alfred2.bash @@ -1,15 +1,9 @@ #!/bin/bash -_interpolate() { - local -r snippet="$1" - local -r varname="$2" - local -r value="${!varname}" +source "${HOME}/.bashrc" - echo "$snippet" | sed "s/<${varname}>/${value}/g" -} - -if [ -n "${varname:-}" ]; then - echo -n "$(_interpolate "$snippet" "$varname" || echo "")" +if [ -n "${varname:-}" ]; then + echo -n "$(navi alfred transform)" else - echo -n "$snippet" + echo -n "$snippet" fi diff --git a/alfred/info.plist b/alfred/info.plist index 12d84b4..3d2ca3f 100644 --- a/alfred/info.plist +++ b/alfred/info.plist @@ -165,6 +165,19 @@ version 1 + + config + + triggerid + play + + type + alfred.workflow.trigger.external + uid + 55C46852-4807-4374-95AB-CC055F4ECB7C + version + 1 + config @@ -311,19 +324,6 @@ fi version 3 - - config - - triggerid - play - - type - alfred.workflow.trigger.external - uid - 55C46852-4807-4374-95AB-CC055F4ECB7C - version - 1 - config diff --git a/scripts/fix b/scripts/fix index 4f5eb14..d70605e 100755 --- a/scripts/fix +++ b/scripts/fix @@ -17,6 +17,8 @@ cargo fmt || true header "dot code beautify..." find scripts -type f | xargs -I% dot code beautify % || true +dot code beautify "${NAVI_HOME}/alfred/alfred.bash" || true +dot code beautify "${NAVI_HOME}/alfred/alfred2.bash" || true dot code beautify "${NAVI_HOME}/tests/core.bash" || true dot code beautify "${NAVI_HOME}/tests/run" || true diff --git a/src/display.rs b/src/display.rs deleted file mode 100644 index abb5eba..0000000 --- a/src/display.rs +++ /dev/null @@ -1,117 +0,0 @@ -use crate::structures::item::Item; -use crate::terminal; -use regex::Regex; -use std::cmp::max; -use termion::color; - -const COMMENT_COLOR: color::LightCyan = color::LightCyan; -const TAG_COLOR: color::Blue = color::Blue; -const SNIPPET_COLOR: color::White = color::White; - -const NEWLINE_ESCAPE_CHAR: char = '\x15'; -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 fn get_widths() -> (usize, usize) { - let width = terminal::width(); - let tag_width = max(4, width * 20 / 100); - let comment_width = max(4, width * 40 / 100); - (usize::from(tag_width), usize::from(comment_width)) -} - -pub fn variable_prompt(varname: &str) -> String { - format!("{}: ", varname) -} - -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() - } -} - -pub fn preview(comment: &str, tags: &str, snippet: &str) { - println!( - "{comment_color}{comment} {tag_color}{tags} \n{snippet_color}{snippet}", - comment = format!("# {}", comment), - tags = format!("[{}]", tags), - snippet = fix_newlines(snippet), - comment_color = color::Fg(COMMENT_COLOR), - tag_color = color::Fg(TAG_COLOR), - snippet_color = color::Fg(SNIPPET_COLOR), - ); -} - -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 trait Writer { - fn write(&mut self, item: Item) -> String; -} - -pub struct FinderWriter { - pub tag_width: usize, - pub comment_width: usize, -} - -pub struct AlfredWriter { - pub is_first: bool, -} - -impl Writer for FinderWriter { - fn write(&mut self, item: Item) -> String { - format!( - "{tag_color}{tags_short}{delimiter}{comment_color}{comment_short}{delimiter}{snippet_color}{snippet_short}{delimiter}{tags}{delimiter}{comment}{delimiter}{snippet}{delimiter}\n", - tags_short = limit_str(item.tags, self.tag_width), - comment_short = limit_str(item.comment, self.comment_width), - snippet_short = fix_newlines(item.snippet), - comment_color = color::Fg(COMMENT_COLOR), - tag_color = color::Fg(TAG_COLOR), - snippet_color = color::Fg(SNIPPET_COLOR), - tags = item.tags, - comment = item.comment, - delimiter = DELIMITER, - snippet = &item.snippet) - } -} - -fn escape_for_json(txt: &str) -> String { - txt.replace('\\', "\\\\") - .replace('"', "\\\"") - .replace(NEWLINE_ESCAPE_CHAR, " ") -} - -impl Writer for AlfredWriter { - fn write(&mut self, item: Item) -> String { - let prefix = if self.is_first { - self.is_first = false; - "" - } else { - "," - }; - - let tags = escape_for_json(item.tags); - let comment = escape_for_json(item.comment); - let snippet = escape_for_json(item.snippet); - - format!( - r#"{prefix}{{"type":"file","title":"{comment}","match":"{comment} {tags} {snippet}","subtitle":"{tags} :: {snippet}","variables":{{"tags":"{tags}","comment":"{comment}","snippet":"{snippet}"}},"icon":{{"path":"navi.png"}}}}"#, - prefix = prefix, - tags = tags, - comment = comment, - snippet = snippet - ) - } -} diff --git a/src/display/alfred.rs b/src/display/alfred.rs new file mode 100644 index 0000000..8ede078 --- /dev/null +++ b/src/display/alfred.rs @@ -0,0 +1,76 @@ +use crate::display::{self, Writer}; +use crate::structures::item::Item; + +pub struct AlfredWriter { + is_first: bool, +} + +pub fn new_writer() -> AlfredWriter { + AlfredWriter { is_first: true } +} + +fn escape_for_json(txt: &str) -> String { + txt.replace('\\', "\\\\") + .replace('"', "\\\"") + .replace(display::NEWLINE_ESCAPE_CHAR, " ") +} + +pub fn print_items_start(varname: Option<&str>) { + print!("{{"); + + if let Some(v) = varname { + print!(r#""variables": {{"varname": "{varname}"}},"#, varname = v); + } + + println!(r#""items": ["#); +} + +pub fn print_items_end() { + println!(r#"]}}"#); +} + +impl Writer for AlfredWriter { + fn write(&mut self, item: Item) -> String { + let prefix = if self.is_first { + self.is_first = false; + "" + } else { + "," + }; + + let tags = escape_for_json(item.tags); + let comment = escape_for_json(item.comment); + let snippet = escape_for_json(item.snippet); + + format!( + r#"{prefix}{{"type":"file","title":"{comment}","match":"{comment} {tags} {snippet}","subtitle":"{tags} :: {snippet}","variables":{{"tags":"{tags}","comment":"{comment}","snippet":"{snippet}"}},"icon":{{"path":"navi.png"}}}}"#, + prefix = prefix, + tags = tags, + comment = comment, + snippet = snippet + ) + } +} + +impl AlfredWriter { + pub fn write_suggestion(&mut self, snippet: &str, varname: &str, line: &str) { + if line.len() < 3 { + return; + } + + let prefix = if self.is_first { + self.is_first = false; + "" + } else { + "," + }; + + println!( + r#"{prefix}{{"title":"{value}","subtitle":"{snippet}","variables":{{"{varname}":"{value}"}},"icon":{{"path":"navi.png"}}}}"#, + prefix = prefix, + snippet = snippet, + varname = varname, + value = line + ); + } +} diff --git a/src/display/mod.rs b/src/display/mod.rs new file mode 100644 index 0000000..9e26b9a --- /dev/null +++ b/src/display/mod.rs @@ -0,0 +1,28 @@ +use crate::structures::item::Item; +use regex::Regex; + +pub mod alfred; +pub mod terminal; + +const NEWLINE_ESCAPE_CHAR: char = '\x15'; +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 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() + } +} + +pub trait Writer { + fn write(&mut self, item: Item) -> String; +} diff --git a/src/display/terminal.rs b/src/display/terminal.rs new file mode 100644 index 0000000..acea822 --- /dev/null +++ b/src/display/terminal.rs @@ -0,0 +1,62 @@ +use crate::display::{self, Writer}; +use crate::structures::item::Item; +use crate::terminal_width; +use termion::color; + +const COMMENT_COLOR: color::LightCyan = color::LightCyan; +const TAG_COLOR: color::Blue = color::Blue; +const SNIPPET_COLOR: color::White = color::White; + +pub fn variable_prompt(varname: &str) -> String { + format!("{}: ", varname) +} + +pub fn preview(comment: &str, tags: &str, snippet: &str) { + println!( + "{comment_color}{comment} {tag_color}{tags} \n{snippet_color}{snippet}", + comment = format!("# {}", comment), + tags = format!("[{}]", tags), + snippet = display::fix_newlines(snippet), + comment_color = color::Fg(COMMENT_COLOR), + tag_color = color::Fg(TAG_COLOR), + snippet_color = color::Fg(SNIPPET_COLOR), + ); +} + +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 struct TerminalWriter { + tag_width: usize, + comment_width: usize, +} + +pub fn new_writer() -> TerminalWriter { + let (tag_width, comment_width) = terminal_width::get_widths(); + display::terminal::TerminalWriter { + tag_width, + comment_width, + } +} + +impl Writer for TerminalWriter { + fn write(&mut self, item: Item) -> String { + format!( + "{tag_color}{tags_short}{delimiter}{comment_color}{comment_short}{delimiter}{snippet_color}{snippet_short}{delimiter}{tags}{delimiter}{comment}{delimiter}{snippet}{delimiter}\n", + tags_short = limit_str(item.tags, self.tag_width), + comment_short = limit_str(item.comment, self.comment_width), + snippet_short = display::fix_newlines(item.snippet), + comment_color = color::Fg(COMMENT_COLOR), + tag_color = color::Fg(TAG_COLOR), + snippet_color = color::Fg(SNIPPET_COLOR), + tags = item.tags, + comment = item.comment, + delimiter = display::DELIMITER, + snippet = &item.snippet) + } +} diff --git a/src/flows/alfred.rs b/src/flows/alfred.rs index a0c994c..54a6b3e 100644 --- a/src/flows/alfred.rs +++ b/src/flows/alfred.rs @@ -1,31 +1,27 @@ +use crate::display; use crate::parser; use crate::structures::cheat::Suggestion; - use crate::structures::{error::command::BashSpawnError, option::Config}; use anyhow::Context; use anyhow::Error; -use regex::Regex; - use std::env; - use std::process::{Command, Stdio}; -lazy_static! { - pub static ref VAR_REGEX: Regex = Regex::new(r"<(\w[\w\d\-_]*)>").expect("Invalid regex"); -} - pub fn main(config: Config) -> Result<(), Error> { - let mut child = Command::new("cat").stdin(Stdio::piped()).spawn().unwrap(); - let stdin = child.stdin.as_mut().unwrap(); + let mut child = Command::new("cat") + .stdin(Stdio::piped()) + .spawn() + .context("Unable to create child")?; + let stdin = child.stdin.as_mut().context("Unable to get stdin")?; - println!(r#"{{"items": ["#); + display::alfred::print_items_start(None); parser::read_all(&config, stdin).context("Failed to parse variables intended for finder")?; + // make sure everything was printed to stdout before attempting to close the items vector let _ = child.wait_with_output().context("Failed to wait for fzf")?; - println!(r#"]}}"#); - + display::alfred::print_items_end(); Ok(()) } @@ -59,26 +55,22 @@ pub fn suggestions(config: Config) -> Result<(), Error> { .stdin(Stdio::piped()) .stdout(Stdio::null()) .spawn() - .unwrap(); - let stdin = child.stdin.as_mut().unwrap(); + .context("Unable to create child")?; + let stdin = child.stdin.as_mut().context("Unable to get stdin")?; let variables = parser::read_all(&config, stdin) .context("Failed to parse variables intended for finder")?; - let tags = env::var("tags").unwrap(); - let _comment = env::var("comment").unwrap(); - let snippet = env::var("snippet").unwrap(); + let tags = env::var("tags").context(r#"The env var "tags" isn't set"#)?; + let snippet = env::var("snippet").context(r#"The env var "snippet" isn't set"#)?; - let varname = VAR_REGEX.captures_iter(&snippet).next(); + let varname = display::VAR_REGEX.captures_iter(&snippet).next(); if let Some(varname) = varname { let varname = &varname[0]; let varname = &varname[1..varname.len() - 1]; - println!( - r#"{{"variables": {{"varname": "{varname}"}}, "items": ["#, - varname = varname - ); + display::alfred::print_items_start(Some(varname)); let lines = variables .get(&tags, &varname) @@ -87,36 +79,28 @@ pub fn suggestions(config: Config) -> Result<(), Error> { Ok(prompt_with_suggestions(&varname, &config, suggestion).unwrap()) })?; - let mut is_first = true; + let mut writer = display::alfred::new_writer(); + for line in lines.split('\n') { - if line.len() < 3 { - continue; - } - - let prefix = if is_first { - is_first = false; - "" - } else { - "," - }; - - println!( - r#"{prefix}{{"title":"{value}","subtitle":"{snippet}","variables":{{"{varname}":"{value}"}},"icon":{{"path":"navi.png"}}}}"#, - prefix = prefix, - snippet = snippet, - varname = varname, - value = line - ); + writer.write_suggestion(&snippet, &varname, &line); } } else { - println!(r#"{{"items": ["#); + display::alfred::print_items_start(None); } - println!(r#"]}}"#); + display::alfred::print_items_end(); Ok(()) } -pub fn transform(_config: Config) -> Result<(), Error> { +pub fn transform() -> Result<(), Error> { + let snippet = env::var("snippet").context(r#"The env var "snippet" isn't set"#)?; + let varname = env::var("varname").context(r#"The env var "varname" isn't set"#)?; + let value = env::var(&varname).context(format!(r#"The env var "{}" isn't set"#, &varname))?; + + let bracketed_varname = format!("<{}>", varname); + let interpolated_snippet = snippet.replace(&bracketed_varname, &value); + println!("{}", interpolated_snippet); + Ok(()) } diff --git a/src/flows/core.rs b/src/flows/core.rs index bacd7aa..5b3fb2a 100644 --- a/src/flows/core.rs +++ b/src/flows/core.rs @@ -10,16 +10,11 @@ use crate::structures::option; use crate::structures::{error::command::BashSpawnError, option::Config}; use anyhow::Context; use anyhow::Error; -use regex::Regex; use std::env; use std::fs; use std::io::Write; use std::process::{Command, Stdio}; -lazy_static! { - pub static ref VAR_REGEX: Regex = Regex::new(r"<(\w[\w\d\-_]*)>").expect("Invalid regex"); -} - pub enum Variant { Core, Filter(String), @@ -71,14 +66,6 @@ fn extract_from_selections(raw_snippet: &str, contains_key: bool) -> (&str, &str (key, tags, snippet) } -/* fn gen_opts_preview(snippet: &str, variable_name: &str) -> Option { - Some(format!( - r#"query="{{}}"; [[ "${{#query:-}}" -lt 3 ]] && query="{{q}}"; query="${{query:1:${{#query}}-2}}"; query="$(echo "$query" | sed 's|/|\\/|g')"; echo "{}" | sed "s/<{}>/${{query}}/g" || echo 'Unable to generate command preview'"#, - snippet.replace('"', "\\\""), - variable_name - )) -} */ - fn prompt_with_suggestions( variable_name: &str, config: &Config, @@ -106,7 +93,7 @@ fn prompt_with_suggestions( let opts = FinderOpts { autoselect: !config.no_autoselect, overrides: config.fzf_overrides_var.clone(), - prompt: Some(display::variable_prompt(variable_name)), + prompt: Some(display::terminal::variable_prompt(variable_name)), ..opts }; @@ -130,9 +117,8 @@ fn prompt_without_suggestions( ) -> Result { let opts = FinderOpts { autoselect: false, - prompt: Some(display::variable_prompt(variable_name)), + prompt: Some(display::terminal::variable_prompt(variable_name)), suggestion_type: SuggestionType::Disabled, - // preview: gen_opts_preview(&snippet, &variable_name), preview_window: Some("up:1".to_string()), ..Default::default() }; @@ -153,7 +139,7 @@ fn replace_variables_from_snippet( ) -> Result { let mut interpolated_snippet = String::from(snippet); - for captures in VAR_REGEX.captures_iter(snippet) { + for captures in display::VAR_REGEX.captures_iter(snippet) { let bracketed_variable_name = &captures[0]; let variable_name = &bracketed_variable_name[1..bracketed_variable_name.len() - 1]; @@ -226,7 +212,7 @@ pub fn main(variant: Variant, config: Config, contains_key: bool) -> Result<(), println!("{}", interpolated_snippet); // save to file } else if let Some(s) = config.save { - fs::write(s, interpolated_snippet).context("Unable to save config")?; + fs::write(s, interpolated_snippet).context("Unable to save output")?; // call navi (this prevents "failed to read /dev/tty" from finder) } else if interpolated_snippet.starts_with("navi") { let new_config = option::config_from_iter(interpolated_snippet.split(' ').collect()); diff --git a/src/flows/preview.rs b/src/flows/preview.rs index 95a8dd3..36aa3c2 100644 --- a/src/flows/preview.rs +++ b/src/flows/preview.rs @@ -12,6 +12,6 @@ fn extract_elements(argstr: &str) -> (&str, &str, &str) { pub fn main(line: &str) -> Result<(), Error> { let (tags, comment, snippet) = extract_elements(line); - display::preview(comment, tags, snippet); + display::terminal::preview(comment, tags, snippet); process::exit(0) } diff --git a/src/handler.rs b/src/handler.rs index 57e3cb4..6099493 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -43,7 +43,7 @@ pub fn handle_config(config: Config) -> Result<(), Error> { Alfred { cmd } => match cmd { AlfredCommand::Start => flows::alfred::main(config), AlfredCommand::Suggestions => flows::alfred::suggestions(config), - AlfredCommand::Transform => flows::alfred::transform(config), + AlfredCommand::Transform => flows::alfred::transform(), }, }, } diff --git a/src/lib.rs b/src/lib.rs index 250f069..5137b02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ mod git; mod handler; mod parser; mod structures; -mod terminal; +mod terminal_width; mod welcome; pub use handler::handle_config; diff --git a/src/parser.rs b/src/parser.rs index aa1023b..c6ac960 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -116,7 +116,7 @@ fn write_cmd( tags: &str, comment: &str, snippet: &str, - writer: &mut Box, + writer: &mut dyn Writer, stdin: &mut std::process::ChildStdin, ) -> Result<(), Error> { if snippet.len() <= 1 { @@ -137,7 +137,7 @@ fn read_file( path: &str, variables: &mut VariableMap, visited_lines: &mut HashSet, - writer: &mut Box, + writer: &mut dyn Writer, stdin: &mut std::process::ChildStdin, ) -> Result<(), Error> { let mut tags = String::from(""); @@ -235,18 +235,14 @@ pub fn read_all( let mut found_something = false; let mut visited_lines = HashSet::new(); let mut writer: Box = if let Some(Alfred { .. }) = &config.cmd { - Box::new(display::AlfredWriter { is_first: true }) + Box::new(display::alfred::new_writer()) } else { - let (tag_width, comment_width) = display::get_widths(); - Box::new(display::FinderWriter { - tag_width, - comment_width, - }) + Box::new(display::terminal::new_writer()) }; let paths = filesystem::cheat_paths(config); if paths.is_err() { - welcome::cheatsheet(&mut writer, stdin); + welcome::cheatsheet(&mut *writer, stdin); return Ok(variables); } @@ -266,7 +262,7 @@ pub fn read_all( path_str, &mut variables, &mut visited_lines, - &mut writer, + &mut *writer, stdin, ) .is_ok() @@ -280,7 +276,7 @@ pub fn read_all( } if !found_something { - welcome::cheatsheet(&mut writer, stdin); + welcome::cheatsheet(&mut *writer, stdin); } Ok(variables) @@ -314,18 +310,19 @@ mod tests { fn test_read_file() { let path = "tests/cheats/ssh.cheat"; let mut variables = VariableMap::new(); - let mut child = Command::new("cat").stdin(Stdio::piped()).spawn().unwrap(); + let mut child = Command::new("cat") + .stdin(Stdio::piped()) + .stdout(Stdio::null()) + .spawn() + .unwrap(); let child_stdin = child.stdin.as_mut().unwrap(); let mut visited_lines: HashSet = HashSet::new(); - let mut writer: Box = Box::new(display::FinderWriter { - comment_width: 20, - tag_width: 30, - }); + let mut writer: Box = Box::new(display::terminal::new_writer()); read_file( path, &mut variables, &mut visited_lines, - &mut writer, + &mut *writer, child_stdin, ) .unwrap(); diff --git a/src/structures/error/file_issue.rs b/src/structures/error/file_issue.rs index 007319a..40d468f 100644 --- a/src/structures/error/file_issue.rs +++ b/src/structures/error/file_issue.rs @@ -3,7 +3,7 @@ use thiserror::Error; #[derive(Error, Debug)] #[error( - "\rHey, listen! Navi encountered a problem. + "\rHey, listen! navi encountered a problem. Do you think this is a bug? File an issue at https://github.com/denisidoro/navi." )] pub struct FileAnIssue { diff --git a/src/structures/option.rs b/src/structures/option.rs index 41518ef..595f126 100644 --- a/src/structures/option.rs +++ b/src/structures/option.rs @@ -11,7 +11,10 @@ fn parse_finder(src: &str) -> Result { } #[derive(Debug, StructOpt)] -#[structopt(after_help = r#"EXAMPLES: +#[structopt(after_help = r#"MORE INFO: + Please refer to https://github.com/denisidoro/navi + +EXAMPLES: navi # default behavior navi --print # doesn't execute the snippet navi --path '/some/dir:/other/dir' # uses custom cheats @@ -106,7 +109,8 @@ pub enum Command { /// bash, zsh or fish shell: String, }, - /// Alfred + /// Helper command for Alfred integration + #[structopt(setting = AppSettings::Hidden)] Alfred { #[structopt(subcommand)] cmd: AlfredCommand, @@ -126,11 +130,11 @@ pub enum RepoCommand { #[derive(Debug, StructOpt)] pub enum AlfredCommand { - /// Start + /// Outputs a JSON with commands Start, - /// Suggestions + /// Outputs a JSON with variable suggestions Suggestions, - /// Transform + /// Transforms the snippet env var with the selected value Transform, } diff --git a/src/terminal.rs b/src/terminal_width.rs similarity index 85% rename from src/terminal.rs rename to src/terminal_width.rs index 353e16e..f0dacda 100644 --- a/src/terminal.rs +++ b/src/terminal_width.rs @@ -1,3 +1,4 @@ +use std::cmp::max; use terminal_size::{terminal_size, terminal_size_using_fd, Height, Width}; fn width_with_shell_out() -> u16 { @@ -53,7 +54,7 @@ fn width_with_fd() -> u16 { } } -pub fn width() -> u16 { +fn width() -> u16 { let size = terminal_size(); if let Some((Width(w), Height(_))) = size { w @@ -61,3 +62,10 @@ pub fn width() -> u16 { width_with_fd() } } + +pub fn get_widths() -> (usize, usize) { + let width = width(); + let tag_width = max(4, width * 20 / 100); + let comment_width = max(4, width * 40 / 100); + (usize::from(tag_width), usize::from(comment_width)) +} diff --git a/src/welcome.rs b/src/welcome.rs index 726e630..221b854 100644 --- a/src/welcome.rs +++ b/src/welcome.rs @@ -6,7 +6,7 @@ fn add_msg( tags: &str, comment: &str, snippet: &str, - writer: &mut Box, + writer: &mut dyn Writer, stdin: &mut std::process::ChildStdin, ) { let item = Item { @@ -19,7 +19,7 @@ fn add_msg( .expect("Could not write to fzf's stdin"); } -pub fn cheatsheet(writer: &mut Box, stdin: &mut std::process::ChildStdin) { +pub fn cheatsheet(writer: &mut dyn Writer, stdin: &mut std::process::ChildStdin) { add_msg( "cheatsheets", "Download default cheatsheets",