Skip to content

Commit 64b8173

Browse files
committed
Add bullet list style options
This change adds a new option `--list-style` so users can choose which character all bulleted lists use for their marker. The [commonmark spec] supports three options for bullet markers: `-`, `*`, `+` which is also now the case here. Previously, when comrak (or cmark-gfm) rendered markdown, it would pick `-` which is now the default. This also adds the ability to optionally provide custom ComrakOptions when testing. If the defaults are fine, you can pass `None`. [commonmark spec]: https://spec.commonmark.org/0.30/#bullet-list-marker
1 parent e23a579 commit 64b8173

File tree

5 files changed

+84
-9
lines changed

5 files changed

+84
-9
lines changed

src/cm.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,8 @@ impl<'a, 'o> CommonMarkFormatter<'a, 'o> {
411411

412412
if entering {
413413
if parent.list_type == ListType::Bullet {
414-
write!(self, "- ").unwrap();
414+
let bullet = char::from(self.options.render.list_style as u8);
415+
write!(self, "{} ", bullet).unwrap();
415416
} else {
416417
self.write_all(&listmarker).unwrap();
417418
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub use html::format_document_with_plugins as format_html_with_plugins;
111111
pub use html::Anchorizer;
112112
pub use parser::{
113113
parse_document, parse_document_with_broken_link_callback, ComrakExtensionOptions,
114-
ComrakOptions, ComrakParseOptions, ComrakPlugins, ComrakRenderOptions, ComrakRenderPlugins,
114+
ComrakOptions, ComrakParseOptions, ComrakPlugins, ComrakRenderOptions, ComrakRenderPlugins, ListStyleType
115115
};
116116
pub use typed_arena::Arena;
117117

src/main.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extern crate xdg;
1111

1212
use comrak::{
1313
Arena, ComrakExtensionOptions, ComrakOptions, ComrakParseOptions, ComrakPlugins,
14-
ComrakRenderOptions,
14+
ComrakRenderOptions, ListStyleType
1515
};
1616

1717
use comrak::adapters::SyntaxHighlighterAdapter;
@@ -161,6 +161,15 @@ if the file does not exist.\
161161
.value_name("THEME")
162162
.help("Syntax highlighting for codefence blocks. Choose a theme or 'none' for disabling.")
163163
.default_value("base16-ocean.dark"),
164+
)
165+
.arg(
166+
clap::Arg::with_name("list-style")
167+
.long("list-style")
168+
.takes_value(true)
169+
.possible_values(&["dash", "plus", "star"])
170+
.default_value("dash")
171+
.value_name("LIST_STYLE")
172+
.help("Specify bullet character for lists (-, +, *)"),
164173
);
165174

166175
let mut matches = app.clone().get_matches();
@@ -220,6 +229,11 @@ if the file does not exist.\
220229
.unwrap_or(0),
221230
unsafe_: matches.is_present("unsafe"),
222231
escape: matches.is_present("escape"),
232+
list_style: matches
233+
.value_of("list-style")
234+
.unwrap_or("dash")
235+
.parse::<ListStyleType>()
236+
.expect("unknown list style")
223237
},
224238
};
225239

src/parser/mod.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::cmp::min;
1818
use std::collections::HashMap;
1919
use std::fmt::{Debug, Formatter};
2020
use std::mem;
21-
use std::str;
21+
use std::str::{self, FromStr};
2222
use strings;
2323
use typed_arena::Arena;
2424

@@ -437,6 +437,9 @@ pub struct ComrakRenderOptions {
437437
/// "<p>&lt;i&gt;italic text&lt;/i&gt;</p>\n");
438438
/// ```
439439
pub escape: bool,
440+
441+
/// TODO: docs
442+
pub list_style: ListStyleType,
440443
}
441444

