Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/configuration/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ impl ConfigurationBuilder {
self.insert("unorderedListKind", value.to_string().into())
}

/// The type of heading to use.
/// Default: `HeadingKind::Atx`
pub fn heading_kind(&mut self, value: HeadingKind) -> &mut Self {
self.insert("headingKind", value.to_string().into())
}

/// The directive used to ignore a line.
/// Default: `dprint-ignore`
pub fn ignore_directive(&mut self, value: &str) -> &mut Self {
Expand Down Expand Up @@ -140,13 +146,14 @@ mod tests {
.emphasis_kind(EmphasisKind::Asterisks)
.strong_kind(StrongKind::Underscores)
.unordered_list_kind(UnorderedListKind::Asterisks)
.heading_kind(HeadingKind::Atx)
.ignore_directive("test")
.ignore_file_directive("test")
.ignore_start_directive("test")
.ignore_end_directive("test");

let inner_config = config.get_inner_config();
assert_eq!(inner_config.len(), 10);
assert_eq!(inner_config.len(), 11);
let diagnostics = resolve_config(inner_config, &Default::default()).diagnostics;
assert_eq!(diagnostics.len(), 0);
}
Expand Down
1 change: 1 addition & 0 deletions src/configuration/resolve_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub fn resolve_config(
UnorderedListKind::Dashes,
&mut diagnostics,
),
heading_kind: get_value(&mut config, "headingKind", HeadingKind::Atx, &mut diagnostics),
ignore_directive: get_value(
&mut config,
"ignoreDirective",
Expand Down
18 changes: 18 additions & 0 deletions src/configuration/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub struct Configuration {
pub emphasis_kind: EmphasisKind,
pub strong_kind: StrongKind,
pub unordered_list_kind: UnorderedListKind,
pub heading_kind: HeadingKind,
pub ignore_directive: String,
pub ignore_file_directive: String,
pub ignore_start_directive: String,
Expand Down Expand Up @@ -91,3 +92,20 @@ impl UnorderedListKind {
}

generate_str_to_from![UnorderedListKind, [Dashes, "dashes"], [Asterisks, "asterisks"]];

/// The style of heading to use for level 1 and level headings:
/// [setext](https://spec.commonmark.org/0.31.2/#setext-headings) or
/// [ATX](https://spec.commonmark.org/0.31.2/#atx-headings). Level 3 and
/// higher headings always use ATX headings, since Markdown only supports
/// setext headers for levels 1 and 2.
#[derive(Clone, PartialEq, Copy, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum HeadingKind {
/// Uses an underline of `=` or `-` beneath the heading text for level 1 and
/// 2 headings.
Setext,
/// Uses `#` or `##` before the heading text for level 1 and 2 headings.
Atx,
}

generate_str_to_from![HeadingKind, [Setext, "setext"], [Atx, "atx"]];
29 changes: 27 additions & 2 deletions src/generation/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,33 @@ fn gen_nodes(nodes: &[Node], context: &mut Context) -> PrintItems {
fn gen_heading(heading: &Heading, context: &mut Context) -> PrintItems {
let mut items = PrintItems::new();

items.push_string(format!("{} ", "#".repeat(heading.level as usize)));
items.extend(with_no_new_lines(gen_nodes(&heading.children, context)));
if heading.level < 3 && context.configuration.heading_kind == HeadingKind::Setext {
// setext headings only apply to level 1 and level 2.
//
// First, output the heading text.
let heading_children = gen_nodes(&heading.children, context);
items.extend(heading_children);
items.push_item(PrintItem::Signal(Signal::NewLine));

// Next, create an underline. To produce a visually appealing underline,
// split the heading text (which may contain more than one line) into
// lines, then determine the length of the longest line. Note that this
// length should be determined **after** formatting, since lines may be
// wrapped during the formatting process.
//
// Incorrect -- need some way to get the text of the heading after's its
// been formatted/line wrapped. How to insert some sort of post-processing
// node?
//let heading_text = heading_children.get_as_text();
// For now, use a constant width.
let heading_text = "x".repeat(context.configuration.line_width as usize);
// For now, use constant-width dummy text.
items.push_string((if heading.level == 1 { "=" } else { "-" }).repeat(heading_text.len()));
} else {
// atx headings apply to all levels.
items.push_string(format!("{} ", "#".repeat(heading.level as usize)));
items.extend(with_no_new_lines(gen_nodes(&heading.children, context)));
}

items
}
Expand Down
7 changes: 6 additions & 1 deletion tests/specs/headers/Headers_All.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
~~ lineWidth: 40 ~~
~~ lineWidth: 40, textWrap: always ~~
!! should format the headers !!
# H1

Expand Down Expand Up @@ -37,9 +37,14 @@ Second Header
!! should keep a header on a single line even when it goes over the line width !!
# Testing this out by going over the line width

Verifying that text is wrapping in other places.

[expect]
# Testing this out by going over the line width

Verifying that text is wrapping in other
places.

!! should remove consecutive spaces in the header text !!
# Here is a test

Expand Down
45 changes: 45 additions & 0 deletions tests/specs/headers/Headers_All_Setext.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
~~ lineWidth: 40, headingKind: setext ~~
!! should format the headers !!
# H1

## H2

### H3

#### H4

First Header
============

Second Header
-------------

[expect]
H1
========================================

H2
----------------------------------------

### H3

#### H4

First Header
========================================

Second Header
----------------------------------------

!! Headers are allowed to flow over multiple lines.
This Header
spans
multiple lines
========================================


[expect]
This Header
spans
multiple lines
========================================