diff --git a/Cargo.lock b/Cargo.lock index 70163ac7d..6f3af17ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -951,6 +951,7 @@ dependencies = [ "dirs 3.0.2", "downcast-rs", "edgedb-cli-derive", + "edgedb-cli-md", "edgedb-client", "edgedb-derive", "edgedb-protocol", @@ -1027,9 +1028,9 @@ version = "0.3.0" dependencies = [ "clap", "clap_generate", + "edgedb-cli-md", "heck", "linked-hash-map", - "minimad", "proc-macro-error", "proc-macro2", "quote 1.0.9", @@ -1038,6 +1039,15 @@ dependencies = [ "trybuild", ] +[[package]] +name = "edgedb-cli-md" +version = "0.3.0" +dependencies = [ + "crossterm", + "minimad", + "termimad", +] + [[package]] name = "edgedb-client" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 6b562abae..360f26952 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,6 +79,7 @@ toml = "0.5.8" termimad = "0.10.2" minimad = "0.7.0" edgedb-cli-derive = { path="edgedb-cli-derive" } +edgedb-cli-md = { path="edgedb-cli-md" } fs-err = "2.6.0" pem = "0.8" rustls = {version="0.19.1", features=["dangerous_configuration"]} diff --git a/edgedb-cli-derive/Cargo.toml b/edgedb-cli-derive/Cargo.toml index 82fb9757b..60820c48b 100644 --- a/edgedb-cli-derive/Cargo.toml +++ b/edgedb-cli-derive/Cargo.toml @@ -6,10 +6,10 @@ authors = ["EdgeDB Inc. "] edition = "2018" [dependencies] +edgedb-cli-md = { path="../edgedb-cli-md" } clap = { git="https://github.com/clap-rs/clap" } clap_generate = { git="https://github.com/clap-rs/clap" } termimad = "0.10.2" -minimad = "0.7.0" syn = {version="1.0.72", features=["extra-traits"]} quote = "1.0.9" proc-macro2 = "1.0.19" diff --git a/edgedb-cli-derive/src/attrib.rs b/edgedb-cli-derive/src/attrib.rs index 5aefc4a17..2e6bd6238 100644 --- a/edgedb-cli-derive/src/attrib.rs +++ b/edgedb-cli-derive/src/attrib.rs @@ -8,6 +8,7 @@ use syn::parse::{Parse, Parser, ParseStream}; use syn::punctuated::Punctuated; use syn::token::Paren; +use edgedb_cli_md as mdstyle; use crate::kw; @@ -590,49 +591,18 @@ impl Markdown { }; parser.parse2(attr.tokens.clone()).unwrap_or_abort(); } - pub fn markdown_text(&self) -> String { - let text = self.source.value(); - let mut min_indent = text.len(); - for line in text.lines() { - let stripped = line.trim_start(); - if stripped.is_empty() { - continue; - } - let indent = line.len() - stripped.len(); - if indent < min_indent { - min_indent = indent; - } - } - if min_indent == 0 { - return text; - } - let mut buf = String::with_capacity(text.len()); - for line in text.lines() { - if line.len() > min_indent { - buf.push_str(&line[min_indent..]); - } - buf.push('\n'); - } - return buf; - } pub fn clap_text(&self) -> syn::LitStr { - let markdown = self.markdown_text(); - let text = parse_markdown(&markdown); - let skin = termimad::MadSkin::default(); - let fmt = termimad::FmtText::from_text( - &skin, - text, - None, - ); - syn::LitStr::new(&fmt.to_string(), self.source.span()) + let text = self.source.value(); + syn::LitStr::new(&mdstyle::format_markdown(&text), self.source.span()) } pub fn formatted_title(&self) -> syn::LitStr { - let markdown = self.markdown_text(); - let mut text = parse_markdown(&markdown); + let text = self.source.value(); + let text = mdstyle::prepare_markdown(&text); + let mut text = mdstyle::parse_markdown(&text); if !text.lines.is_empty() { text.lines.drain(1..); } - let skin = termimad::MadSkin::default(); + let skin = mdstyle::make_skin(); let fmt = termimad::FmtText::from_text( &skin, text, @@ -718,47 +688,3 @@ impl CliParse { !matches!(self.kind, FromOccurrences | FromFlag) } } - -fn parse_markdown(text: &str) -> minimad::Text { - use minimad::{Text, Composite}; - use minimad::Line::*; - use minimad::CompositeStyle::*; - - let lines = Text::from(&text[..]).lines; - let mut text = Text { lines: Vec::with_capacity(lines.len()) }; - for line in lines.into_iter() { - if let Normal(Composite { style, compounds: cmps }) = line { - if cmps.len() == 0 { - text.lines.push( - Normal(Composite { style, compounds: cmps }) - ); - continue; - } - match (style, text.lines.last_mut()) { - (_, Some(&mut Normal(Composite { ref compounds , ..}))) - if compounds.len() == 0 - => { - text.lines.push( - Normal(Composite { style, compounds: cmps }) - ); - } - | (Paragraph, Some(&mut Normal(Composite { - style: Paragraph, ref mut compounds }))) - | (Paragraph, Some(&mut Normal(Composite { - style: ListItem, ref mut compounds }))) - | (Quote, Some(&mut Normal(Composite { - style: Quote, ref mut compounds }))) - => { - compounds.push(minimad::Compound::raw_str(" ")); - compounds.extend(cmps); - } - _ => { - text.lines.push( - Normal(Composite { style, compounds: cmps }) - ); - } - } - } - } - return text; -} diff --git a/edgedb-cli-md/.gitignore b/edgedb-cli-md/.gitignore new file mode 100644 index 000000000..2a66ba770 --- /dev/null +++ b/edgedb-cli-md/.gitignore @@ -0,0 +1,3 @@ +/Cargo.lock +/target + diff --git a/edgedb-cli-md/Cargo.toml b/edgedb-cli-md/Cargo.toml new file mode 100644 index 000000000..f1472ecdb --- /dev/null +++ b/edgedb-cli-md/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "edgedb-cli-md" +license = "MIT/Apache-2.0" +version = "0.3.0" +authors = ["EdgeDB Inc. "] +edition = "2018" + +[dependencies] +termimad = "0.10.2" +minimad = "0.7.0" +crossterm = "0.19.0" diff --git a/edgedb-cli-md/src/lib.rs b/edgedb-cli-md/src/lib.rs new file mode 100644 index 000000000..80adce171 --- /dev/null +++ b/edgedb-cli-md/src/lib.rs @@ -0,0 +1,91 @@ +pub fn prepare_markdown(text: &str) -> String { + let mut min_indent = text.len(); + for line in text.lines() { + let stripped = line.trim_start(); + if stripped.is_empty() { + continue; + } + let indent = line.len() - stripped.len(); + if indent < min_indent { + min_indent = indent; + } + } + if min_indent == 0 { + return text.to_string(); + } + let mut buf = String::with_capacity(text.len()); + for line in text.lines() { + if line.len() > min_indent { + buf.push_str(&line[min_indent..]); + } + buf.push('\n'); + } + return buf; +} + +pub fn make_skin() -> termimad::MadSkin { + use crossterm::style::{Color, Attribute}; + let mut skin = termimad::MadSkin::default(); + skin.bold.set_fg(Color::Reset); + skin.inline_code.set_bg(Color::Reset); + skin.inline_code.add_attr(Attribute::Bold); + skin.code_block.set_bg(Color::Reset); + skin.code_block.add_attr(Attribute::Bold); + skin +} + +pub fn parse_markdown(text: &str) -> minimad::Text { + use minimad::{Text, Composite}; + use minimad::Line::*; + use minimad::CompositeStyle::*; + + let lines = Text::from(&text[..]).lines; + let mut text = Text { lines: Vec::with_capacity(lines.len()) }; + for line in lines.into_iter() { + if let Normal(Composite { style, compounds: cmps }) = line { + if cmps.len() == 0 { + text.lines.push( + Normal(Composite { style, compounds: cmps }) + ); + continue; + } + match (style, text.lines.last_mut()) { + (_, Some(&mut Normal(Composite { ref compounds , ..}))) + if compounds.len() == 0 + => { + text.lines.push( + Normal(Composite { style, compounds: cmps }) + ); + } + | (Paragraph, Some(&mut Normal(Composite { + style: Paragraph, ref mut compounds }))) + | (Paragraph, Some(&mut Normal(Composite { + style: ListItem, ref mut compounds }))) + | (Quote, Some(&mut Normal(Composite { + style: Quote, ref mut compounds }))) + => { + compounds.push(minimad::Compound::raw_str(" ")); + compounds.extend(cmps); + } + _ => { + text.lines.push( + Normal(Composite { style, compounds: cmps }) + ); + } + } + } + } + return text; +} + +pub fn format_markdown(text: &str) -> String { + let text = prepare_markdown(&text); + let text = parse_markdown(&text); + let skin = make_skin(); + let fmt = termimad::FmtText::from_text( + &skin, + text, + None, + ); + fmt.to_string() +} diff --git a/src/options.rs b/src/options.rs index 3d7f33a1d..9c6f5f81a 100644 --- a/src/options.rs +++ b/src/options.rs @@ -13,6 +13,8 @@ use edgedb_client::Builder; use edgedb_cli_derive::EdbClap; use fs_err as fs; +use edgedb_cli_md as mdstyle; + use crate::cli; use crate::cli::options::CliCommand; use crate::commands::parser::Common; @@ -500,9 +502,10 @@ fn term_width() -> usize { impl Options { pub fn from_args_and_env() -> anyhow::Result { + let about = mdstyle::format_markdown(&EDGEDB_ABOUT); let app = ::into_app() .name("edgedb") - .about(EDGEDB_ABOUT) + .about(about.as_str()) .term_width(term_width()); let app = update_main_help(app); let matches = get_matches(app);