Skip to content

Commit e0de513

Browse files
authored
Merge pull request #229 from edwardloveall/el-bullet-style
Add bullet list style options
2 parents e23a579 + 3e493e0 commit e0de513

File tree

5 files changed

+106
-8
lines changed

5 files changed

+106
-8
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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ pub use html::Anchorizer;
112112
pub use parser::{
113113
parse_document, parse_document_with_broken_link_callback, ComrakExtensionOptions,
114114
ComrakOptions, ComrakParseOptions, ComrakPlugins, ComrakRenderOptions, ComrakRenderPlugins,
115+
ListStyleType,
115116
};
116117
pub use typed_arena::Arena;
117118

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 (-, +, *) in CommonMark ouput"),
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: 54 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,29 @@ pub struct ComrakRenderOptions {
437437
/// "<p>&lt;i&gt;italic text&lt;/i&gt;</p>\n");
438438
/// ```
439439
pub escape: bool,
440+
441+
/// Set the type of [bullet list marker](https://spec.commonmark.org/0.30/#bullet-list-marker) to use. Options are:
442+
///
443+
/// * `ListStyleType::Dash` to use `-` (default)
444+
/// * `ListStyleType::Plus` to use `+`
445+
/// * `ListStyleType::Star` to use `*`
446+
///
447+
/// ```rust
448+
/// # use comrak::{markdown_to_commonmark, ComrakOptions, ListStyleType};
449+
/// let mut options = ComrakOptions::default();
450+
/// let input = "- one\n- two\n- three";
451+
/// assert_eq!(markdown_to_commonmark(input, &options),
452+
/// "- one\n- two\n- three\n"); // default is Dash
453+
///
454+
/// options.render.list_style = ListStyleType::Plus;
455+
/// assert_eq!(markdown_to_commonmark(input, &options),
456+
/// "+ one\n+ two\n+ three\n");
457+
///
458+
/// options.render.list_style = ListStyleType::Star;
459+
/// assert_eq!(markdown_to_commonmark(input, &options),
460+
/// "* one\n* two\n* three\n");
461+
/// ```
462+
pub list_style: ListStyleType,
440463
}
441464

442465
#[derive(Default, Debug)]
@@ -1891,3 +1914,33 @@ pub enum AutolinkType {
18911914
URI,
18921915
Email,
18931916
}
1917+
1918+
#[derive(Debug, Clone, Copy)]
1919+
/// Options for bulleted list redering in markdown. See `link_style` in [ComrakRenderOptions] for more details.
1920+
pub enum ListStyleType {
1921+
/// The `-` character
1922+
Dash = 45,
1923+
/// The `+` character
1924+
Plus = 43,
1925+
/// The `*` character
1926+
Star = 42,
1927+
}
1928+
1929+
impl Default for ListStyleType {
1930+
fn default() -> Self {
1931+
ListStyleType::Dash
1932+
}
1933+
}
1934+
1935+
impl FromStr for ListStyleType {
1936+
type Err = ();
1937+
1938+
fn from_str(input: &str) -> Result<ListStyleType, Self::Err> {
1939+
match input {
1940+
"dash" => Ok(ListStyleType::Dash),
1941+
"plus" => Ok(ListStyleType::Plus),
1942+
"star" => Ok(ListStyleType::Star),
1943+
_ => Err(()),
1944+
}
1945+
}
1946+
}

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)