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:
parent
4c8d9a3063
commit
9bcfb2f1da
@ -41,9 +41,9 @@ function main {
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
if [ "$all_status" -ne 0 ]; then
|
if [ "$all_status" -ne 0 ]; then
|
||||||
echo "$(red_text "Some tests failed.")"
|
red_text "Some tests failed."
|
||||||
else
|
else
|
||||||
echo "$(green_text "All tests passed.")"
|
green_text "All tests passed."
|
||||||
fi
|
fi
|
||||||
return "$all_status"
|
return "$all_status"
|
||||||
}
|
}
|
||||||
@ -64,8 +64,9 @@ function indent {
|
|||||||
local depth="$1"
|
local depth="$1"
|
||||||
local scaled_depth=$((depth * 2))
|
local scaled_depth=$((depth * 2))
|
||||||
shift 1
|
shift 1
|
||||||
local prefix=$(printf -- "%${scaled_depth}s")
|
local prefix
|
||||||
while read l; do
|
prefix=$(printf -- "%${scaled_depth}s")
|
||||||
|
while read -r l; do
|
||||||
(IFS=' '; printf -- '%s%s\n' "$prefix" "$l")
|
(IFS=' '; printf -- '%s%s\n' "$prefix" "$l")
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
@ -93,12 +94,13 @@ function compare_all_org_document {
|
|||||||
local target_document
|
local target_document
|
||||||
local all_status=0
|
local all_status=0
|
||||||
while read target_document; do
|
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
|
set +e
|
||||||
(run_compare "$relative_path" "$target_document")
|
(run_compare "$relative_path" "$target_document")
|
||||||
if [ "$?" -ne 0 ]; then all_status=1; fi
|
if [ "$?" -ne 0 ]; then all_status=1; fi
|
||||||
set -e
|
set -e
|
||||||
done<<<$(find "$root_dir" -type f -iname '*.org')
|
done<<<"$(find "$root_dir" -type f -iname '*.org' | sort)"
|
||||||
return "$all_status"
|
return "$all_status"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,3 +5,4 @@
|
|||||||
*** Lorem
|
*** Lorem
|
||||||
* Ipsum
|
* Ipsum
|
||||||
**** Dolar
|
**** Dolar
|
||||||
|
***** Cat
|
||||||
|
@ -34,12 +34,13 @@ use crate::parser::object_parser::standard_set_object;
|
|||||||
use crate::parser::util::blank_line;
|
use crate::parser::util::blank_line;
|
||||||
use crate::types::DocumentElement;
|
use crate::types::DocumentElement;
|
||||||
use crate::types::Heading;
|
use crate::types::Heading;
|
||||||
|
use crate::types::HeadlineLevel;
|
||||||
use crate::types::Object;
|
use crate::types::Object;
|
||||||
use crate::types::PriorityCookie;
|
use crate::types::PriorityCookie;
|
||||||
use crate::types::TodoKeywordType;
|
use crate::types::TodoKeywordType;
|
||||||
|
|
||||||
pub(crate) const fn heading(
|
pub(crate) const fn heading(
|
||||||
parent_level: usize,
|
parent_level: HeadlineLevel,
|
||||||
) -> impl for<'b, 'g, 'r, 's> Fn(
|
) -> impl for<'b, 'g, 'r, 's> Fn(
|
||||||
RefContext<'b, 'g, 'r, 's>,
|
RefContext<'b, 'g, 'r, 's>,
|
||||||
OrgSource<'s>,
|
OrgSource<'s>,
|
||||||
@ -51,15 +52,23 @@ pub(crate) const fn heading(
|
|||||||
fn _heading<'b, 'g, 'r, 's>(
|
fn _heading<'b, 'g, 'r, 's>(
|
||||||
context: RefContext<'b, 'g, 'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
parent_level: usize,
|
parent_star_count: HeadlineLevel,
|
||||||
) -> Res<OrgSource<'s>, Heading<'s>> {
|
) -> Res<OrgSource<'s>, Heading<'s>> {
|
||||||
not(|i| context.check_exit_matcher(i))(input)?;
|
not(|i| context.check_exit_matcher(i))(input)?;
|
||||||
let (
|
let (
|
||||||
remaining,
|
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 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) =
|
let (remaining, maybe_section) =
|
||||||
opt(map(section_matcher, DocumentElement::Section))(remaining)?;
|
opt(map(section_matcher, DocumentElement::Section))(remaining)?;
|
||||||
let (remaining, _ws) = opt(tuple((start_of_line, many0(blank_line))))(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>(
|
fn headline<'b, 'g, 'r, 's>(
|
||||||
context: RefContext<'b, 'g, 'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
parent_level: usize,
|
parent_star_count: HeadlineLevel,
|
||||||
) -> Res<
|
) -> Res<
|
||||||
OrgSource<'s>,
|
OrgSource<'s>,
|
||||||
(
|
(
|
||||||
usize,
|
HeadlineLevel,
|
||||||
|
HeadlineLevel,
|
||||||
Option<(TodoKeywordType, OrgSource<'s>)>,
|
Option<(TodoKeywordType, OrgSource<'s>)>,
|
||||||
Option<(OrgSource<'s>, PriorityCookie)>,
|
Option<(OrgSource<'s>, PriorityCookie)>,
|
||||||
Option<OrgSource<'s>>,
|
Option<OrgSource<'s>>,
|
||||||
@ -124,11 +134,11 @@ fn headline<'b, 'g, 'r, 's>(
|
|||||||
});
|
});
|
||||||
let parser_context = context.with_additional_node(&parser_context);
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, (_, (star_count, _), _)) = tuple((
|
let (remaining, (_, (headline_level, star_count, _), _)) = tuple((
|
||||||
start_of_line,
|
start_of_line,
|
||||||
verify(
|
verify(
|
||||||
parser_with_context!(headline_level)(&parser_context),
|
parser_with_context!(headline_level)(&parser_context),
|
||||||
|(level, _)| *level > parent_level,
|
|(_, count, _)| *count > parent_star_count,
|
||||||
),
|
),
|
||||||
peek(org_space),
|
peek(org_space),
|
||||||
))(input)?;
|
))(input)?;
|
||||||
@ -159,6 +169,7 @@ fn headline<'b, 'g, 'r, 's>(
|
|||||||
Ok((
|
Ok((
|
||||||
remaining,
|
remaining,
|
||||||
(
|
(
|
||||||
|
headline_level,
|
||||||
star_count,
|
star_count,
|
||||||
maybe_todo_keyword.map(|(_, todo, _)| todo),
|
maybe_todo_keyword.map(|(_, todo, _)| todo),
|
||||||
maybe_priority,
|
maybe_priority,
|
||||||
@ -261,9 +272,9 @@ fn priority_cookie<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, PriorityCooki
|
|||||||
fn headline_level<'b, 'g, 'r, 's>(
|
fn headline_level<'b, 'g, 'r, 's>(
|
||||||
context: RefContext<'b, 'g, 'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, (usize, OrgSource<'s>)> {
|
) -> Res<OrgSource<'s>, (HeadlineLevel, HeadlineLevel, OrgSource<'s>)> {
|
||||||
let (remaining, stars) = is_a("*")(input)?;
|
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 {
|
let level = match context.get_global_settings().odd_levels_only {
|
||||||
crate::context::HeadlineLevelFilter::Odd => {
|
crate::context::HeadlineLevelFilter::Odd => {
|
||||||
if count % 2 == 0 {
|
if count % 2 == 0 {
|
||||||
@ -274,5 +285,5 @@ fn headline_level<'b, 'g, 'r, 's>(
|
|||||||
}
|
}
|
||||||
crate::context::HeadlineLevelFilter::OddEven => count,
|
crate::context::HeadlineLevelFilter::OddEven => count,
|
||||||
};
|
};
|
||||||
Ok((remaining, (level, stars)))
|
Ok((remaining, (level, count, stars)))
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use super::Object;
|
|||||||
use super::Source;
|
use super::Source;
|
||||||
|
|
||||||
pub type PriorityCookie = u8;
|
pub type PriorityCookie = u8;
|
||||||
|
pub type HeadlineLevel = u16;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Document<'s> {
|
pub struct Document<'s> {
|
||||||
@ -14,7 +15,7 @@ pub struct Document<'s> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Heading<'s> {
|
pub struct Heading<'s> {
|
||||||
pub source: &'s str,
|
pub source: &'s str,
|
||||||
pub level: usize,
|
pub level: HeadlineLevel,
|
||||||
pub todo_keyword: Option<(TodoKeywordType, &'s str)>,
|
pub todo_keyword: Option<(TodoKeywordType, &'s str)>,
|
||||||
pub priority_cookie: Option<PriorityCookie>,
|
pub priority_cookie: Option<PriorityCookie>,
|
||||||
pub title: Vec<Object<'s>>,
|
pub title: Vec<Object<'s>>,
|
||||||
|
@ -7,6 +7,7 @@ mod source;
|
|||||||
pub use document::Document;
|
pub use document::Document;
|
||||||
pub use document::DocumentElement;
|
pub use document::DocumentElement;
|
||||||
pub use document::Heading;
|
pub use document::Heading;
|
||||||
|
pub use document::HeadlineLevel;
|
||||||
pub use document::PriorityCookie;
|
pub use document::PriorityCookie;
|
||||||
pub use document::Section;
|
pub use document::Section;
|
||||||
pub use document::TodoKeywordType;
|
pub use document::TodoKeywordType;
|
||||||
|
Loading…
Reference in New Issue
Block a user