21 Commits

Author SHA1 Message Date
Tom Alexander
fcd63b1231 fixup
All checks were successful
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-08-31 21:58:41 -04:00
Tom Alexander
743b4c9982 fixup
All checks were successful
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-08-31 21:55:20 -04:00
Tom Alexander
7eccf8fccd Remove dependency on run-docker-image task.
Some checks failed
rust-test Build rust-test has failed
rust-build Build rust-build has succeeded
2023-08-31 21:48:06 -04:00
Tom Alexander
a40a504f94 Switch to using read-only root in docker containers.
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-08-31 21:23:51 -04:00
Tom Alexander
80d77ff5d6 Fix handling of unicode in compare tests.
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-08-31 20:20:00 -04:00
Tom Alexander
ee92049e5d Merge branch 'special_block'
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-08-31 19:19:29 -04:00
Tom Alexander
510985e97c Fix greater blocks by preventing nesting even if they are not the immediate parent. 2023-08-31 19:17:46 -04:00
Tom Alexander
949d0989f4 Add a test showing the current parser is broken with deeply nested greater blocks. 2023-08-31 19:15:28 -04:00
Tom Alexander
2a4d22bdd4 Add test for nesting of greater blocks.
This shows that greater blocks of different types can be directly nested even if they are both special blocks (as long as they are different special blocks).
2023-08-31 19:09:38 -04:00
Tom Alexander
7a903acedc Support special blocks in compare. 2023-08-31 19:04:44 -04:00
Tom Alexander
5171326d63 Create a test for special blocks. 2023-08-31 19:02:18 -04:00
Tom Alexander
67f79aeb51 Remove context from detect plain list.
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-08-31 18:53:28 -04:00
Tom Alexander
b2383d9f93 Fix footnote definition performance.
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
We were re-parsing each footnote definition in the footnote definition exit matcher which causes their contents to get re-parsed. This compounds with long lists of footnote definitions.
2023-08-31 18:47:23 -04:00
Tom Alexander
9e2a323f6f Merge branch 'trailing_whitespace_at_end_of_file'
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-08-31 17:29:52 -04:00
Tom Alexander
0fcb3f73f9 Move handling of contentless item to handle contentless description item. 2023-08-31 17:25:42 -04:00
Tom Alexander
bfc9e7f58d When re-parsing last item in list, only disable white space consumption for last element in item. 2023-08-31 17:08:21 -04:00
Tom Alexander
b5f0521b56 Only consume trailing whitespace when not exiting for all objects. 2023-08-31 15:45:31 -04:00
Tom Alexander
2048d8f0b6 Support comments at the end of the line in diary sexp.
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-08-31 15:31:54 -04:00
Tom Alexander
466716881e Fix macros consuming whitespace even when the exit matcher is calling for an exit.
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-08-31 15:11:29 -04:00
Tom Alexander
eb9c582fa5 '>' is allowed as a post character in text markup.
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-08-29 23:57:15 -04:00
Tom Alexander
214e895d85 Support backslash at the end of a macro. 2023-08-29 23:42:16 -04:00
41 changed files with 256 additions and 126 deletions

View File

@@ -99,29 +99,41 @@ spec:
runAfter: runAfter:
- fetch-repository - fetch-repository
- name: run-image - name: run-image
taskRef: taskSpec:
name: run-docker-image metadata: {}
stepTemplate:
name: ""
workingDir: "$(workspaces.source.path)"
workspaces:
- name: source
mountPath: /source
- name: cargo-cache
mountPath: /usr/local/cargo/registry
optional: true
steps:
- name: run
image: "$(params.IMAGE)"
command: []
args:
[
--no-default-features,
--features,
compare,
--no-fail-fast,
--lib,
--test,
test_loader,
]
workspaces: workspaces:
- name: source - name: source
workspace: git-source workspace: git-source
- name: cargo-cache - name: cargo-cache
workspace: cargo-cache workspace: cargo-cache
params:
- name: IMAGE
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
runAfter: runAfter:
- build-image - build-image
params:
- name: args
value:
[
--no-default-features,
--features,
compare,
--no-fail-fast,
--lib,
--test,
test_loader,
]
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
finally: finally:
- name: report-success - name: report-success
when: when:

View File

@@ -40,7 +40,7 @@ test:
.PHONY: dockertest .PHONY: dockertest
dockertest: dockertest:
> $(MAKE) -C docker/organic_test > $(MAKE) -C docker/organic_test
> docker run --init --rm -i -t -v "$$(readlink -f ./):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source organic-test --no-default-features --features compare --no-fail-fast --lib --test test_loader -- --test-threads $(TESTJOBS) > docker run --init --rm -i -t --read-only -v "$$(readlink -f ./):/source:ro" --mount type=tmpfs,destination=/tmp --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source organic-test --no-default-features --features compare --no-fail-fast --lib --test test_loader -- --test-threads $(TESTJOBS)
.PHONY: dockerclean .PHONY: dockerclean
dockerclean: dockerclean:
@@ -60,7 +60,7 @@ jaeger:
# 4317 for OTLP gRPC, 4318 for OTLP HTTP. We currently use gRPC but I forward both ports regardless. # 4317 for OTLP gRPC, 4318 for OTLP HTTP. We currently use gRPC but I forward both ports regardless.
# #
# These flags didn't help even though they seem like they would: --collector.queue-size=20000 --collector.num-workers=100 # These flags didn't help even though they seem like they would: --collector.queue-size=20000 --collector.num-workers=100
> docker run -d --rm --name organicdocker -p 4317:4317 -p 4318:4318 -p 16686:16686 -e COLLECTOR_OTLP_ENABLED=true jaegertracing/all-in-one:1.47 --collector.grpc-server.max-message-size=20000000 --collector.otlp.grpc.max-message-size=20000000 > docker run -d --rm --name organicdocker --read-only -p 4317:4317 -p 4318:4318 -p 16686:16686 -e COLLECTOR_OTLP_ENABLED=true jaegertracing/all-in-one:1.47 --collector.grpc-server.max-message-size=20000000 --collector.otlp.grpc.max-message-size=20000000
.PHONY: jaegerweb .PHONY: jaegerweb
jaegerweb: jaegerweb:

