13 Commits

Author SHA1 Message Date
Tom Alexander
59222c58b1 Publish version 0.1.13.
All checks were successful
rustfmt Build rustfmt has succeeded
clippy Build clippy has succeeded
rust-build Build rust-build has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-test Build rust-test has succeeded
2023-12-15 21:10:21 -05:00
Tom Alexander
4d95a7f244 Merge branch 'post_blank'
All checks were successful
clippy Build clippy has succeeded
rustfmt Build rustfmt has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-15 20:11:20 -05:00
Tom Alexander
5a8159eed7 Fix clippy.
All checks were successful
clippy Build clippy has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
2023-12-15 19:57:35 -05:00
Tom Alexander
e24fcb9ded Add dummy values for new fields for plaintext. 2023-12-15 19:54:03 -05:00
Tom Alexander
4b94dc60d2 Fix handling of documents containing only whitespace. 2023-12-15 19:49:12 -05:00
Tom Alexander
2046603d01 Fix handling post blank for org documents. 2023-12-15 19:42:43 -05:00
Tom Alexander
30412361e1 Fix handling fixed width area post-blank inside a list. 2023-12-15 19:37:33 -05:00
Tom Alexander
e846c85188 Fix handling fixed width areas with empty lines in the middle. 2023-12-15 19:17:16 -05:00
Tom Alexander
99b74095e6 Fix heading post-blank. 2023-12-15 19:10:14 -05:00
Tom Alexander
6b802d36bf Implement the new fields for target. 2023-12-15 18:57:19 -05:00
Tom Alexander
33ca43ca40 Remove the old Paragraph::of_text function.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has failed
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-15 18:06:48 -05:00
Tom Alexander
f5280a3090 Implement the new fields for bullshitium broken dynamic block. 2023-12-15 18:04:42 -05:00
Tom Alexander
c28d8ccea4 Fix post-blank for headlines containing only whitespace. 2023-12-15 17:59:47 -05:00
20 changed files with 86 additions and 70 deletions

View File

@@ -2,7 +2,7 @@
[package]
name = "organic"
version = "0.1.12"
version = "0.1.13"
authors = ["Tom Alexander <tom@fizz.buzz>"]
description = "An org-mode parser."
edition = "2021"

View File

View File

@@ -0,0 +1,4 @@

View File

@@ -0,0 +1,5 @@
* foo

View File

@@ -0,0 +1,3 @@
: foo
:
: bar

View File

@@ -0,0 +1,6 @@
1. foo
#+begin_src text
#+end_src
2. baz

View File

@@ -0,0 +1,3 @@
<<FOO>> bar
[[FOO][baz]]

View File

@@ -0,0 +1,5 @@
* foo
** bar
* baz

View File

@@ -285,7 +285,7 @@ where
pub(crate) fn compare_children<'b, 's, 'x, RC>(
source: &'s str,
emacs: &'b Token<'s>,
rust_children: &'x Vec<RC>,
rust_children: &'x [RC],
child_status: &mut Vec<DiffEntry<'b, 's>>,
this_status: &mut DiffStatus,
message: &mut Option<String>,

View File

