Compare commits
No commits in common. "3d86e75059e89229b08df83dd5126cbf20a9218d" and "ac0db640810972e2b2274a8ead5b451dd520c119" have entirely different histories.
3d86e75059
...
ac0db64081
@ -25,4 +25,3 @@ This could significantly reduce our calls to exit matchers.
|
|||||||
I think targets would break this.
|
I think targets would break this.
|
||||||
|
|
||||||
The exit matchers are already implicitly building this behavior since they should all exit very early when the starting character is wrong. Putting this logic in a centralized place, far away from where those characters are actually going to be used, is unfortunate for readability.
|
The exit matchers are already implicitly building this behavior since they should all exit very early when the starting character is wrong. Putting this logic in a centralized place, far away from where those characters are actually going to be used, is unfortunate for readability.
|
||||||
** Use exit matcher to cut off trailing whitespace instead of re-matching in plain lists.
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
<<<Foo Bar Baz>>>
|
|
||||||
|
|
||||||
foo bar baz
|
|
@ -1,6 +0,0 @@
|
|||||||
<<<foo bar baz>>>
|
|
||||||
|
|
||||||
|
|
||||||
foo
|
|
||||||
bar
|
|
||||||
baz
|
|
@ -1 +0,0 @@
|
|||||||
[[elisp:(local-set-key "\M-\x" 'foo-bar-baz)]]
|
|
@ -1,2 +0,0 @@
|
|||||||
* DONE
|
|
||||||
*
|
|
@ -1,6 +0,0 @@
|
|||||||
#+TODO: TODO(t) INPROGRESS(i/!) | DONE(d!) CANCELED(c@/!)
|
|
||||||
# ! : Log changes leading to this state.
|
|
||||||
# @ : Log changes leading to this state and prompt for a comment to include.
|
|
||||||
# /! : Log changes leaving this state if and only if to a state that does not log. This can be combined with the above like WAIT(w!/!) or DELAYED(d@/!)
|
|
||||||
* INPROGRESS
|
|
||||||
- State "TODO" from "INPROGRESS" [2023-09-14 Thu 02:13]
|
|
@ -546,26 +546,14 @@ fn compare_heading<'s>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Compare title
|
// Compare title
|
||||||
let title = get_property(emacs, ":title")?;
|
let title = get_property(emacs, ":title")?.ok_or("Missing :title attribute.")?;
|
||||||
match (title, rust.title.len()) {
|
let title_status = title
|
||||||
(None, 0) => {}
|
.as_list()?
|
||||||
(None, _) => {
|
.iter()
|
||||||
this_status = DiffStatus::Bad;
|
.zip(rust.title.iter())
|
||||||
message = Some(format!(
|
.map(|(emacs_child, rust_child)| compare_object(source, emacs_child, rust_child))
|
||||||
"Titles do not match (emacs != rust): {:?} != {:?}",
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
title, rust.title
|
child_status.push(artificial_diff_scope("title".to_owned(), title_status)?);
|
||||||
))
|
|
||||||
}
|
|
||||||
(Some(title), _) => {
|
|
||||||
let title_status = title
|
|
||||||
.as_list()?
|
|
||||||
.iter()
|
|
||||||
.zip(rust.title.iter())
|
|
||||||
.map(|(emacs_child, rust_child)| compare_object(source, emacs_child, rust_child))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
child_status.push(artificial_diff_scope("title".to_owned(), title_status)?);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compare priority
|
// Compare priority
|
||||||
let priority = get_property(emacs, ":priority")?;
|
let priority = get_property(emacs, ":priority")?;
|
||||||
@ -1926,8 +1914,6 @@ fn compare_regular_link<'s>(
|
|||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Compare :type :path :format :raw-link :application :search-option
|
|
||||||
|
|
||||||
Ok(DiffResult {
|
Ok(DiffResult {
|
||||||
status: this_status,
|
status: this_status,
|
||||||
name: emacs_name.to_owned(),
|
name: emacs_name.to_owned(),
|
||||||
|
@ -12,10 +12,6 @@ pub struct GlobalSettings<'g, 's> {
|
|||||||
pub file_access: &'g dyn FileAccessInterface,
|
pub file_access: &'g dyn FileAccessInterface,
|
||||||
pub in_progress_todo_keywords: BTreeSet<String>,
|
pub in_progress_todo_keywords: BTreeSet<String>,
|
||||||
pub complete_todo_keywords: BTreeSet<String>,
|
pub complete_todo_keywords: BTreeSet<String>,
|
||||||
/// Set to true to allow for plain lists using single letters as the bullet in the same way that numbers are used.
|
|
||||||
///
|
|
||||||
/// Corresponds to the org-list-allow-alphabetical elisp variable.
|
|
||||||
pub org_list_allow_alphabetical: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'g, 's> GlobalSettings<'g, 's> {
|
impl<'g, 's> GlobalSettings<'g, 's> {
|
||||||
@ -27,7 +23,6 @@ impl<'g, 's> GlobalSettings<'g, 's> {
|
|||||||
},
|
},
|
||||||
in_progress_todo_keywords: BTreeSet::new(),
|
in_progress_todo_keywords: BTreeSet::new(),
|
||||||
complete_todo_keywords: BTreeSet::new(),
|
complete_todo_keywords: BTreeSet::new(),
|
||||||
org_list_allow_alphabetical: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ fn _detect_element<'b, 'g, 'r, 's>(
|
|||||||
can_be_paragraph: bool,
|
can_be_paragraph: bool,
|
||||||
) -> Res<OrgSource<'s>, ()> {
|
) -> Res<OrgSource<'s>, ()> {
|
||||||
if alt((
|
if alt((
|
||||||
parser_with_context!(detect_plain_list)(context),
|
detect_plain_list,
|
||||||
detect_footnote_definition,
|
detect_footnote_definition,
|
||||||
detect_diary_sexp,
|
detect_diary_sexp,
|
||||||
detect_comment,
|
detect_comment,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
|
use nom::bytes::complete::tag_no_case;
|
||||||
use nom::character::complete::satisfy;
|
use nom::character::complete::satisfy;
|
||||||
use nom::combinator::eof;
|
use nom::combinator::eof;
|
||||||
use nom::combinator::peek;
|
use nom::combinator::peek;
|
||||||
use nom::combinator::recognize;
|
use nom::combinator::recognize;
|
||||||
use nom::sequence::tuple;
|
|
||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
@ -439,7 +439,7 @@ pub(crate) fn entity<'b, 'g, 'r, 's>(
|
|||||||
) -> Res<OrgSource<'s>, Entity<'s>> {
|
) -> Res<OrgSource<'s>, Entity<'s>> {
|
||||||
let (remaining, _) = tag("\\")(input)?;
|
let (remaining, _) = tag("\\")(input)?;
|
||||||
let (remaining, entity_name) = name(context, remaining)?;
|
let (remaining, entity_name) = name(context, remaining)?;
|
||||||
|
let (remaining, _) = alt((tag("{}"), peek(recognize(entity_end))))(remaining)?;
|
||||||
let (remaining, _trailing_whitespace) =
|
let (remaining, _trailing_whitespace) =
|
||||||
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
|
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
|
||||||
|
|
||||||
@ -460,12 +460,9 @@ fn name<'b, 'g, 'r, 's>(
|
|||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
// TODO: This should be defined by org-entities and optionally org-entities-user
|
// TODO: This should be defined by org-entities and optionally org-entities-user
|
||||||
for entity in ORG_ENTITIES {
|
for entity in ORG_ENTITIES {
|
||||||
let result = tuple((
|
let result = tag_no_case::<_, _, CustomError<_>>(entity)(input);
|
||||||
tag::<_, _, CustomError<_>>(entity),
|
|
||||||
alt((tag("{}"), peek(recognize(entity_end)))),
|
|
||||||
))(input);
|
|
||||||
match result {
|
match result {
|
||||||
Ok((remaining, (ent, _))) => {
|
Ok((remaining, ent)) => {
|
||||||
return Ok((remaining, ent));
|
return Ok((remaining, ent));
|
||||||
}
|
}
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
|
@ -3,17 +3,15 @@ use nom::bytes::complete::is_not;
|
|||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::character::complete::line_ending;
|
use nom::character::complete::line_ending;
|
||||||
use nom::character::complete::space0;
|
use nom::character::complete::space0;
|
||||||
|
use nom::character::complete::space1;
|
||||||
use nom::combinator::eof;
|
use nom::combinator::eof;
|
||||||
use nom::combinator::not;
|
use nom::combinator::not;
|
||||||
use nom::combinator::recognize;
|
use nom::combinator::opt;
|
||||||
use nom::multi::many0;
|
use nom::multi::many0;
|
||||||
use nom::sequence::preceded;
|
use nom::sequence::preceded;
|
||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::util::org_line_ending;
|
|
||||||
use super::util::org_spaces0;
|
|
||||||
use super::util::org_spaces1;
|
|
||||||
use crate::context::parser_with_context;
|
use crate::context::parser_with_context;
|
||||||
use crate::context::RefContext;
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
@ -49,10 +47,10 @@ fn fixed_width_area_line<'b, 'g, 'r, 's>(
|
|||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
let (remaining, _indent) = space0(input)?;
|
let (remaining, _indent) = space0(input)?;
|
||||||
let (remaining, _) = tuple((
|
let (remaining, (_colon, _leading_whitespace_and_content, _line_ending)) = tuple((
|
||||||
tag(":"),
|
tag(":"),
|
||||||
alt((recognize(tuple((org_spaces1, is_not("\r\n")))), org_spaces0)),
|
opt(tuple((space1, is_not("\r\n")))),
|
||||||
org_line_ending,
|
alt((line_ending, eof)),
|
||||||
))(remaining)?;
|
))(remaining)?;
|
||||||
let source = get_consumed(input, remaining);
|
let source = get_consumed(input, remaining);
|
||||||
Ok((remaining, source))
|
Ok((remaining, source))
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::character::complete::anychar;
|
use nom::character::complete::anychar;
|
||||||
|
use nom::character::complete::line_ending;
|
||||||
|
use nom::character::complete::space0;
|
||||||
use nom::character::complete::space1;
|
use nom::character::complete::space1;
|
||||||
|
use nom::combinator::eof;
|
||||||
use nom::combinator::map;
|
use nom::combinator::map;
|
||||||
use nom::combinator::not;
|
use nom::combinator::not;
|
||||||
use nom::combinator::opt;
|
use nom::combinator::opt;
|
||||||
use nom::combinator::peek;
|
|
||||||
use nom::combinator::recognize;
|
use nom::combinator::recognize;
|
||||||
use nom::combinator::verify;
|
use nom::combinator::verify;
|
||||||
use nom::multi::many0;
|
use nom::multi::many0;
|
||||||
@ -17,11 +19,6 @@ use nom::sequence::tuple;
|
|||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::section::section;
|
use super::section::section;
|
||||||
use super::util::get_consumed;
|
use super::util::get_consumed;
|
||||||
use super::util::org_line_ending;
|
|
||||||
use super::util::org_space;
|
|
||||||
use super::util::org_space_or_line_ending;
|
|
||||||
use super::util::org_spaces0;
|
|
||||||
use super::util::org_spaces1;
|
|
||||||
use super::util::start_of_line;
|
use super::util::start_of_line;
|
||||||
use crate::context::parser_with_context;
|
use crate::context::parser_with_context;
|
||||||
use crate::context::ContextElement;
|
use crate::context::ContextElement;
|
||||||
@ -84,10 +81,10 @@ fn _heading<'b, 'g, 'r, 's>(
|
|||||||
Heading {
|
Heading {
|
||||||
source: source.into(),
|
source: source.into(),
|
||||||
stars: star_count,
|
stars: star_count,
|
||||||
todo_keyword: maybe_todo_keyword.map(|(todo_keyword_type, todo_keyword)| {
|
todo_keyword: maybe_todo_keyword.map(|((todo_keyword_type, todo_keyword), _ws)| {
|
||||||
(todo_keyword_type, Into::<&str>::into(todo_keyword))
|
(todo_keyword_type, Into::<&str>::into(todo_keyword))
|
||||||
}),
|
}),
|
||||||
priority_cookie: maybe_priority.map(|(_, priority)| priority),
|
priority_cookie: maybe_priority.map(|(priority, _)| priority),
|
||||||
title,
|
title,
|
||||||
tags: heading_tags,
|
tags: heading_tags,
|
||||||
children,
|
children,
|
||||||
@ -112,9 +109,9 @@ fn headline<'b, 'g, 'r, 's>(
|
|||||||
OrgSource<'s>,
|
OrgSource<'s>,
|
||||||
(
|
(
|
||||||
usize,
|
usize,
|
||||||
Option<(TodoKeywordType, OrgSource<'s>)>,
|
Option<((TodoKeywordType, OrgSource<'s>), OrgSource<'s>)>,
|
||||||
Option<(OrgSource<'s>, PriorityCookie)>,
|
Option<(PriorityCookie, OrgSource<'s>)>,
|
||||||
Option<OrgSource<'s>>,
|
Option<(OrgSource<'s>, OrgSource<'s>)>,
|
||||||
Vec<Object<'s>>,
|
Vec<Object<'s>>,
|
||||||
Vec<&'s str>,
|
Vec<&'s str>,
|
||||||
),
|
),
|
||||||
@ -125,45 +122,45 @@ 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,
|
||||||
|
(
|
||||||
|
_,
|
||||||
|
star_count,
|
||||||
|
_,
|
||||||
|
maybe_todo_keyword,
|
||||||
|
maybe_priority,
|
||||||
|
maybe_comment,
|
||||||
|
title,
|
||||||
|
maybe_tags,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
),
|
||||||
|
) = tuple((
|
||||||
start_of_line,
|
start_of_line,
|
||||||
verify(many1_count(tag("*")), |star_count| {
|
verify(many1_count(tag("*")), |star_count| {
|
||||||
*star_count > parent_stars
|
*star_count > parent_stars
|
||||||
}),
|
}),
|
||||||
peek(org_space),
|
space1,
|
||||||
))(input)?;
|
opt(tuple((
|
||||||
|
parser_with_context!(heading_keyword)(&parser_context),
|
||||||
let (remaining, maybe_todo_keyword) = opt(tuple((
|
space1,
|
||||||
org_spaces1,
|
))),
|
||||||
parser_with_context!(heading_keyword)(&parser_context),
|
opt(tuple((priority_cookie, space1))),
|
||||||
peek(org_space_or_line_ending),
|
opt(tuple((tag("COMMENT"), space1))),
|
||||||
)))(remaining)?;
|
|
||||||
|
|
||||||
let (remaining, maybe_priority) = opt(tuple((org_spaces1, priority_cookie)))(remaining)?;
|
|
||||||
|
|
||||||
let (remaining, maybe_comment) = opt(tuple((
|
|
||||||
org_spaces1,
|
|
||||||
tag("COMMENT"),
|
|
||||||
peek(org_space_or_line_ending),
|
|
||||||
)))(remaining)?;
|
|
||||||
|
|
||||||
let (remaining, maybe_title) = opt(tuple((
|
|
||||||
org_spaces1,
|
|
||||||
many1(parser_with_context!(standard_set_object)(&parser_context)),
|
many1(parser_with_context!(standard_set_object)(&parser_context)),
|
||||||
)))(remaining)?;
|
opt(tuple((space0, tags))),
|
||||||
|
space0,
|
||||||
let (remaining, maybe_tags) = opt(tuple((org_spaces0, tags)))(remaining)?;
|
alt((line_ending, eof)),
|
||||||
|
))(input)?;
|
||||||
let (remaining, _) = tuple((org_spaces0, org_line_ending))(remaining)?;
|
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
remaining,
|
remaining,
|
||||||
(
|
(
|
||||||
star_count,
|
star_count,
|
||||||
maybe_todo_keyword.map(|(_, todo, _)| todo),
|
maybe_todo_keyword,
|
||||||
maybe_priority,
|
maybe_priority,
|
||||||
maybe_comment.map(|(_, comment, _)| comment),
|
maybe_comment,
|
||||||
maybe_title.map(|(_, title)| title).unwrap_or(Vec::new()),
|
title,
|
||||||
maybe_tags
|
maybe_tags
|
||||||
.map(|(_ws, tags)| {
|
.map(|(_ws, tags)| {
|
||||||
tags.into_iter()
|
tags.into_iter()
|
||||||
@ -181,9 +178,8 @@ fn headline_title_end<'b, 'g, 'r, 's>(
|
|||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(tuple((
|
recognize(tuple((
|
||||||
org_spaces0,
|
opt(tuple((space0, tags, space0))),
|
||||||
opt(tuple((tags, org_spaces0))),
|
alt((line_ending, eof)),
|
||||||
org_line_ending,
|
|
||||||
)))(input)
|
)))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,17 +44,9 @@ pub(crate) fn todo_keywords<'s>(input: &'s str) -> Res<&'s str, (Vec<&'s str>, V
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn todo_keyword_word<'s>(input: &'s str) -> Res<&'s str, &'s str> {
|
fn todo_keyword_word<'s>(input: &'s str) -> Res<&'s str, &'s str> {
|
||||||
let (remaining, keyword) = verify(take_till(|c| "( \t\r\n|".contains(c)), |result: &str| {
|
verify(take_till(|c| " \t\r\n|".contains(c)), |result: &str| {
|
||||||
!result.is_empty()
|
!result.is_empty()
|
||||||
})(input)?;
|
})(input)
|
||||||
|
|
||||||
let (remaining, _) = opt(tuple((
|
|
||||||
tag("("),
|
|
||||||
take_till(|c| "() \t\r\n|".contains(c)),
|
|
||||||
tag(")"),
|
|
||||||
)))(remaining)?;
|
|
||||||
|
|
||||||
Ok((remaining, keyword))
|
|
||||||
}
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -41,15 +41,12 @@ use crate::types::PlainList;
|
|||||||
use crate::types::PlainListItem;
|
use crate::types::PlainListItem;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub(crate) fn detect_plain_list<'b, 'g, 'r, 's>(
|
pub(crate) fn detect_plain_list<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
||||||
context: RefContext<'b, 'g, 'r, 's>,
|
|
||||||
input: OrgSource<'s>,
|
|
||||||
) -> Res<OrgSource<'s>, ()> {
|
|
||||||
if verify(
|
if verify(
|
||||||
tuple((
|
tuple((
|
||||||
start_of_line,
|
start_of_line,
|
||||||
space0,
|
space0,
|
||||||
parser_with_context!(bullet)(context),
|
bullet,
|
||||||
alt((space1, line_ending, eof)),
|
alt((space1, line_ending, eof)),
|
||||||
)),
|
)),
|
||||||
|(_start, indent, bull, _after_whitespace)| {
|
|(_start, indent, bull, _after_whitespace)| {
|
||||||
@ -148,17 +145,12 @@ fn plain_list_item<'b, 'g, 'r, 's>(
|
|||||||
let (remaining, leading_whitespace) = space0(input)?;
|
let (remaining, leading_whitespace) = space0(input)?;
|
||||||
// It is fine that we get the indent level using the number of bytes rather than the number of characters because nom's space0 only matches space and tab (0x20 and 0x09)
|
// It is fine that we get the indent level using the number of bytes rather than the number of characters because nom's space0 only matches space and tab (0x20 and 0x09)
|
||||||
let indent_level = leading_whitespace.len();
|
let indent_level = leading_whitespace.len();
|
||||||
let (remaining, bull) = verify(
|
let (remaining, bull) = verify(bullet, |bull: &OrgSource<'_>| {
|
||||||
parser_with_context!(bullet)(context),
|
Into::<&str>::into(bull) != "*" || indent_level > 0
|
||||||
|bull: &OrgSource<'_>| Into::<&str>::into(bull) != "*" || indent_level > 0,
|
})(remaining)?;
|
||||||
)(remaining)?;
|
|
||||||
|
|
||||||
let (remaining, _maybe_counter_set) = opt(tuple((
|
let (remaining, _maybe_counter_set) =
|
||||||
space1,
|
opt(tuple((space1, tag("[@"), counter, tag("]"))))(remaining)?;
|
||||||
tag("[@"),
|
|
||||||
parser_with_context!(counter)(context),
|
|
||||||
tag("]"),
|
|
||||||
)))(remaining)?;
|
|
||||||
|
|
||||||
// TODO: parse checkbox
|
// TODO: parse checkbox
|
||||||
|
|
||||||
@ -236,36 +228,18 @@ fn plain_list_item<'b, 'g, 'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn bullet<'b, 'g, 'r, 's>(
|
fn bullet<'s>(i: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
context: RefContext<'b, 'g, 'r, 's>,
|
|
||||||
input: OrgSource<'s>,
|
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
alt((
|
alt((
|
||||||
tag("*"),
|
tag("*"),
|
||||||
tag("-"),
|
tag("-"),
|
||||||
tag("+"),
|
tag("+"),
|
||||||
recognize(tuple((
|
recognize(tuple((counter, alt((tag("."), tag(")")))))),
|
||||||
parser_with_context!(counter)(context),
|
))(i)
|
||||||
alt((tag("."), tag(")"))),
|
|
||||||
))),
|
|
||||||
))(input)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn counter<'b, 'g, 'r, 's>(
|
fn counter<'s>(i: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
context: RefContext<'b, 'g, 'r, 's>,
|
alt((recognize(one_of("abcdefghijklmnopqrstuvwxyz")), digit1))(i)
|
||||||
input: OrgSource<'s>,
|
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
if context.get_global_settings().org_list_allow_alphabetical {
|
|
||||||
alt((
|
|
||||||
recognize(one_of(
|
|
||||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
||||||
)),
|
|
||||||
digit1,
|
|
||||||
))(input)
|
|
||||||
} else {
|
|
||||||
digit1(input)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
@ -584,30 +558,21 @@ dolar"#,
|
|||||||
r#"+
|
r#"+
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
let global_settings = GlobalSettings::default();
|
let result = detect_plain_list(input);
|
||||||
let initial_context = ContextElement::document_context();
|
|
||||||
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
|
||||||
let result = detect_plain_list(&initial_context, input);
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn detect_eof() {
|
fn detect_eof() {
|
||||||
let input = OrgSource::new(r#"+"#);
|
let input = OrgSource::new(r#"+"#);
|
||||||
let global_settings = GlobalSettings::default();
|
let result = detect_plain_list(input);
|
||||||
let initial_context = ContextElement::document_context();
|
|
||||||
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
|
||||||
let result = detect_plain_list(&initial_context, input);
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn detect_no_gap() {
|
fn detect_no_gap() {
|
||||||
let input = OrgSource::new(r#"+foo"#);
|
let input = OrgSource::new(r#"+foo"#);
|
||||||
let global_settings = GlobalSettings::default();
|
let result = detect_plain_list(input);
|
||||||
let initial_context = ContextElement::document_context();
|
|
||||||
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
|
||||||
let result = detect_plain_list(&initial_context, input);
|
|
||||||
// Since there is no whitespace after the '+' this is a paragraph, not a plain list.
|
// Since there is no whitespace after the '+' this is a paragraph, not a plain list.
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
@ -615,10 +580,7 @@ dolar"#,
|
|||||||
#[test]
|
#[test]
|
||||||
fn detect_with_gap() {
|
fn detect_with_gap() {
|
||||||
let input = OrgSource::new(r#"+ foo"#);
|
let input = OrgSource::new(r#"+ foo"#);
|
||||||
let global_settings = GlobalSettings::default();
|
let result = detect_plain_list(input);
|
||||||
let initial_context = ContextElement::document_context();
|
|
||||||
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
|
||||||
let result = detect_plain_list(&initial_context, input);
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,17 @@
|
|||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::is_not;
|
use nom::bytes::complete::tag;
|
||||||
use nom::bytes::complete::tag_no_case;
|
|
||||||
use nom::character::complete::anychar;
|
use nom::character::complete::anychar;
|
||||||
use nom::character::complete::line_ending;
|
use nom::combinator::map;
|
||||||
use nom::character::complete::one_of;
|
|
||||||
use nom::combinator::peek;
|
use nom::combinator::peek;
|
||||||
use nom::combinator::recognize;
|
use nom::combinator::recognize;
|
||||||
use nom::combinator::verify;
|
use nom::combinator::verify;
|
||||||
use nom::multi::many1;
|
|
||||||
use nom::multi::many_till;
|
use nom::multi::many_till;
|
||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::radio_link::RematchObject;
|
use super::radio_link::RematchObject;
|
||||||
use super::util::exit_matcher_parser;
|
use super::util::exit_matcher_parser;
|
||||||
use super::util::get_consumed;
|
|
||||||
use super::util::org_space_or_line_ending;
|
|
||||||
use crate::context::parser_with_context;
|
use crate::context::parser_with_context;
|
||||||
use crate::context::RefContext;
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
|
||||||
use crate::error::MyError;
|
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::types::Object;
|
use crate::types::Object;
|
||||||
use crate::types::PlainText;
|
use crate::types::PlainText;
|
||||||
@ -79,52 +72,11 @@ impl<'x> RematchObject<'x> for PlainText<'x> {
|
|||||||
_context: RefContext<'b, 'g, 'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Object<'s>> {
|
) -> Res<OrgSource<'s>, Object<'s>> {
|
||||||
let mut remaining = input;
|
map(tag(self.source), |s| {
|
||||||
let mut goal = self.source;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if goal.is_empty() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// let is_whitespace = recognize(many1(org_space_or_line_ending))(input);
|
|
||||||
let is_not_whitespace = is_not::<&str, &str, CustomError<_>>(" \t\r\n")(goal);
|
|
||||||
match is_not_whitespace {
|
|
||||||
Ok((new_goal, payload)) => {
|
|
||||||
let (new_remaining, _) = tag_no_case(payload)(remaining)?;
|
|
||||||
remaining = new_remaining;
|
|
||||||
goal = new_goal;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
let is_whitespace = recognize(many1(alt((
|
|
||||||
recognize(one_of::<&str, &str, CustomError<_>>(" \t")),
|
|
||||||
line_ending,
|
|
||||||
))))(goal);
|
|
||||||
match is_whitespace {
|
|
||||||
Ok((new_goal, _)) => {
|
|
||||||
let (new_remaining, _) = many1(org_space_or_line_ending)(remaining)?;
|
|
||||||
remaining = new_remaining;
|
|
||||||
goal = new_goal;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
|
||||||
"Target does not match.".into(),
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
|
|
||||||
let source = get_consumed(input, remaining);
|
|
||||||
Ok((
|
|
||||||
remaining,
|
|
||||||
Object::PlainText(PlainText {
|
Object::PlainText(PlainText {
|
||||||
source: Into::<&str>::into(source),
|
source: Into::<&str>::into(s),
|
||||||
}),
|
})
|
||||||
))
|
})(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use nom::branch::alt;
|
|||||||
use nom::bytes::complete::escaped;
|
use nom::bytes::complete::escaped;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::bytes::complete::take_till1;
|
use nom::bytes::complete::take_till1;
|
||||||
use nom::character::complete::anychar;
|
use nom::character::complete::one_of;
|
||||||
use nom::combinator::verify;
|
use nom::combinator::verify;
|
||||||
use nom::multi::many_till;
|
use nom::multi::many_till;
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ fn pathreg<'b, 'g, 'r, 's>(
|
|||||||
_ => false,
|
_ => false,
|
||||||
}),
|
}),
|
||||||
'\\',
|
'\\',
|
||||||
anychar,
|
one_of(r#"]"#),
|
||||||
)(input)?;
|
)(input)?;
|
||||||
Ok((remaining, path))
|
Ok((remaining, path))
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::is_a;
|
|
||||||
use nom::character::complete::anychar;
|
use nom::character::complete::anychar;
|
||||||
use nom::character::complete::line_ending;
|
use nom::character::complete::line_ending;
|
||||||
use nom::character::complete::none_of;
|
use nom::character::complete::none_of;
|
||||||
@ -10,11 +9,9 @@ use nom::combinator::not;
|
|||||||
use nom::combinator::opt;
|
use nom::combinator::opt;
|
||||||
use nom::combinator::peek;
|
use nom::combinator::peek;
|
||||||
use nom::combinator::recognize;
|
use nom::combinator::recognize;
|
||||||
use nom::combinator::verify;
|
|
||||||
use nom::multi::many0;
|
use nom::multi::many0;
|
||||||
use nom::multi::many_till;
|
use nom::multi::many_till;
|
||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
use nom::Slice;
|
|
||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use crate::context::parser_with_context;
|
use crate::context::parser_with_context;
|
||||||
@ -215,9 +212,6 @@ fn text_until_eol<'r, 's>(
|
|||||||
Ok(line.trim())
|
Ok(line.trim())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a tuple of (input, output) from a nom parser.
|
|
||||||
///
|
|
||||||
/// This is similar to recognize except it returns the input instead of the portion of the input that was consumed.
|
|
||||||
pub(crate) fn include_input<'s, F, O>(
|
pub(crate) fn include_input<'s, F, O>(
|
||||||
mut inner: F,
|
mut inner: F,
|
||||||
) -> impl FnMut(OrgSource<'s>) -> Res<OrgSource<'s>, (OrgSource<'s>, O)>
|
) -> impl FnMut(OrgSource<'s>) -> Res<OrgSource<'s>, (OrgSource<'s>, O)>
|
||||||
@ -229,44 +223,3 @@ where
|
|||||||
Ok((remaining, (input, output)))
|
Ok((remaining, (input, output)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Match single space or tab.
|
|
||||||
///
|
|
||||||
/// In org-mode syntax, spaces and tabs are interchangeable.
|
|
||||||
pub(crate) fn org_space<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, char> {
|
|
||||||
one_of(" \t")(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Matches a single space, tab, line ending, or end of file.
|
|
||||||
///
|
|
||||||
/// In org-mode syntax there are often delimiters that could be any whitespace at all or the end of file.
|
|
||||||
pub(crate) fn org_space_or_line_ending<'s>(
|
|
||||||
input: OrgSource<'s>,
|
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
alt((recognize(one_of(" \t")), org_line_ending))(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Match as many spaces and tabs as possible. No minimum match.
|
|
||||||
///
|
|
||||||
/// In org-mode syntax, spaces and tabs are interchangeable.
|
|
||||||
pub(crate) fn org_spaces0<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
let found = is_a(" \t")(input);
|
|
||||||
if found.is_ok() {
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
Ok((input, input.slice(..0)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Match as many spaces and tabs as possible. Minimum 1 character.
|
|
||||||
///
|
|
||||||
/// In org-mode syntax, spaces and tabs are interchangeable.
|
|
||||||
pub(crate) fn org_spaces1<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
verify(is_a(" \t"), |res: &OrgSource<'_>| res.len() > 0)(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Match a line break or the end of the file.
|
|
||||||
///
|
|
||||||
/// In org-mode syntax, the end of the file can serve the same purpose as a line break syntactically.
|
|
||||||
pub(crate) fn org_line_ending<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
alt((line_ending, eof))(input)
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user