View File

@@ -87,7 +87,6 @@ fn is_expect_fail(name: &str) -> Option<&str> {
"autogen_greater_element_drawer_drawer_with_headline_inside" => Some("Apparently lines with :end: become their own paragraph. This odd behavior needs to be investigated more."), "autogen_greater_element_drawer_drawer_with_headline_inside" => Some("Apparently lines with :end: become their own paragraph. This odd behavior needs to be investigated more."),
"autogen_element_container_priority_footnote_definition_dynamic_block" => Some("Apparently broken begin lines become their own paragraph."), "autogen_element_container_priority_footnote_definition_dynamic_block" => Some("Apparently broken begin lines become their own paragraph."),
"autogen_lesser_element_paragraphs_paragraph_with_backslash_line_breaks" => Some("The text we're getting out of the parse tree is already processed to remove line breaks, so our comparison needs to take that into account."), "autogen_lesser_element_paragraphs_paragraph_with_backslash_line_breaks" => Some("The text we're getting out of the parse tree is already processed to remove line breaks, so our comparison needs to take that into account."),
"autogen_unicode_hearts" => Some("Unicode is coming out of emacs strange."),
_ => None, _ => None,
} }
} }

View File

@@ -29,8 +29,8 @@ endif
# NOTE: This target will write to folders underneath the git-root # NOTE: This target will write to folders underneath the git-root
.PHONY: run .PHONY: run
run: build run: build
docker run --rm --init -v "$$(readlink -f ../../):/source" --workdir=/source $(IMAGE_NAME) docker run --rm --init --read-only --mount type=tmpfs,destination=/tmp -v "$$(readlink -f ../../):/source" --workdir=/source $(IMAGE_NAME)
.PHONY: shell .PHONY: shell
shell: build shell: build
docker run --rm -i -t --entrypoint /bin/sh -v "$$(readlink -f ../../):/source" --workdir=/source $(IMAGE_NAME) docker run --rm -i -t --entrypoint /bin/sh --mount type=tmpfs,destination=/tmp -v "$$(readlink -f ../../):/source" --workdir=/source $(IMAGE_NAME)

View File

@@ -30,8 +30,8 @@ endif
# NOTE: This target will write to folders underneath the git-root # NOTE: This target will write to folders underneath the git-root
.PHONY: run .PHONY: run
run: build run: build
docker run --rm --init -v "$$(readlink -f ../../):/source" --workdir=/source --mount source=cargo-cache,target=/usr/local/cargo/registry $(IMAGE_NAME) docker run --rm --init --read-only --mount type=tmpfs,destination=/tmp -v "$$(readlink -f ../../):/source" --workdir=/source --mount source=cargo-cache,target=/usr/local/cargo/registry $(IMAGE_NAME)
.PHONY: shell .PHONY: shell
shell: build shell: build
docker run --rm -i -t --entrypoint /bin/sh -v "$$(readlink -f ../../):/source" --workdir=/source --mount source=cargo-cache,target=/usr/local/cargo/registry $(IMAGE_NAME) docker run --rm -i -t --entrypoint /bin/sh --mount type=tmpfs,destination=/tmp -v "$$(readlink -f ../../):/source" --workdir=/source --mount source=cargo-cache,target=/usr/local/cargo/registry $(IMAGE_NAME)

View File

@@ -26,6 +26,7 @@ RUN make DESTDIR="/root/dist" install
FROM rustlang/rust:nightly-alpine3.17 FROM rustlang/rust:nightly-alpine3.17
ENV LANG=en_US.UTF-8
RUN apk add --no-cache musl-dev ncurses gnutls RUN apk add --no-cache musl-dev ncurses gnutls
RUN cargo install --locked --no-default-features --features ci-autoclean cargo-cache RUN cargo install --locked --no-default-features --features ci-autoclean cargo-cache
COPY --from=build-emacs /root/dist/ / COPY --from=build-emacs /root/dist/ /

View File

@@ -29,8 +29,8 @@ endif
.PHONY: run .PHONY: run
run: build run: build
docker run --rm --init -v "$$(readlink -f ../../):/source:ro" --workdir=/source --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target $(IMAGE_NAME) --no-default-features --features compare --no-fail-fast --lib --test test_loader docker run --rm --init --read-only --mount type=tmpfs,destination=/tmp -v "$$(readlink -f ../../):/source:ro" --workdir=/source --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target $(IMAGE_NAME) --no-default-features --features compare --no-fail-fast --lib --test test_loader
.PHONY: shell .PHONY: shell
shell: build shell: build
docker run --rm -i -t --entrypoint /bin/sh -v "$$(readlink -f ../../):/source:ro" --workdir=/source --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target $(IMAGE_NAME) docker run --rm -i -t --entrypoint /bin/sh --mount type=tmpfs,destination=/tmp -v "$$(readlink -f ../../):/source:ro" --workdir=/source --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target $(IMAGE_NAME)

View File

@@ -0,0 +1,18 @@
#+begin_defun
foo
#+begin_lorem
,#+begin_center
bar
,#+end_center
ipsum
#+end_lorem
baz
#+end_defun
#+begin_center
#+begin_quote
#+begin_center
lorem
#+end_center
#+end_quote
#+end_center

View File

@@ -0,0 +1,12 @@
#+begin_defun
foo
#+begin_lorem
ipsum
#+end_lorem
bar
#+begin_center
#+begin_quote
baz
#+end_quote
#+end_center
#+end_defun

View File

@@ -0,0 +1,5 @@
#+begin_defun
foo
{{{bar(baz)}}}
#+end_defun

View File

@@ -0,0 +1 @@
- {{{foo(bar)}}} :: baz

View File

@@ -0,0 +1,2 @@
- foo

View File

@@ -0,0 +1 @@
%%(foo bar) ; baz

View File

@@ -0,0 +1 @@
foo ==>bar=.

View File

