Skip to content

Commit

Permalink
Correctly indent lists directly after header on first format
Browse files Browse the repository at this point in the history
  • Loading branch information
Terr committed Nov 11, 2024
1 parent c733707 commit 7d0f273
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 17 deletions.
4 changes: 3 additions & 1 deletion src/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ pub fn wrap_long_lines(formatted_lines: &mut Vec<FormattedLine>, max_line_length
}

// Find a word boundary to split the string at
let Some(split_pos) = find_word_boundary(current_line, max_line_length) else { continue; };
let Some(split_pos) = find_word_boundary(current_line, max_line_length) else {
continue;
};

// This FormattedLine will be placed below (line index + 1) the `current_line` in
// the document
Expand Down
13 changes: 11 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,31 @@ impl Default for Document {
pub struct Block {
contents: Vec<FormattedLine>,
header: FormattedLine,
is_before_first_header: bool,
}

impl Block {
pub fn new(header: FormattedLine) -> Self {
let is_before_first_header = header.is_empty();

Block {
header,
contents: Vec::new(),
is_before_first_header,
}
}

pub fn add_line(&mut self, line: FormattedLine) {
self.contents.push(line);
}

fn indent_level(&self) -> usize {
self.header.indent_level
/// Returns the indentation level of the text contents the `Block` and sibling headers
fn contents_indent_level(&self) -> usize {
if self.is_before_first_header {
0
} else {
self.header.indent_level + 1
}
}

fn has_header(&self) -> bool {
Expand Down
6 changes: 3 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,16 @@ mod tests {

#[test]
fn format_full_document() {
let actual = format_file(Path::new("tests/1.input"));
let expected = read_file(Path::new("tests/1.expected")).unwrap();
let actual = format_file(Path::new("tests/full_document.input"));
let expected = read_file(Path::new("tests/full_document.expected")).unwrap();

assert_equal(&actual, &expected);
}

/// Formatting a text for a second time should not result in a different output
#[test]
fn format_full_document_twice() {
let first_format = format_file(Path::new("tests/1.input"));
let first_format = format_file(Path::new("tests/full_document.input"));
let second_format = format(&first_format);

assert_equal(&second_format, &first_format);
Expand Down
25 changes: 14 additions & 11 deletions src/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub fn parse_document(contents: &str) -> Document {
// Preserve the existing indenting of the text/code in these lines that would
// otherwise be trimmed off.
FormattedLine {
indent_level: current_block.indent_level() + 1,
indent_level: current_block.contents_indent_level(),
line_type: LineType::Preformatted,
contents: format!(
"{preformat_indent}{text}",
Expand Down Expand Up @@ -89,16 +89,16 @@ fn determine_new_header_indent(document: &Document, raw_line: &RawLine) -> usize

match previous_block.raw_header_indent().cmp(&raw_line.num_indent) {
// New header is a sibling (at the same level) of the previous header
Ordering::Equal => previous_block.indent_level(),
Ordering::Equal => previous_block.contents_indent_level().saturating_sub(1),

// New header is a parent of *a* previous header
Ordering::Greater => document
.find_latest_block_with_raw_indent(raw_line.num_indent)
.map(|block| block.indent_level())
.map(|block| block.contents_indent_level().saturating_sub(1))
.unwrap_or(0),

// New header is a child of the previous header
Ordering::Less => previous_block.indent_level() + 1,
Ordering::Less => previous_block.contents_indent_level(),
}
}

Expand All @@ -120,12 +120,15 @@ fn determine_new_bullet_point_indent(current_block: &Block, raw_line: &RawLine)
Ordering::Equal => previous_list_item.indent_level,

// List item is shifted one or more levels to the left compared to the previous
// bullet point in the list. Find the first line (starting from the last line)
// that had the same indenting in the original raw file.
// bullet point in the list. This can mean the previous list was interrupted by some
// text, signalling the end of that list and meaning that this is a new list.
//
// Find the first line (starting from the last line) that had the same indenting in the
// original raw file.
Ordering::Greater => current_block
.find_latest_line_with_raw_indent(raw_line.num_indent)
.map(|line| line.indent_level)
.unwrap_or(current_block.indent_level() + 1),
.unwrap_or(current_block.contents_indent_level()),

// List item is shifted right compared to the previous bullet point. Only one
// level of indenting per line can be added per line.
Expand All @@ -134,7 +137,7 @@ fn determine_new_bullet_point_indent(current_block: &Block, raw_line: &RawLine)
} else if let Some(previous_text) = current_block.find_previous_of(LineType::Text) {
previous_text.indent_level
} else {
0
current_block.contents_indent_level()
}
}

Expand All @@ -153,16 +156,16 @@ fn parse_text_line(current_block: &mut Block, raw_line: RawLine) -> FormattedLin
}
} else if current_block.has_header() {
// Non-bullet list Contents of a block follow the block's indent level plus one
FormattedLine::from_raw(raw_line, current_block.indent_level() + 1)
FormattedLine::from_raw(raw_line, current_block.contents_indent_level())
} else {
// This applies to empty lines and to lines of text that are placed before the
// very first header of the document.

FormattedLine::from_raw(raw_line, current_block.indent_level())
FormattedLine::from_raw(raw_line, current_block.contents_indent_level())
}
} else {
// This applies to the first line after a header.

FormattedLine::from_raw(raw_line, current_block.indent_level() + 1)
FormattedLine::from_raw(raw_line, current_block.contents_indent_level())
}
}
5 changes: 5 additions & 0 deletions tests/bullet_points.expected
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,8 @@ Text.
* Bullet point 4.1
* Bullet point 4.1.1
* Bullet point 5

=== Header 2

* Bullet point 1
* Bullet point 2
4 changes: 4 additions & 0 deletions tests/bullet_points.input
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ Text.
* Bullet point 4.1
* Bullet point 4.1.1
* Bullet point 5

=== Header 2
* Bullet point 1
* Bullet point 2
File renamed without changes.
File renamed without changes.

0 comments on commit 7d0f273

Please sign in to comment.