442445
#[derive(Default, Debug)]
@@ -1891,3 +1894,31 @@ pub enum AutolinkType {
18911894
URI,
18921895
Email,
18931896
}
1897+
1898+
#[derive(Debug, Clone, Copy)]
1899+
/// TODO: docs
1900+
pub enum ListStyleType {
1901+
/// TODO: docs
1902+
Dash = 45,
1903+
/// TODO: docs
1904+
Plus = 43,
1905+
/// TODO: docs
1906+
Star = 42,
1907+
}
1908+
1909+
impl Default for ListStyleType {
1910+
fn default() -> Self { ListStyleType::Dash }
1911+
}
1912+
1913+
impl FromStr for ListStyleType {
1914+
type Err = ();
1915+
1916+
fn from_str(input: &str) -> Result<ListStyleType, Self::Err> {
1917+
match input {
1918+
"dash" => Ok(ListStyleType::Dash),
1919+
"plus" => Ok(ListStyleType::Plus),
1920+
"star" => Ok(ListStyleType::Star),
1921+
_ => Err(()),
1922+
}
1923+
}
1924+
}

src/tests.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ fn fuzz_doesnt_crash(md: String) {
3737
width: 80,
3838
unsafe_: true,
3939
escape: false,
40+
list_style: ::ListStyleType::Dash
4041
},
4142
};
4243

@@ -62,12 +63,12 @@ fn compare_strs(output: &str, expected: &str, kind: &str) {
6263
}
6364

6465
#[track_caller]
65-
fn commonmark(input: &str, expected: &str) {
66+
fn commonmark(input: &str, expected: &str, opts: Option<&::ComrakOptions>) {
6667
let arena = ::Arena::new();
67-
let mut options = ::ComrakOptions::default();
68-
options.render.width = 72;
68+
let defaults = ::ComrakOptions::default();
69+
let options = opts.unwrap_or(&defaults);
6970

70-
let root = ::parse_document(&arena, input, &options);
71+
let root = ::parse_document(&arena, input, options);
7172
let mut output = vec![];
7273
cm::format_document(root, &options, &mut output).unwrap();
7374
compare_strs(&String::from_utf8(output).unwrap(), expected, "regular");
@@ -253,6 +254,31 @@ fn lists() {
253254
);
254255
}
255256

257+
#[test]
258+
fn markdown_list_bullets() {
259+
let dash = concat!("- a\n");
260+
let plus = concat!("+ a\n");
261+
let star = concat!("* a\n");
262+
let mut dash_opts = ::ComrakOptions::default();
263+
dash_opts.render.list_style = ::ListStyleType::Dash;
264+
let mut plus_opts = ::ComrakOptions::default();
265+
plus_opts.render.list_style = ::ListStyleType::Plus;
266+
let mut star_opts = ::ComrakOptions::default();
267+
star_opts.render.list_style = ::ListStyleType::Star;
268+
269+
commonmark(dash, dash, Some(&dash_opts));
270+
commonmark(plus, dash, Some(&dash_opts));
271+
commonmark(star, dash, Some(&dash_opts));
272+
273+
commonmark(dash, plus, Some(&plus_opts));
274+
commonmark(plus, plus, Some(&plus_opts));
275+
commonmark(star, plus, Some(&plus_opts));
276+
277+
commonmark(dash, star, Some(&star_opts));
278+
commonmark(plus, star, Some(&star_opts));
279+
commonmark(star, star, Some(&star_opts));
280+
}
281+
256282
#[test]
257283
fn thematic_breaks() {
258284
html(
@@ -263,6 +289,8 @@ fn thematic_breaks() {
263289

264290
#[test]
265291
fn width_breaks() {
292+
let mut options = ::ComrakOptions::default();
293+
options.render.width = 72;
266294
let input = concat!(
267295
"this should break because it has breakable characters. break right here newline\n",
268296
"\n",
@@ -279,7 +307,7 @@ fn width_breaks() {
279307
"a-long-line-that-won't-break-because-there-is-no-character-it-can-break-on\n"
280308
);
281309

282-
commonmark(input, output);
310+
commonmark(input, output, Some(&options));
283311
}
284312

285313
#[test]
@@ -1272,6 +1300,7 @@ fn exercise_full_api<'a>() {
12721300
width: 123456,
12731301
unsafe_: false,
12741302
escape: false,
1303+
list_style: ::ListStyleType::Dash,
12751304
},
12761305
};
12771306

0 commit comments

Comments
 (0)