@@ -41,6 +41,7 @@ function launch_container {
if [ "$SHELL" != "YES" ]; then if [ "$SHELL" != "YES" ]; then
local features_joined=$(IFS=","; echo "${features[*]}") local features_joined=$(IFS=","; echo "${features[*]}")
additional_args+=(cargo run --no-default-features --features "$features_joined") additional_args+=(cargo run --no-default-features --features "$features_joined")
additional_flags+=(--read-only)
else else
additional_args+=(/bin/sh) additional_args+=(/bin/sh)
additional_flags+=(-t) additional_flags+=(-t)
@@ -50,7 +51,7 @@ function launch_container {
additional_flags+=(--env RUST_BACKTRACE=full) additional_flags+=(--env RUST_BACKTRACE=full)
fi fi
docker run "${additional_flags[@]}" --init --rm -i -v "$($REALPATH ./):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source --entrypoint "" organic-test "${additional_args[@]}" docker run "${additional_flags[@]}" --init --rm -i --mount type=tmpfs,destination=/tmp -v "$($REALPATH ./):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source --entrypoint "" organic-test "${additional_args[@]}"
} }
main "${@}" main "${@}"

View File

@@ -33,7 +33,7 @@ function get_test_names {
local test_file_full_path=$($REALPATH "$test_file") local test_file_full_path=$($REALPATH "$test_file")
local relative_to_samples=$($REALPATH --relative-to "$samples_dir" "$test_file_full_path") local relative_to_samples=$($REALPATH --relative-to "$samples_dir" "$test_file_full_path")
local without_extension="${relative_to_samples%.org}" local without_extension="${relative_to_samples%.org}"
echo "${without_extension/\//_}" | tr '[:upper:]' '[:lower:]' echo "autogen_${without_extension//\//_}" | tr '[:upper:]' '[:lower:]'
else else
echo "$test_file" | tr '[:upper:]' '[:lower:]' echo "$test_file" | tr '[:upper:]' '[:lower:]'
fi fi
@@ -56,7 +56,7 @@ cargo test --no-default-features --features compare --no-fail-fast --lib --test
EOF EOF
) )
docker run "${additional_flags[@]}" --init --rm -v "$($REALPATH ./):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source --entrypoint "" organic-test sh -c "$init_script" docker run "${additional_flags[@]}" --init --rm --read-only --mount type=tmpfs,destination=/tmp -v "$($REALPATH ./):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source --entrypoint "" organic-test sh -c "$init_script"
} }

View File