@@ -27,7 +27,7 @@ pub(crate) fn record_event(event_type: EventType, input: OrgSource<'_>) {
pub fn report(original_document: &str) {
let mut db = GLOBAL_DATA.lock().unwrap();
let db = db.get_or_insert_with(HashMap::new);
let mut results: Vec<_> = db.iter().map(|(k, v)| (k, v)).collect();
let mut results: Vec<_> = db.iter().collect();
results.sort_by_key(|(_k, v)| *v);
// This would put the most common at the top, but that is a pain when there is already a lot of output from the parser.
// results.sort_by(|(_ak, av), (_bk, bv)| bv.cmp(av));

View File

@@ -81,10 +81,10 @@ pub(crate) fn broken_end<'b, 'g, 'r, 's>(
Ok((
remaining,
Paragraph::of_text_full(
Paragraph::of_text(
input.get_until(remaining).into(),
body,
if body.len() > 0 { Some(body) } else { None },
if !body.is_empty() { Some(body) } else { None },
post_blank.map(Into::<&str>::into),
),
))
@@ -124,6 +124,7 @@ pub(crate) fn broken_dynamic_block<'b, 'g, 'r, 's>(
match paragraph.children.first_mut() {
Some(Object::PlainText(plain_text)) => {
plain_text.source = input.get_until_end_of_str(plain_text.source).into();
paragraph.contents = Some(input.get_until_end_of_str(plain_text.source).into());
}
Some(obj) => {
panic!("Unhandled first object type inside bullshitium {:?}", obj);
@@ -134,14 +135,18 @@ pub(crate) fn broken_dynamic_block<'b, 'g, 'r, 's>(
};
Ok((remaining, paragraph))
} else {
let (remaining, _trailing_ws) =
let (remaining, post_blank) =
maybe_consume_trailing_whitespace_if_not_exiting(context, lead_in_remaining)?;
let body = Into::<&str>::into(input.get_until(lead_in_remaining));
Ok((
remaining,
Paragraph::of_text(
input.get_until(remaining).into(),
input.get_until(lead_in_remaining).into(),
body,
if !body.is_empty() { Some(body) } else { None },
post_blank.map(Into::<&str>::into),
),
))
}

View File

@@ -3,6 +3,7 @@ use std::path::Path;
use nom::combinator::all_consuming;
use nom::combinator::opt;
use nom::multi::many0;
use nom::InputTake;
use super::headline::heading;
use super::in_buffer_settings::apply_in_buffer_settings;
@@ -195,9 +196,9 @@ fn _document<'b, 'g, 'r, 's>(
zeroth_section,
children,
contents: if contents.len() > 0 {
Some(Into::<&str>::into(contents))
Into::<&str>::into(contents)
} else {
None
Into::<&str>::into(remaining.take(0))
},
},
))

View File

@@ -14,7 +14,7 @@ use nom::InputTake;
use super::affiliated_keyword::parse_affiliated_keywords;
use super::org_source::OrgSource;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting_mid_line;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use super::util::org_line_ending;
use crate::context::parser_with_context;
use crate::context::RefContext;
@@ -48,8 +48,11 @@ where
),
))(remaining)?;
let (remaining, post_blank) =
maybe_consume_trailing_whitespace_if_not_exiting_mid_line(context, remaining)?;
let post_blank_begin = remaining;
let (remaining, _first_line_break) = org_line_ending(remaining)?;
let (remaining, _additional_post_blank) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let post_blank = get_consumed(post_blank_begin, remaining);
let source = get_consumed(input, remaining);
let mut value = Vec::with_capacity(remaining_lines.len() + 1);
value.push(Into::<&str>::into(first_line));
@@ -63,7 +66,11 @@ where
affiliated_keywords,
),
value,
post_blank: post_blank.map(Into::<&str>::into),
post_blank: if post_blank.len() > 0 {
Some(Into::<&str>::into(post_blank))
} else {
None
},
},
))
}
@@ -72,8 +79,8 @@ where
fn fixed_width_area_line<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
start_of_line(input)?;
let (remaining, _) = tuple((space0, tag(":")))(input)?;
if let Ok((remain, _line_break)) = org_line_ending(remaining) {
return Ok((remain, remaining.take(0)));
if let Ok((_remain, _line_break)) = org_line_ending(remaining) {
return Ok((remaining, remaining.take(0)));
}
let (remaining, _) = tag(" ")(remaining)?;
let (remaining, value) = recognize(many_till(anychar, peek(org_line_ending)))(remaining)?;

View File

@@ -67,6 +67,7 @@ fn _heading<'b, 'g, 'r, 's>(
let section_matcher = bind_context!(section, context);
let heading_matcher = bind_context!(heading(pre_headline.star_count), context);
let (contents_begin, _) = opt(many0(blank_line))(remaining)?;
let maybe_post_blank = get_consumed(remaining, contents_begin);
let (remaining, maybe_section) =
opt(map(section_matcher, DocumentElement::Section))(remaining)?;
let (remaining, _ws) = opt(tuple((start_of_line, many0(blank_line))))(remaining)?;
@@ -83,7 +84,8 @@ fn _heading<'b, 'g, 'r, 's>(
}
children.insert(0, section);
}
let remaining = if children.is_empty() {
let has_children = !children.is_empty();
let remaining = if !has_children {
// Support empty headings
let (remain, _ws) = many0(blank_line)(remaining)?;
remain
@@ -119,6 +121,11 @@ fn _heading<'b, 'g, 'r, 's>(
} else {
None
},
post_blank: if has_children {
None
} else {
Some(Into::<&str>::into(maybe_post_blank))
},
},
))
}

View File

