diff --git a/Cargo.lock b/Cargo.lock index f56ed097..60995fd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,6 +68,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + [[package]] name = "byteorder" version = "1.4.3" @@ -92,7 +98,7 @@ version = "4.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" dependencies = [ - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex", "is-terminal", @@ -133,6 +139,7 @@ dependencies = [ "derive_builder", "emojis", "entities", + "in-place", "memchr", "ntest", "once_cell", @@ -295,12 +302,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.8.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "flate2" @@ -368,22 +372,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "indexmap" -version = "1.9.2" +name = "in-place" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "1cdb69f3adfd5f493210cece799f4620417bf9965bc1536c22ae0e29ba27a8c0" dependencies = [ - "autocfg", - "hashbrown", + "tempfile", ] [[package]] -name = "instant" -version = "0.1.12" +name = "indexmap" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ - "cfg-if", + "autocfg", + "hashbrown", ] [[package]] @@ -404,7 +408,7 @@ checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" dependencies = [ "hermit-abi", "io-lifetimes", - "rustix", + "rustix 0.36.17", "windows-sys 0.42.0", ] @@ -422,9 +426,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "line-wrap" @@ -447,6 +451,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + [[package]] name = "memchr" version = "2.5.0" @@ -516,7 +526,7 @@ version = "6.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "once_cell", "onig_sys", @@ -654,7 +664,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12e6c80c1139113c28ee4670dc50cc42915228b51f56a9e407f0ec60f966646f" dependencies = [ "bit-set", - "bitflags", + "bitflags 1.3.2", "byteorder", "lazy_static", "num-traits", @@ -738,7 +748,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -775,14 +785,27 @@ version = "0.36.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.1.4", "windows-sys 0.45.0", ] +[[package]] +name = "rustix" +version = "0.38.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", +] + [[package]] name = "rusty-fork" version = "0.3.0" @@ -889,7 +912,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6c454c27d9d7d9a84c7803aaa3c50cd088d2906fe3c6e42da3209aa623576a8" dependencies = [ "bincode", - "bitflags", + "bitflags 1.3.2", "fancy-regex", "flate2", "fnv", @@ -908,15 +931,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.4.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.42.0", + "rustix 0.38.32", + "windows-sys 0.52.0", ] [[package]] @@ -934,7 +956,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907" dependencies = [ - "rustix", + "rustix 0.36.17", "windows-sys 0.42.0", ] diff --git a/Cargo.toml b/Cargo.toml index b46dbd72..07dd531c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "comrak" version = "0.22.0" authors = ["Amelia Cuss "] +rust-version = "1.62.1" description = "A 100% CommonMark-compatible GitHub Flavored Markdown parser and formatter" documentation = "https://docs.rs/comrak" homepage = "https://hrzn.ee/kivikakk/comrak" @@ -45,6 +46,7 @@ slug = "0.1.4" emojis = { version = "0.5.2", optional = true } arbitrary = { version = "1", optional = true, features = ["derive"] } derive_builder = "0.12.0" +in-place = { version = "0.2.0", optional = true } [dev-dependencies] ntest = "0.9" @@ -54,7 +56,7 @@ propfuzz = "0.0.1" [features] default = ["cli", "syntect"] -cli = ["clap", "shell-words", "xdg"] +cli = ["clap", "shell-words", "xdg", "in-place"] shortcodes = ["emojis"] [target.'cfg(all(not(windows), not(target_arch="wasm32")))'.dependencies] diff --git a/src/cm.rs b/src/cm.rs index 17b30888..192d2aa2 100644 --- a/src/cm.rs +++ b/src/cm.rs @@ -576,14 +576,12 @@ impl<'a, 'o> CommonMarkFormatter<'a, 'o> { fn format_line_break(&mut self, entering: bool, next_is_block: bool) { if entering { - if !self.options.render.hardbreaks { - if !next_is_block { - // If the next element is a block, a backslash means a - // literal backslash instead of a line break. In this case - // we can just skip the line break since it's meaningless - // before a block. - write!(self, "\\").unwrap(); - } + if !self.options.render.hardbreaks && !next_is_block { + // If the next element is a block, a backslash means a + // literal backslash instead of a line break. In this case + // we can just skip the line break since it's meaningless + // before a block. + write!(self, "\\").unwrap(); } self.cr(); } diff --git a/src/main.rs b/src/main.rs index cd8d049b..24c2e136 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,10 +14,12 @@ use std::path::PathBuf; use std::process; use clap::{Parser, ValueEnum}; +use in_place::InPlace; const EXIT_SUCCESS: i32 = 0; const EXIT_PARSE_CONFIG: i32 = 2; const EXIT_READ_INPUT: i32 = 3; +const EXIT_CHECK_FILE_NUM: i32 = 4; #[derive(Debug, Parser)] #[command(about, author, version)] @@ -35,6 +37,10 @@ struct Cli { #[arg(short, long, value_name = "PATH", default_value = get_default_config_path())] config_file: String, + /// To perform an in-place formatting + #[arg(short, long, conflicts_with_all(["format", "output"]))] + inplace: bool, + /// Treat newlines as hard line breaks #[arg(long)] hardbreaks: bool, @@ -204,6 +210,18 @@ fn cli_with_config() -> Cli { fn main() -> Result<(), Box> { let cli = cli_with_config(); + if cli.inplace { + if let Some(ref files) = cli.files { + if files.len() != 1 { + eprintln!("cannot have more than 1 input file with in-place mode"); + process::exit(EXIT_CHECK_FILE_NUM); + } + } else { + eprintln!("no input file specified: cannot use standard input with in-place mode"); + process::exit(EXIT_CHECK_FILE_NUM); + } + } + let exts = &cli.extensions; let mut extension = ExtensionOptionsBuilder::default(); @@ -272,8 +290,8 @@ fn main() -> Result<(), Box> { None => { std::io::stdin().read_to_end(&mut s)?; } - Some(fs) => { - for f in &fs { + Some(ref fs) => { + for f in fs { match fs::File::open(f) { Ok(mut io) => { io.read_to_end(&mut s)?; @@ -290,19 +308,29 @@ fn main() -> Result<(), Box> { let arena = Arena::new(); let root = comrak::parse_document(&arena, &String::from_utf8(s)?, &options); - let formatter = match cli.format { - Format::Html => { - plugins.render.codefence_syntax_highlighter = syntax_highlighter; - comrak::format_html_with_plugins + let formatter = if cli.inplace { + comrak::format_commonmark_with_plugins + } else { + match cli.format { + Format::Html => { + plugins.render.codefence_syntax_highlighter = syntax_highlighter; + comrak::format_html_with_plugins + } + Format::Xml => comrak::format_xml_with_plugins, + Format::CommonMark => comrak::format_commonmark_with_plugins, } - Format::Xml => comrak::format_xml_with_plugins, - Format::CommonMark => comrak::format_commonmark_with_plugins, }; if let Some(output_filename) = cli.output { let mut bw = BufWriter::new(fs::File::create(output_filename)?); formatter(root, &options, &mut bw, &plugins)?; bw.flush()?; + } else if cli.inplace { + let inp: in_place::InPlaceFile = + InPlace::new(unsafe { cli.files.unwrap_unchecked().get_unchecked(0) }).open()?; + let mut bw = inp.writer(); + formatter(root, &options, &mut bw, &plugins)?; + inp.save()?; } else { let stdout = std::io::stdout(); let mut bw = BufWriter::new(stdout.lock()); diff --git a/src/nodes.rs b/src/nodes.rs index 9884ffca..0e073263 100644 --- a/src/nodes.rs +++ b/src/nodes.rs @@ -290,37 +290,27 @@ pub struct NodeDescriptionItem { } /// The type of list. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum ListType { /// A bullet list, i.e. an unordered list. + #[default] Bullet, /// An ordered list. Ordered, } -impl Default for ListType { - fn default() -> ListType { - ListType::Bullet - } -} - /// The delimiter for ordered lists, i.e. the character which appears after each number. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum ListDelimType { /// A period character `.`. + #[default] Period, /// A paren character `)`. Paren, } -impl Default for ListDelimType { - fn default() -> ListDelimType { - ListDelimType::Period - } -} - impl ListDelimType { pub(crate) fn xml_name(&self) -> &'static str { match *self { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 5848e7e8..3aa16a48 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1482,7 +1482,7 @@ impl<'a, 'o, 'c> Parser<'a, 'o, 'c> { fn parse_html_block_prefix(&mut self, t: u8) -> bool { match t { - 1 | 2 | 3 | 4 | 5 => true, + 1..=5 => true, 6 | 7 => !self.blank, _ => unreachable!(), } @@ -2415,20 +2415,15 @@ pub enum AutolinkType { Email, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] /// Options for bulleted list redering in markdown. See `link_style` in [RenderOptions] for more details. pub enum ListStyleType { /// The `-` character + #[default] Dash = 45, /// The `+` character Plus = 43, /// The `*` character Star = 42, } - -impl Default for ListStyleType { - fn default() -> Self { - ListStyleType::Dash - } -} diff --git a/src/parser/table.rs b/src/parser/table.rs index bfa45b79..fc7ed2db 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -113,7 +113,7 @@ fn try_opening_header<'a>( ast.sourcepos.end = start.column_add((cell.end_offset - header_row.paragraph_offset) as isize); ast.internal_offset = cell.internal_offset; - ast.content = cell.content.clone(); + ast.content.clone_from(&cell.content); i += 1; } @@ -168,7 +168,7 @@ fn try_opening_row<'a>( let cell_ast = &mut cell_node.data.borrow_mut(); cell_ast.internal_offset = cell.internal_offset; cell_ast.sourcepos.end.column = sourcepos.start.column + cell.end_offset; - cell_ast.content = cell.content.clone(); + cell_ast.content.clone_from(&cell.content); last_column = cell_ast.sourcepos.end.column; diff --git a/src/tests.rs b/src/tests.rs index 69d038b4..42d46762 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -87,9 +87,9 @@ where fn html_opts_w(input: &str, expected: &str, options: &Options) { let arena = Arena::new(); - let root = parse_document(&arena, input, &options); + let root = parse_document(&arena, input, options); let mut output = vec![]; - html::format_document(root, &options, &mut output).unwrap(); + html::format_document(root, options, &mut output).unwrap(); compare_strs( &String::from_utf8(output).unwrap(), expected, @@ -102,12 +102,12 @@ fn html_opts_w(input: &str, expected: &str, options: &Options) { } let mut md = vec![]; - cm::format_document(root, &options, &mut md).unwrap(); + cm::format_document(root, options, &mut md).unwrap(); let md_string = &String::from_utf8(md).unwrap(); - let root = parse_document(&arena, md_string, &options); + let root = parse_document(&arena, md_string, options); let mut output_from_rt = vec![]; - html::format_document(root, &options, &mut output_from_rt).unwrap(); + html::format_document(root, options, &mut output_from_rt).unwrap(); compare_strs( &String::from_utf8(output_from_rt).unwrap(), expected, diff --git a/src/tests/pathological.rs b/src/tests/pathological.rs index a979defd..aa73c549 100644 --- a/src/tests/pathological.rs +++ b/src/tests/pathological.rs @@ -6,7 +6,7 @@ use ntest::timeout; #[timeout(4000)] fn pathological_emphases() { let n = 50_000; - let input = format!("{}", "*a_ ".repeat(n)); + let input = "*a_ ".repeat(n).to_string(); let mut exp = format!("

{}", input); // Right-most space is trimmed in output. exp.pop(); @@ -41,8 +41,10 @@ fn pathological_table_columns_2() { "a\n".repeat(n) ); - let mut extension = ExtensionOptions::default(); - extension.table = true; + let extension = parser::ExtensionOptions { + table: true, + ..Default::default() + }; // Not interested in the actual html, just that we don't timeout markdown_to_html(