@@ -25,7 +25,7 @@ function get_test_names {
local test_file_full_path=$($REALPATH "$test_file") local test_file_full_path=$($REALPATH "$test_file")
local relative_to_samples=$($REALPATH --relative-to "$samples_dir" "$test_file_full_path") local relative_to_samples=$($REALPATH --relative-to "$samples_dir" "$test_file_full_path")
local without_extension="${relative_to_samples%.org}" local without_extension="${relative_to_samples%.org}"
echo "${without_extension/\//_}" | tr '[:upper:]' '[:lower:]' echo "${without_extension//\//_}" | tr '[:upper:]' '[:lower:]'
else else
echo "$test_file" | tr '[:upper:]' '[:lower:]' echo "$test_file" | tr '[:upper:]' '[:lower:]'
fi fi

View File

@@ -737,7 +737,7 @@ fn compare_greater_block<'s>(
let emacs_name = match rust.name.to_lowercase().as_str() { let emacs_name = match rust.name.to_lowercase().as_str() {
"center" => "center-block", "center" => "center-block",
"quote" => "quote-block", "quote" => "quote-block",
_ => todo!(), _ => "special-block",
}; };
if assert_name(emacs, emacs_name).is_err() { if assert_name(emacs, emacs_name).is_err() {
this_status = DiffStatus::Bad; this_status = DiffStatus::Bad;
@@ -1457,7 +1457,7 @@ fn compare_plain_text<'s>(
.as_atom()? .as_atom()?
.parse()?; .parse()?;
let emacs_text_length = end_ind - start_ind; let emacs_text_length = end_ind - start_ind;
if rust_source.len() != emacs_text_length { if rust_source.chars().count() != emacs_text_length {
this_status = DiffStatus::Bad; this_status = DiffStatus::Bad;
message = Some(format!( message = Some(format!(
"(emacs len != rust len) {:?} != {:?}", "(emacs len != rust len) {:?} != {:?}",

View File

@@ -13,7 +13,7 @@ fn is_slice_of(parent: &str, child: &str) -> bool {
/// Get the offset into source that the rust object exists at. /// Get the offset into source that the rust object exists at.
/// ///
/// These offsets are zero-based unlike the elisp ones. /// These offsets are zero-based unlike the elisp ones.
pub fn get_offsets<'s, S: Source<'s>>(source: &'s str, rust_object: &'s S) -> (usize, usize) { fn get_offsets<'s, S: Source<'s>>(source: &'s str, rust_object: &'s S) -> (usize, usize) {
let rust_object_source = rust_object.get_source(); let rust_object_source = rust_object.get_source();
assert!(is_slice_of(source, rust_object_source)); assert!(is_slice_of(source, rust_object_source));
let offset = rust_object_source.as_ptr() as usize - source.as_ptr() as usize; let offset = rust_object_source.as_ptr() as usize - source.as_ptr() as usize;
@@ -50,8 +50,11 @@ pub fn assert_bounds<'s, S: Source<'s>>(
standard_properties.end.ok_or("Token should have an end.")?, standard_properties.end.ok_or("Token should have an end.")?,
); );
let (rust_begin, rust_end) = get_offsets(source, rust); let (rust_begin, rust_end) = get_offsets(source, rust);
if (rust_begin + 1) != begin || (rust_end + 1) != end { let rust_begin_char_offset = (&source[..rust_begin]).chars().count();
Err(format!("Rust bounds (in bytes) ({rust_begin}, {rust_end}) do not match emacs bounds ({emacs_begin}, {emacs_end})", rust_begin = rust_begin + 1, rust_end = rust_end + 1, emacs_begin=begin, emacs_end=end))?; let rust_end_char_offset =
rust_begin_char_offset + (&source[rust_begin..rust_end]).chars().count();
if (rust_begin_char_offset + 1) != begin || (rust_end_char_offset + 1) != end {
Err(format!("Rust bounds (in chars) ({rust_begin}, {rust_end}) do not match emacs bounds ({emacs_begin}, {emacs_end})", rust_begin = rust_begin_char_offset + 1, rust_end = rust_end_char_offset + 1, emacs_begin=begin, emacs_end=end))?;
} }
Ok(()) Ok(())

View File

@@ -5,6 +5,7 @@ use nom::combinator::recognize;
use nom::multi::many_till; use nom::multi::many_till;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use crate::error::Res; use crate::error::Res;
use crate::parser::exiting::ExitClass; use crate::parser::exiting::ExitClass;
@@ -26,6 +27,8 @@ pub fn angle_link<'r, 's>(
let (remaining, _separator) = tag(":")(remaining)?; let (remaining, _separator) = tag(":")(remaining)?;
let (remaining, path) = path_angle(context, remaining)?; let (remaining, path) = path_angle(context, remaining)?;
let (remaining, _) = tag(">")(remaining)?; let (remaining, _) = tag(">")(remaining)?;
let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,

View File

@@ -2,7 +2,6 @@ use nom::branch::alt;
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::bytes::complete::tag_no_case; use nom::bytes::complete::tag_no_case;
use nom::character::complete::anychar; use nom::character::complete::anychar;
use nom::character::complete::space0;
use nom::combinator::opt; use nom::combinator::opt;
use nom::combinator::recognize; use nom::combinator::recognize;
use nom::combinator::verify; use nom::combinator::verify;
@@ -14,6 +13,7 @@ use nom::sequence::tuple;
use super::citation_reference::must_balance_bracket; use super::citation_reference::must_balance_bracket;
use super::org_source::BracketDepth; use super::org_source::BracketDepth;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::Res; use crate::error::Res;
@@ -48,7 +48,8 @@ pub fn citation<'r, 's>(
parser_with_context!(global_suffix)(context), parser_with_context!(global_suffix)(context),
))))(remaining)?; ))))(remaining)?;
let (remaining, _) = tag("]")(remaining)?; let (remaining, _) = tag("]")(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,

View File

@@ -1,9 +1,12 @@
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::line_ending; use nom::character::complete::line_ending;
use nom::character::complete::space0; use nom::character::complete::space0;
use nom::combinator::eof; use nom::combinator::eof;
use nom::combinator::opt;
use nom::combinator::recognize; use nom::combinator::recognize;
use nom::multi::many_till;
use nom::sequence::tuple; use nom::sequence::tuple;
use super::org_source::OrgSource; use super::org_source::OrgSource;
@@ -24,6 +27,11 @@ pub fn diary_sexp<'r, 's>(
let (remaining, _clock) = tag("%%")(remaining)?; let (remaining, _clock) = tag("%%")(remaining)?;
let (remaining, _gap_whitespace) = space0(remaining)?; let (remaining, _gap_whitespace) = space0(remaining)?;
let (remaining, _sexp) = recognize(sexp)(remaining)?; let (remaining, _sexp) = recognize(sexp)(remaining)?;
let (remaining, _trailing_comment) = opt(tuple((
space0,
tag(";"),
many_till(anychar, alt((line_ending, eof))),
)))(remaining)?;
let (remaining, _trailing_whitespace) = let (remaining, _trailing_whitespace) =
recognize(tuple((space0, alt((line_ending, eof)))))(remaining)?; recognize(tuple((space0, alt((line_ending, eof)))))(remaining)?;

View File

@@ -128,7 +128,7 @@ fn _detect_element<'r, 's>(
input: OrgSource<'s>, input: OrgSource<'s>,
can_be_paragraph: bool, can_be_paragraph: bool,
) -> Res<OrgSource<'s>, ()> { ) -> Res<OrgSource<'s>, ()> {
if detect_plain_list(context, input).is_ok() { if detect_plain_list(input).is_ok() {
return Ok((input, ())); return Ok((input, ()));
} }
if _element(context, input, can_be_paragraph).is_ok() { if _element(context, input, can_be_paragraph).is_ok() {

View File

@@ -2,12 +2,12 @@ use nom::branch::alt;
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::bytes::complete::tag_no_case; use nom::bytes::complete::tag_no_case;
use nom::character::complete::satisfy; use nom::character::complete::satisfy;
use nom::character::complete::space0;
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 super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
@@ -440,7 +440,8 @@ pub fn entity<'r, '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, _) = alt((tag("{}"), peek(recognize(entity_end))))(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((

View File

@@ -8,6 +8,7 @@ use nom::multi::many_till;
use nom::sequence::tuple; 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::Context; use super::Context;
use crate::error::Res; use crate::error::Res;
use crate::parser::exiting::ExitClass; use crate::parser::exiting::ExitClass;
@@ -35,6 +36,8 @@ pub fn export_snippet<'r, 's>(
parser_with_context!(contents)(&parser_context), parser_with_context!(contents)(&parser_context),
)))(remaining)?; )))(remaining)?;
let (remaining, _) = tag("@@")(remaining)?; let (remaining, _) = tag("@@")(remaining)?;
let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,

View File

@@ -80,21 +80,10 @@ fn footnote_definition_end<'r, 's>(
context: Context<'r, 's>, context: Context<'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
) -> Res<OrgSource<'s>, OrgSource<'s>> { ) -> Res<OrgSource<'s>, OrgSource<'s>> {
let allow_nesting_context =
context.with_additional_node(ContextElement::Context("allow nesting footnotes"));
let footnote_definition_matcher = parser_with_context!(footnote_definition)(
if immediate_in_section(context, "footnote definition") {
&allow_nesting_context
} else {
context
},
);
let maybe_consume_trailing_whitespace_matcher =
parser_with_context!(maybe_consume_trailing_whitespace)(context);
let (remaining, source) = alt(( let (remaining, source) = alt((
recognize(tuple(( recognize(tuple((
maybe_consume_trailing_whitespace_matcher, parser_with_context!(maybe_consume_trailing_whitespace)(context),
footnote_definition_matcher, detect_footnote_definition,
))), ))),
recognize(tuple(( recognize(tuple((
start_of_line, start_of_line,
@@ -107,6 +96,12 @@ fn footnote_definition_end<'r, 's>(
Ok((remaining, source)) Ok((remaining, source))
} }
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn detect_footnote_definition<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
tuple((start_of_line, tag_no_case("[fn:"), label, tag("]")))(input)?;
Ok((input, ()))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@@ -1,13 +1,13 @@
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::bytes::complete::tag_no_case;
use nom::character::complete::space0;
use nom::combinator::verify; use nom::combinator::verify;
use nom::multi::many_till; use nom::multi::many_till;
use super::org_source::BracketDepth; use super::org_source::BracketDepth;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::parser_context::ContextElement; use super::parser_context::ContextElement;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
@@ -54,7 +54,8 @@ fn anonymous_footnote<'r, 's>(
)(remaining)?; )(remaining)?;
let (remaining, _) = tag("]")(remaining)?; let (remaining, _) = tag("]")(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,
@@ -89,7 +90,8 @@ fn inline_footnote<'r, 's>(
)(remaining)?; )(remaining)?;
let (remaining, _) = tag("]")(remaining)?; let (remaining, _) = tag("]")(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,
@@ -103,13 +105,14 @@ fn inline_footnote<'r, 's>(
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn footnote_reference_only<'r, 's>( fn footnote_reference_only<'r, 's>(
_context: Context<'r, 's>, context: Context<'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
) -> Res<OrgSource<'s>, FootnoteReference<'s>> { ) -> Res<OrgSource<'s>, FootnoteReference<'s>> {
let (remaining, _) = tag_no_case("[fn:")(input)?; let (remaining, _) = tag_no_case("[fn:")(input)?;
let (remaining, label_contents) = label(remaining)?; let (remaining, label_contents) = label(remaining)?;
let (remaining, _) = tag("]")(remaining)?; let (remaining, _) = tag("]")(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,

View File

@@ -12,6 +12,7 @@ use nom::multi::many_till;
use nom::sequence::tuple; use nom::sequence::tuple;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::in_section;
use super::Context; use super::Context;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
@@ -26,7 +27,6 @@ use crate::parser::source::SetSource;
use crate::parser::util::blank_line; use crate::parser::util::blank_line;
use crate::parser::util::exit_matcher_parser; use crate::parser::util::exit_matcher_parser;
use crate::parser::util::get_consumed; use crate::parser::util::get_consumed;
use crate::parser::util::immediate_in_section;
use crate::parser::util::start_of_line; use crate::parser::util::start_of_line;
use crate::parser::Element; use crate::parser::Element;
use crate::parser::Paragraph; use crate::parser::Paragraph;
@@ -49,11 +49,11 @@ pub fn greater_block<'r, 's>(
}), }),
))(remaining)?; ))(remaining)?;
let context_name = match Into::<&str>::into(name).to_lowercase().as_str() { let context_name = match Into::<&str>::into(name).to_lowercase().as_str() {
"center" => "center block", "center" => "center block".to_owned(),
"quote" => "quote block", "quote" => "quote block".to_owned(),
_ => "greater block", name @ _ => format!("special block {}", name),
}; };
if immediate_in_section(context, context_name) { if in_section(context, context_name.as_str()) {
return Err(nom::Err::Error(CustomError::MyError(MyError( return Err(nom::Err::Error(CustomError::MyError(MyError(
"Cannot nest objects of the same element".into(), "Cannot nest objects of the same element".into(),
)))); ))));
@@ -63,7 +63,7 @@ pub fn greater_block<'r, 's>(
let (remaining, _nl) = line_ending(remaining)?; let (remaining, _nl) = line_ending(remaining)?;
let parser_context = context let parser_context = context
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true)) .with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
.with_additional_node(ContextElement::Context(context_name)) .with_additional_node(ContextElement::Context(context_name.as_str()))
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Alpha, class: ExitClass::Alpha,
exit_matcher: &exit_with_name, exit_matcher: &exit_with_name,

View File

@@ -4,7 +4,6 @@ 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::character::complete::line_ending;
use nom::character::complete::one_of; use nom::character::complete::one_of;
use nom::character::complete::space0;
use nom::combinator::opt; use nom::combinator::opt;
use nom::combinator::recognize; use nom::combinator::recognize;
use nom::combinator::verify; use nom::combinator::verify;
@@ -12,6 +11,7 @@ use nom::multi::many_till;
use super::org_source::BracketDepth; use super::org_source::BracketDepth;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
@@ -34,7 +34,8 @@ pub fn inline_babel_call<'r, 's>(
let (remaining, _header1) = opt(parser_with_context!(header)(context))(remaining)?; let (remaining, _header1) = opt(parser_with_context!(header)(context))(remaining)?;
let (remaining, _argument) = argument(context, remaining)?; let (remaining, _argument) = argument(context, remaining)?;
let (remaining, _header2) = opt(parser_with_context!(header)(context))(remaining)?; let (remaining, _header2) = opt(parser_with_context!(header)(context))(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,

View File

@@ -4,7 +4,6 @@ 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::character::complete::line_ending;
use nom::character::complete::one_of; use nom::character::complete::one_of;
use nom::character::complete::space0;
use nom::combinator::opt; use nom::combinator::opt;
use nom::combinator::recognize; use nom::combinator::recognize;
use nom::combinator::verify; use nom::combinator::verify;
@@ -14,6 +13,7 @@ use tracing::span;
use super::org_source::BracketDepth; use super::org_source::BracketDepth;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
@@ -35,7 +35,8 @@ pub fn inline_source_block<'r, 's>(
let (remaining, _) = lang(context, remaining)?; let (remaining, _) = lang(context, remaining)?;
let (remaining, _header1) = opt(parser_with_context!(header)(context))(remaining)?; let (remaining, _header1) = opt(parser_with_context!(header)(context))(remaining)?;
let (remaining, _body) = body(context, remaining)?; let (remaining, _body) = body(context, remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,

View File

@@ -5,7 +5,6 @@ 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;
use nom::character::complete::one_of; use nom::character::complete::one_of;
use nom::character::complete::space0;
use nom::combinator::peek; use nom::combinator::peek;
use nom::combinator::recognize; use nom::combinator::recognize;
use nom::combinator::verify; use nom::combinator::verify;
@@ -14,6 +13,7 @@ use nom::multi::many_till;
use nom::sequence::tuple; 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::Context; use super::Context;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
@@ -36,7 +36,8 @@ pub fn latex_fragment<'r, 's>(
parser_with_context!(dollar_char_fragment)(context), parser_with_context!(dollar_char_fragment)(context),
parser_with_context!(bordered_dollar_fragment)(context), parser_with_context!(bordered_dollar_fragment)(context),
))(input)?; ))(input)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,

View File

@@ -1,6 +1,5 @@
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::character::complete::anychar; use nom::character::complete::anychar;
use nom::character::complete::space0;
use nom::combinator::not; use nom::combinator::not;
use nom::combinator::opt; use nom::combinator::opt;
use nom::combinator::peek; use nom::combinator::peek;
@@ -9,7 +8,9 @@ use nom::multi::many0;
use nom::multi::separated_list0; use nom::multi::separated_list0;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use crate::error::CustomError;
use crate::error::Res; use crate::error::Res;
use crate::parser::object::OrgMacro; use crate::parser::object::OrgMacro;
use crate::parser::parser_with_context::parser_with_context; use crate::parser::parser_with_context::parser_with_context;
@@ -25,7 +26,8 @@ pub fn org_macro<'r, 's>(
let (remaining, macro_name) = org_macro_name(context, remaining)?; let (remaining, macro_name) = org_macro_name(context, remaining)?;
let (remaining, macro_args) = opt(parser_with_context!(org_macro_args)(context))(remaining)?; let (remaining, macro_args) = opt(parser_with_context!(org_macro_args)(context))(remaining)?;
let (remaining, _) = tag("}}}")(remaining)?; let (remaining, _) = tag("}}}")(remaining)?;
let (remaining, _trailing_whitespace) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
@@ -86,6 +88,11 @@ fn org_macro_arg<'r, 's>(
} }
if next_char == '\\' { if next_char == '\\' {
escaping = true; escaping = true;
if peek(tag::<_, _, CustomError<_>>(")"))(new_remaining).is_ok() {
// Special case for backslash at the end of a macro
remaining = new_remaining;
break;
}
} }
if next_char == ',' || next_char == ')' { if next_char == ',' || next_char == ')' {
break; break;

View File

@@ -38,10 +38,7 @@ use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::parser::util::start_of_line; use crate::parser::util::start_of_line;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub fn detect_plain_list<'r, 's>( pub fn detect_plain_list<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
_context: Context<'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, ()> {
if verify( if verify(
tuple(( tuple((
start_of_line, start_of_line,
@@ -69,6 +66,7 @@ pub fn plain_list<'r, 's>(
) -> Res<OrgSource<'s>, PlainList<'s>> { ) -> Res<OrgSource<'s>, PlainList<'s>> {
let parser_context = context let parser_context = context
.with_additional_node(ContextElement::Context("plain list")) .with_additional_node(ContextElement::Context("plain list"))
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Beta, class: ExitClass::Beta,
exit_matcher: &plain_list_end, exit_matcher: &plain_list_end,
@@ -143,29 +141,32 @@ pub fn plain_list_item<'r, 's>(
Into::<&str>::into(bull) != "*" || indent_level > 0 Into::<&str>::into(bull) != "*" || indent_level > 0
})(remaining)?; })(remaining)?;
let maybe_contentless_item: Res<OrgSource<'_>, OrgSource<'_>> = eof(remaining); let (remaining, maybe_tag) = opt(tuple((
space1,
parser_with_context!(item_tag)(context),
tag(" ::"),
)))(remaining)?;
let maybe_contentless_item: Res<OrgSource<'_>, OrgSource<'_>> =
peek(recognize(tuple((many0(blank_line), eof))))(remaining);
match maybe_contentless_item { match maybe_contentless_item {
Ok((rem, _ws)) => { Ok((_rem, _ws)) => {
let source = get_consumed(input, rem); let (remaining, _trailing_ws) = opt(blank_line)(remaining)?;
let source = get_consumed(input, remaining);
return Ok(( return Ok((
rem, remaining,
PlainListItem { PlainListItem {
source: source.into(), source: source.into(),
indentation: indent_level, indentation: indent_level,
bullet: bull.into(), bullet: bull.into(),
tag: Vec::new(), tag: maybe_tag
.map(|(_ws, item_tag, _divider)| item_tag)
.unwrap_or(Vec::new()),
children: Vec::new(), children: Vec::new(),
}, },
)); ));
} }
Err(_) => {} Err(_) => {}
}; };
let (remaining, maybe_tag) = opt(tuple((
space1,
parser_with_context!(item_tag)(context),
tag(" ::"),
)))(remaining)?;
let (remaining, _ws) = item_tag_post_gap(context, remaining)?; let (remaining, _ws) = item_tag_post_gap(context, remaining)?;
let exit_matcher = plain_list_item_end(indent_level); let exit_matcher = plain_list_item_end(indent_level);
let parser_context = context let parser_context = context
@@ -175,14 +176,24 @@ pub fn plain_list_item<'r, 's>(
exit_matcher: &exit_matcher, exit_matcher: &exit_matcher,
})); }));
let (remaining, (children, _exit_contents)) = many_till( let (mut remaining, (mut children, _exit_contents)) = many_till(
parser_with_context!(element(true))(&parser_context), include_input(parser_with_context!(element(true))(&parser_context)),
alt(( parser_with_context!(exit_matcher_parser)(&parser_context),
peek(recognize(tuple((start_of_line, many0(blank_line), eof)))),
parser_with_context!(exit_matcher_parser)(&parser_context),
)),
)(remaining)?; )(remaining)?;
if !children.is_empty() && !context.should_consume_trailing_whitespace() {
let final_item_context =
parser_context.with_additional_node(ContextElement::ConsumeTrailingWhitespace(false));
let (final_child_start, _original_final_child) = children
.pop()
.expect("if-statement already checked that children was non-empty.");
let (remain, reparsed_final_element) = include_input(parser_with_context!(element(true))(
&final_item_context,
))(final_child_start)?;
remaining = remain;
children.push(reparsed_final_element);
}
let (remaining, _trailing_ws) = let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
@@ -196,11 +207,23 @@ pub fn plain_list_item<'r, 's>(
tag: maybe_tag tag: maybe_tag
.map(|(_ws, item_tag, _divider)| item_tag) .map(|(_ws, item_tag, _divider)| item_tag)
.unwrap_or(Vec::new()), .unwrap_or(Vec::new()),
children, children: children.into_iter().map(|(_start, item)| item).collect(),
}, },
)); ));
} }
fn include_input<'s, F, O>(
mut inner: F,
) -> impl FnMut(OrgSource<'s>) -> Res<OrgSource<'s>, (OrgSource<'s>, O)>
where
F: FnMut(OrgSource<'s>) -> Res<OrgSource<'s>, O>,
{
move |input: OrgSource<'_>| {
let (remaining, output) = inner(input)?;
Ok((remaining, (input, output)))
}
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn bullet<'s>(i: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> { fn bullet<'s>(i: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
alt(( alt((
@@ -496,24 +519,21 @@ dolar"#,
r#"+ r#"+
"#, "#,
); );
let initial_context: ContextTree<'_, '_> = ContextTree::new(); let result = detect_plain_list(input);
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 initial_context: ContextTree<'_, '_> = ContextTree::new(); let result = detect_plain_list(input);
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 initial_context: ContextTree<'_, '_> = ContextTree::new(); let result = detect_plain_list(input);
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());
} }
@@ -521,8 +541,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 initial_context: ContextTree<'_, '_> = ContextTree::new(); let result = detect_plain_list(input);
let result = detect_plain_list(&initial_context, input);
assert!(result.is_ok()); assert!(result.is_ok());
} }
} }

View File

@@ -6,6 +6,7 @@ use nom::combinator::verify;
use nom::multi::many_till; use nom::multi::many_till;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use super::Object; use super::Object;
use crate::error::CustomError; use crate::error::CustomError;
@@ -104,7 +105,8 @@ pub fn radio_target<'r, 's>(
)(remaining)?; )(remaining)?;
let (remaining, _closing) = tag(">>>")(remaining)?; let (remaining, _closing) = tag(">>>")(remaining)?;
let (remaining, _trailing_whitespace) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,

View File

@@ -3,13 +3,13 @@ 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::one_of; use nom::character::complete::one_of;
use nom::character::complete::space0;
use nom::combinator::verify; use nom::combinator::verify;
use nom::multi::many_till; use nom::multi::many_till;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::parser_with_context::parser_with_context; use super::parser_with_context::parser_with_context;
use super::util::get_consumed; use super::util::get_consumed;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use super::Object; use super::Object;
use super::RegularLink; use super::RegularLink;
@@ -39,7 +39,8 @@ pub fn regular_link_without_description<'r, 's>(
let (remaining, _opening_bracket) = tag("[[")(input)?; let (remaining, _opening_bracket) = tag("[[")(input)?;
let (remaining, _path) = pathreg(context, remaining)?; let (remaining, _path) = pathreg(context, remaining)?;
let (remaining, _closing_bracket) = tag("]]")(remaining)?; let (remaining, _closing_bracket) = tag("]]")(remaining)?;
let (remaining, _trailing_whitespace) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,
@@ -59,7 +60,8 @@ pub fn regular_link_with_description<'r, 's>(
let (remaining, _closing_bracket) = tag("][")(remaining)?; let (remaining, _closing_bracket) = tag("][")(remaining)?;
let (remaining, _description) = description(context, remaining)?; let (remaining, _description) = description(context, remaining)?;
let (remaining, _closing_bracket) = tag("]]")(remaining)?; let (remaining, _closing_bracket) = tag("]]")(remaining)?;
let (remaining, _trailing_whitespace) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,

View File

@@ -1,10 +1,10 @@
use nom::branch::alt; use nom::branch::alt;
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::character::complete::space0;
use nom::combinator::recognize; use nom::combinator::recognize;
use nom::sequence::tuple; 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::Context; use super::Context;
use crate::error::Res; use crate::error::Res;
use crate::parser::parser_with_context::parser_with_context; use crate::parser::parser_with_context::parser_with_context;
@@ -23,12 +23,13 @@ pub fn statistics_cookie<'r, 's>(
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub fn percent_statistics_cookie<'r, 's>( pub fn percent_statistics_cookie<'r, 's>(
_context: Context<'r, 's>, context: Context<'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
) -> Res<OrgSource<'s>, StatisticsCookie<'s>> { ) -> Res<OrgSource<'s>, StatisticsCookie<'s>> {
let (remaining, source) = let (remaining, source) =
recognize(tuple((tag("["), nom::character::complete::u64, tag("%]"))))(input)?; recognize(tuple((tag("["), nom::character::complete::u64, tag("%]"))))(input)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
Ok(( Ok((
remaining, remaining,
StatisticsCookie { StatisticsCookie {
@@ -39,7 +40,7 @@ pub fn percent_statistics_cookie<'r, 's>(
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub fn fraction_statistics_cookie<'r, 's>( pub fn fraction_statistics_cookie<'r, 's>(
_context: Context<'r, 's>, context: Context<'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
) -> Res<OrgSource<'s>, StatisticsCookie<'s>> { ) -> Res<OrgSource<'s>, StatisticsCookie<'s>> {
let (remaining, source) = recognize(tuple(( let (remaining, source) = recognize(tuple((
@@ -49,7 +50,8 @@ pub fn fraction_statistics_cookie<'r, 's>(
nom::character::complete::u64, nom::character::complete::u64,
tag("]"), tag("]"),
)))(input)?; )))(input)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
Ok(( Ok((
remaining, remaining,
StatisticsCookie { StatisticsCookie {

View File

@@ -2,7 +2,6 @@ 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::one_of; use nom::character::complete::one_of;
use nom::character::complete::space0;
use nom::combinator::map; use nom::combinator::map;
use nom::combinator::not; use nom::combinator::not;
use nom::combinator::opt; use nom::combinator::opt;
@@ -13,6 +12,7 @@ use nom::multi::many_till;
use super::org_source::BracketDepth; use super::org_source::BracketDepth;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use super::Object; use super::Object;
use crate::error::CustomError; use crate::error::CustomError;
@@ -37,7 +37,8 @@ pub fn subscript<'r, 's>(
let (remaining, _) = tag("_")(input)?; let (remaining, _) = tag("_")(input)?;
pre(context, input)?; pre(context, input)?;
let (remaining, _body) = script_body(context, remaining)?; let (remaining, _body) = script_body(context, remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,
@@ -56,7 +57,8 @@ pub fn superscript<'r, 's>(
let (remaining, _) = tag("^")(input)?; let (remaining, _) = tag("^")(input)?;
pre(context, input)?; pre(context, input)?;
let (remaining, _body) = script_body(context, remaining)?; let (remaining, _body) = script_body(context, remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,

View File

@@ -1,13 +1,13 @@
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::character::complete::anychar; use nom::character::complete::anychar;
use nom::character::complete::one_of; use nom::character::complete::one_of;
use nom::character::complete::space0;
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::many_till; use nom::multi::many_till;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
@@ -49,7 +49,8 @@ pub fn target<'r, 's>(
)))); ))));
} }
let (remaining, _) = tag(">>")(remaining)?; let (remaining, _) = tag(">>")(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((

View File

@@ -17,6 +17,7 @@ use tracing::span;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::radio_link::RematchObject; use super::radio_link::RematchObject;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use super::Context;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
@@ -204,7 +205,8 @@ fn _text_markup_object<'r, 's, 'x>(
} }
let (remaining, _close) = text_markup_end_specialized(context, remaining)?; let (remaining, _close) = text_markup_end_specialized(context, remaining)?;
let (remaining, _trailing_whitespace) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
Ok((remaining, children)) Ok((remaining, children))
} }
@@ -254,7 +256,8 @@ fn _text_markup_string<'r, 's, 'x>(
} }
let (remaining, _close) = text_markup_end_specialized(context, remaining)?; let (remaining, _close) = text_markup_end_specialized(context, remaining)?;
let (remaining, _trailing_whitespace) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
Ok((remaining, contents)) Ok((remaining, contents))
} }
@@ -277,7 +280,7 @@ pub fn pre<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgSo
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub fn post<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> { pub fn post<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
let (remaining, _) = alt((recognize(one_of(" \r\n\t-.,;:!?')}[\">")), line_ending))(input)?; let (remaining, _) = alt((recognize(one_of(" \r\n\t-.,;:!?')}[\"")), line_ending))(input)?;
Ok((remaining, ())) Ok((remaining, ()))
} }

View File

@@ -3,7 +3,6 @@ use nom::bytes::complete::tag;
use nom::character::complete::anychar; use nom::character::complete::anychar;
use nom::character::complete::digit1; use nom::character::complete::digit1;
use nom::character::complete::one_of; use nom::character::complete::one_of;
use nom::character::complete::space0;
use nom::character::complete::space1; use nom::character::complete::space1;
use nom::combinator::opt; use nom::combinator::opt;
use nom::combinator::recognize; use nom::combinator::recognize;
@@ -12,6 +11,7 @@ use nom::multi::many_till;
use nom::sequence::tuple; 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::Context; use super::Context;
use crate::error::Res; use crate::error::Res;
use crate::parser::exiting::ExitClass; use crate::parser::exiting::ExitClass;
@@ -49,7 +49,8 @@ fn diary_timestamp<'r, 's>(
let (remaining, _) = tag("<%%(")(input)?; let (remaining, _) = tag("<%%(")(input)?;
let (remaining, _body) = sexp(context, remaining)?; let (remaining, _body) = sexp(context, remaining)?;
let (remaining, _) = tag(")>")(remaining)?; let (remaining, _) = tag(")>")(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
@@ -112,7 +113,8 @@ fn active_timestamp<'r, 's>(
)))(remaining)?; )))(remaining)?;
let (remaining, _) = tag(">")(remaining)?; let (remaining, _) = tag(">")(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
@@ -145,7 +147,8 @@ fn inactive_timestamp<'r, 's>(
)))(remaining)?; )))(remaining)?;
let (remaining, _) = tag("]")(remaining)?; let (remaining, _) = tag("]")(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
@@ -166,7 +169,8 @@ fn active_date_range_timestamp<'r, 's>(
let (remaining, _separator) = tag("--")(remaining)?; let (remaining, _separator) = tag("--")(remaining)?;
let (remaining, _second_timestamp) = active_timestamp(context, remaining)?; let (remaining, _second_timestamp) = active_timestamp(context, remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
@@ -206,7 +210,8 @@ fn active_time_range_timestamp<'r, 's>(
)))(remaining)?; )))(remaining)?;
let (remaining, _) = tag(">")(remaining)?; let (remaining, _) = tag(">")(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
@@ -227,7 +232,8 @@ fn inactive_date_range_timestamp<'r, 's>(
let (remaining, _separator) = tag("--")(remaining)?; let (remaining, _separator) = tag("--")(remaining)?;
let (remaining, _second_timestamp) = inactive_timestamp(context, remaining)?; let (remaining, _second_timestamp) = inactive_timestamp(context, remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
@@ -267,7 +273,8 @@ fn inactive_time_range_timestamp<'r, 's>(
)))(remaining)?; )))(remaining)?;
let (remaining, _) = tag("]")(remaining)?; let (remaining, _) = tag("]")(remaining)?;
let (remaining, _) = space0(remaining)?; let (remaining, _trailing_whitespace) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((

View File

@@ -68,6 +68,18 @@ pub fn element_trailing_whitespace<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s
alt((eof, recognize(many0(blank_line))))(input) alt((eof, recognize(many0(blank_line))))(input)
} }
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub fn maybe_consume_object_trailing_whitespace_if_not_exiting<'r, 's>(
context: Context<'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Option<OrgSource<'s>>> {
if exit_matcher_parser(context, input).is_err() {
opt(space0)(input)
} else {
Ok((input, None))
}
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub fn maybe_consume_trailing_whitespace_if_not_exiting<'r, 's>( pub fn maybe_consume_trailing_whitespace_if_not_exiting<'r, 's>(
context: Context<'r, 's>, context: Context<'r, 's>,