Decide headline nesting by star count, not headline level.

It is possible to have two headlines that have the same level but different star counts when set to Odd because of rounding. Deciding nesting by star count instead of headline level avoids this issue.
This commit is contained in:
Tom Alexander 2023-09-20 03:22:25 -04:00
parent 4c8d9a3063
commit 9bcfb2f1da
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
5 changed files with 35 additions and 19 deletions

View File

@ -41,9 +41,9 @@ function main {
set -e
if [ "$all_status" -ne 0 ]; then
echo "$(red_text "Some tests failed.")"
red_text "Some tests failed."
else
echo "$(green_text "All tests passed.")"
green_text "All tests passed."
fi
return "$all_status"
}
@ -64,8 +64,9 @@ function indent {
local depth="$1"
local scaled_depth=$((depth * 2))
shift 1
local prefix=$(printf -- "%${scaled_depth}s")
while read l; do
local prefix
prefix=$(printf -- "%${scaled_depth}s")
while read -r l; do
(IFS=' '; printf -- '%s%s\n' "$prefix" "$l")
done
}
@ -93,12 +94,13 @@ function compare_all_org_document {
local target_document
local all_status=0
while read target_document; do
local relative_path=$($REALPATH --relative-to "$root_dir" "$target_document")
local relative_path
relative_path=$($REALPATH --relative-to "$root_dir" "$target_document")
set +e
(run_compare "$relative_path" "$target_document")
if [ "$?" -ne 0 ]; then all_status=1; fi
set -e
done<<<$(find "$root_dir" -type f -iname '*.org')
done<<<"$(find "$root_dir" -type f -iname '*.org' | sort)"
return "$all_status"
}

View File

@ -5,3 +5,4 @@
*** Lorem
* Ipsum
**** Dolar
***** Cat

View File

@ -34,12 +34,13 @@ use crate::parser::object_parser::standard_set_object;
use crate::parser::util::blank_line;
use crate::types::DocumentElement;
use crate::types::Heading;
use crate::types::HeadlineLevel;
use crate::types::Object;
use crate::types::PriorityCookie;
use crate::types::TodoKeywordType;
pub(crate) const fn heading(
parent_level: usize,
parent_level: HeadlineLevel,
) -> impl for<'b, 'g, 'r, 's> Fn(
RefContext<'b, 'g, 'r, 's>,
OrgSource<'s>,
@ -51,15 +52,23 @@ pub(crate) const fn heading(
fn _heading<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
parent_level: usize,
parent_star_count: HeadlineLevel,
) -> Res<OrgSource<'s>, Heading<'s>> {
not(|i| context.check_exit_matcher(i))(input)?;
let (
remaining,
(headline_level, maybe_todo_keyword, maybe_priority, maybe_comment, title, heading_tags),
) = headline(context, input, parent_level)?;
(
headline_level,
star_count,
maybe_todo_keyword,
maybe_priority,
maybe_comment,
title,
heading_tags,
),
) = headline(context, input, parent_star_count)?;
let section_matcher = parser_with_context!(section)(context);
let heading_matcher = parser_with_context!(heading(headline_level))(context);
let heading_matcher = parser_with_context!(heading(star_count))(context);
let (remaining, maybe_section) =
opt(map(section_matcher, DocumentElement::Section))(remaining)?;
let (remaining, _ws) = opt(tuple((start_of_line, many0(blank_line))))(remaining)?;
@ -106,11 +115,12 @@ pub(crate) fn detect_headline<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()
fn headline<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
parent_level: usize,
parent_star_count: HeadlineLevel,
) -> Res<
OrgSource<'s>,
(
usize,
HeadlineLevel,
HeadlineLevel,
Option<(TodoKeywordType, OrgSource<'s>)>,
Option<(OrgSource<'s>, PriorityCookie)>,
Option<OrgSource<'s>>,
@ -124,11 +134,11 @@ fn headline<'b, 'g, 'r, 's>(
});
let parser_context = context.with_additional_node(&parser_context);
let (remaining, (_, (star_count, _), _)) = tuple((
let (remaining, (_, (headline_level, star_count, _), _)) = tuple((
start_of_line,
verify(
parser_with_context!(headline_level)(&parser_context),
|(level, _)| *level > parent_level,
|(_, count, _)| *count > parent_star_count,
),
peek(org_space),
))(input)?;
@ -159,6 +169,7 @@ fn headline<'b, 'g, 'r, 's>(
Ok((
remaining,
(
headline_level,
star_count,
maybe_todo_keyword.map(|(_, todo, _)| todo),
maybe_priority,
@ -261,9 +272,9 @@ fn priority_cookie<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, PriorityCooki
fn headline_level<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, (usize, OrgSource<'s>)> {
) -> Res<OrgSource<'s>, (HeadlineLevel, HeadlineLevel, OrgSource<'s>)> {
let (remaining, stars) = is_a("*")(input)?;
let count = stars.len();
let count = stars.len().try_into().unwrap();
let level = match context.get_global_settings().odd_levels_only {
crate::context::HeadlineLevelFilter::Odd => {
if count % 2 == 0 {
@ -274,5 +285,5 @@ fn headline_level<'b, 'g, 'r, 's>(
}
crate::context::HeadlineLevelFilter::OddEven => count,
};
Ok((remaining, (level, stars)))
Ok((remaining, (level, count, stars)))
}

View File

@ -3,6 +3,7 @@ use super::Object;
use super::Source;
pub type PriorityCookie = u8;
pub type HeadlineLevel = u16;
#[derive(Debug)]
pub struct Document<'s> {
@ -14,7 +15,7 @@ pub struct Document<'s> {
#[derive(Debug)]
pub struct Heading<'s> {
pub source: &'s str,
pub level: usize,
pub level: HeadlineLevel,
pub todo_keyword: Option<(TodoKeywordType, &'s str)>,
pub priority_cookie: Option<PriorityCookie>,
pub title: Vec<Object<'s>>,

View File

@ -7,6 +7,7 @@ mod source;
pub use document::Document;
pub use document::DocumentElement;
pub use document::Heading;
pub use document::HeadlineLevel;
pub use document::PriorityCookie;
pub use document::Section;
pub use document::TodoKeywordType;