@@ -101,7 +101,7 @@ pub(crate) fn empty_paragraph<'b, 'g, 'r, 's>(
let source = get_consumed(input, remaining);
Ok((
remaining,
Paragraph::of_text_full(
Paragraph::of_text(
Into::<&str>::into(source),
Into::<&str>::into(first_line_with_spaces),
Some(Into::<&str>::into(first_line_with_spaces)),
@@ -116,7 +116,7 @@ pub(crate) fn empty_paragraph<'b, 'g, 'r, 's>(
let source = get_consumed(input, remaining);
Ok((
remaining,
Paragraph::of_text_full(
Paragraph::of_text(
Into::<&str>::into(source),
Into::<&str>::into(first_line),
Some(Into::<&str>::into(first_line)),

View File

@@ -46,7 +46,7 @@ pub(crate) fn target<'b, 'g, 'r, 's>(
)));
}
let (remaining, _) = tag(">>")(remaining)?;
let (remaining, _trailing_whitespace) =
let (remaining, post_blank) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
@@ -55,6 +55,7 @@ pub(crate) fn target<'b, 'g, 'r, 's>(
Target {
source: source.into(),
value: body.into(),
post_blank: post_blank.map(Into::<&str>::into),
},
))
}

View File

@@ -72,13 +72,6 @@ fn element_trailing_whitespace<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, O
alt((eof, recognize(many0(blank_line))))(input)
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn element_trailing_whitespace_mid_line<'s>(
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, OrgSource<'s>> {
alt((eof, recognize(many0(blank_line))))(input)
}
#[cfg_attr(
feature = "tracing",
tracing::instrument(ret, level = "debug", skip(context))
@@ -121,22 +114,6 @@ pub(crate) fn maybe_consume_trailing_whitespace_if_not_exiting<'b, 'g, 'r, 's>(
}
}
#[cfg_attr(
feature = "tracing",
tracing::instrument(ret, level = "debug", skip(context))
)]
pub(crate) fn maybe_consume_trailing_whitespace_if_not_exiting_mid_line<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Option<OrgSource<'s>>> {
if context.should_consume_trailing_whitespace() && exit_matcher_parser(context, input).is_err()
{
Ok(opt(element_trailing_whitespace_mid_line)(input)?)
} else {
Ok((input, None))
}
}
#[cfg_attr(
feature = "tracing",
tracing::instrument(ret, level = "debug", skip(context))

View File

@@ -17,7 +17,7 @@ pub struct Document<'s> {
pub path: Option<PathBuf>,
pub zeroth_section: Option<Section<'s>>,
pub children: Vec<Heading<'s>>,
pub contents: Option<&'s str>,
pub contents: &'s str,
}
#[derive(Debug)]
@@ -36,6 +36,7 @@ pub struct Heading<'s> {
pub deadline: Option<Timestamp<'s>>,
pub closed: Option<Timestamp<'s>>,
pub contents: Option<&'s str>,
pub post_blank: Option<&'s str>,
}
#[derive(Debug)]
@@ -63,14 +64,11 @@ impl<'s> StandardProperties<'s> for Document<'s> {
}
fn get_contents<'b>(&'b self) -> Option<&'s str> {
self.contents
Some(self.contents)
}
fn get_post_blank(&self) -> PostBlank {
self.into_iter()
.last()
.map(|child| child.get_post_blank())
.unwrap_or(0)
0
}
}
@@ -102,10 +100,11 @@ impl<'s> StandardProperties<'s> for Heading<'s> {
}
fn get_post_blank(&self) -> PostBlank {
self.children
.last()
.map(|child| child.get_post_blank())
self.post_blank
.map(|text| text.lines().count())
.unwrap_or(0)
.try_into()
.expect("Too much post-blank to fit into a PostBlank.")
}
}

View File

@@ -204,21 +204,7 @@ impl<'s> Paragraph<'s> {
/// Generate a paragraph of the passed in text with no additional properties.
///
/// This is used for elements that support an "empty" content like greater blocks.
pub(crate) fn of_text(source: &'s str, body: &'s str) -> Self {
// TODO: This should be replaced with of_text_full.
Paragraph {
source,
contents: None,
post_blank: None,
affiliated_keywords: AffiliatedKeywords::default(),
children: vec![Object::PlainText(PlainText { source: body })],
}
}
/// Generate a paragraph of the passed in text with no additional properties.
///
/// This is used for elements that support an "empty" content like greater blocks.
pub(crate) fn of_text_full(
pub(crate) fn of_text(
source: &'s str,
body: &'s str,
contents: Option<&'s str>,

View File

@@ -266,6 +266,7 @@ pub struct LineBreak<'s> {
pub struct Target<'s> {
pub source: &'s str,
pub value: &'s str,
pub post_blank: Option<&'s str>,
}
#[derive(Debug)]
@@ -923,11 +924,15 @@ impl<'s> StandardProperties<'s> for Target<'s> {
}
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
None
}
fn get_post_blank(&self) -> PostBlank {
todo!()
self.post_blank
.map(|post_blank| post_blank.chars().count())
.unwrap_or(0)
.try_into()
.expect("Too much post-blank to fit into a PostBlank.")
}
}
@@ -1009,11 +1014,13 @@ impl<'s> StandardProperties<'s> for PlainText<'s> {
}
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
// This field does not actually exist in emacs for plaintext
Some(self.source)
}
fn get_post_blank(&self) -> PostBlank {
todo!()
// This field does not actually exist in emacs for plaintext
0
}
}