Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d90ff5891b | ||
|
|
a3c01805b8 | ||
|
|
e3d755317d | ||
|
|
b89607fc8b | ||
|
|
51c4e2b62a | ||
|
|
a6561d37fb | ||
|
|
4e8b3eb422 | ||
|
|
2c31590974 | ||
|
|
28b2d27054 | ||
|
|
84edd10864 | ||
|
|
728a79f9a4 | ||
|
|
ad4ef50669 | ||
|
|
12cbb89861 | ||
|
|
7c471ab32e | ||
|
|
400f53e440 | ||
|
|
028aeb70aa | ||
|
|
70fafd801e | ||
|
|
bdba495f69 | ||
|
|
b0392ad6fb | ||
|
|
1c142b68c6 | ||
|
|
9060f9b26d | ||
|
|
d3c733c5ad | ||
|
|
275b4b53d1 | ||
|
|
d38e198258 | ||
|
|
27cf6c0462 | ||
|
|
c7d5c89a60 | ||
|
|
ee02e07717 | ||
|
|
a7330e38e4 | ||
|
|
08eb59acd3 | ||
|
|
da1ce2717d | ||
|
|
a8f277efe5 | ||
|
|
7f6f22717b | ||
|
|
0ef141d65e | ||
|
|
71180d19fb | ||
|
|
33091112a5 | ||
|
|
5997567233 | ||
|
|
2915a81edc | ||
|
|
df79cbd0b7 | ||
|
|
a7b9eb9db4 | ||
|
|
d262833f9b | ||
|
|
0d438a8e0f | ||
|
|
0b009511ff | ||
|
|
3bdb24ad88 | ||
|
|
fdf35ba23c | ||
|
|
cd69e08516 | ||
|
|
b54c6d366c | ||
|
|
15e8d1ab77 | ||
|
|
8502a8830d | ||
|
|
74a6101de7 | ||
|
|
ba57eb16fd | ||
|
|
c309d14776 | ||
|
|
0d728510d7 | ||
|
|
22e9bc991f | ||
|
|
564104f1e8 | ||
|
|
12ad3b09f0 | ||
|
|
eabffe5ecc | ||
|
|
b47029fdbb | ||
|
|
25b8c80d4e | ||
|
|
54825538e4 | ||
|
|
66d10a7a1b | ||
|
|
acf1205e75 | ||
|
|
2cd2f7570c | ||
|
|
f16a554154 | ||
|
|
a40a504f94 | ||
|
|
80d77ff5d6 | ||
|
|
ee92049e5d | ||
|
|
510985e97c | ||
|
|
949d0989f4 | ||
|
|
2a4d22bdd4 | ||
|
|
7a903acedc | ||
|
|
5171326d63 | ||
|
|
67f79aeb51 | ||
|
|
b2383d9f93 | ||
|
|
9e2a323f6f | ||
|
|
0fcb3f73f9 | ||
|
|
bfc9e7f58d | ||
|
|
b5f0521b56 | ||
|
|
2048d8f0b6 | ||
|
|
466716881e | ||
|
|
eb9c582fa5 | ||
|
|
214e895d85 | ||
|
|
db3086743c | ||
|
|
207a0546b0 | ||
|
|
e9480fd156 |
203
.lighthouse/pipeline-foreign-document-test.yaml
Normal file
203
.lighthouse/pipeline-foreign-document-test.yaml
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
apiVersion: tekton.dev/v1beta1
|
||||||
|
kind: PipelineRun
|
||||||
|
metadata:
|
||||||
|
name: rust-foreign-document-test
|
||||||
|
spec:
|
||||||
|
pipelineSpec:
|
||||||
|
timeouts:
|
||||||
|
pipeline: "2h0m0s"
|
||||||
|
tasks: "1h0m40s"
|
||||||
|
finally: "0h30m0s"
|
||||||
|
params:
|
||||||
|
- name: image-name
|
||||||
|
description: The name for the built image
|
||||||
|
type: string
|
||||||
|
- name: path-to-image-context
|
||||||
|
description: The path to the build context
|
||||||
|
type: string
|
||||||
|
- name: path-to-dockerfile
|
||||||
|
description: The path to the Dockerfile
|
||||||
|
type: string
|
||||||
|
tasks:
|
||||||
|
- name: do-stuff
|
||||||
|
taskSpec:
|
||||||
|
metadata: {}
|
||||||
|
stepTemplate:
|
||||||
|
image: alpine:3.18
|
||||||
|
name: ""
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 600Mi
|
||||||
|
workingDir: /workspace/source
|
||||||
|
steps:
|
||||||
|
- image: alpine:3.18
|
||||||
|
name: do-stuff-step
|
||||||
|
script: |
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
echo "hello world"
|
||||||
|
- name: report-pending
|
||||||
|
taskRef:
|
||||||
|
name: gitea-set-status
|
||||||
|
runAfter:
|
||||||
|
- fetch-repository
|
||||||
|
params:
|
||||||
|
- name: CONTEXT
|
||||||
|
value: "$(params.JOB_NAME)"
|
||||||
|
- name: REPO_FULL_NAME
|
||||||
|
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
|
||||||
|
- name: GITEA_HOST_URL
|
||||||
|
value: code.fizz.buzz
|
||||||
|
- name: SHA
|
||||||
|
value: "$(tasks.fetch-repository.results.commit)"
|
||||||
|
- name: DESCRIPTION
|
||||||
|
value: "Build $(params.JOB_NAME) has started"
|
||||||
|
- name: STATE
|
||||||
|
value: pending
|
||||||
|
- name: TARGET_URL
|
||||||
|
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
|
||||||
|
- name: fetch-repository
|
||||||
|
taskRef:
|
||||||
|
name: git-clone
|
||||||
|
workspaces:
|
||||||
|
- name: output
|
||||||
|
workspace: git-source
|
||||||
|
params:
|
||||||
|
- name: url
|
||||||
|
value: $(params.REPO_URL)
|
||||||
|
- name: revision
|
||||||
|
value: $(params.PULL_BASE_SHA)
|
||||||
|
- name: deleteExisting
|
||||||
|
value: "true"
|
||||||
|
- name: build-image
|
||||||
|
taskRef:
|
||||||
|
name: kaniko
|
||||||
|
params:
|
||||||
|
- name: IMAGE
|
||||||
|
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
|
||||||
|
- name: CONTEXT
|
||||||
|
value: $(params.path-to-image-context)
|
||||||
|
- name: DOCKERFILE
|
||||||
|
value: $(params.path-to-dockerfile)
|
||||||
|
- name: BUILDER_IMAGE
|
||||||
|
value: "gcr.io/kaniko-project/executor:v1.12.1"
|
||||||
|
- name: EXTRA_ARGS
|
||||||
|
value:
|
||||||
|
- --target=foreign-document-test
|
||||||
|
- --cache=true
|
||||||
|
- --cache-copy-layers
|
||||||
|
- --cache-repo=harbor.fizz.buzz/kanikocache/cache
|
||||||
|
- --use-new-run # Should result in a speed-up
|
||||||
|
- --reproducible # To remove timestamps so layer caching works.
|
||||||
|
- --snapshot-mode=redo
|
||||||
|
- --skip-unused-stages=true
|
||||||
|
- --registry-mirror=dockerhub.dockerhub.svc.cluster.local
|
||||||
|
workspaces:
|
||||||
|
- name: source
|
||||||
|
workspace: git-source
|
||||||
|
- name: dockerconfig
|
||||||
|
workspace: docker-credentials
|
||||||
|
runAfter:
|
||||||
|
- fetch-repository
|
||||||
|
- name: run-image
|
||||||
|
taskRef:
|
||||||
|
name: run-docker-image
|
||||||
|
workspaces:
|
||||||
|
- name: source
|
||||||
|
workspace: git-source
|
||||||
|
- name: cargo-cache
|
||||||
|
workspace: cargo-cache
|
||||||
|
runAfter:
|
||||||
|
- build-image
|
||||||
|
params:
|
||||||
|
- name: docker-image
|
||||||
|
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
|
||||||
|
finally:
|
||||||
|
- name: report-success
|
||||||
|
when:
|
||||||
|
- input: "$(tasks.status)"
|
||||||
|
operator: in
|
||||||
|
values: ["Succeeded", "Completed"]
|
||||||
|
taskRef:
|
||||||
|
name: gitea-set-status
|
||||||
|
params:
|
||||||
|
- name: CONTEXT
|
||||||
|
value: "$(params.JOB_NAME)"
|
||||||
|
- name: REPO_FULL_NAME
|
||||||
|
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
|
||||||
|
- name: GITEA_HOST_URL
|
||||||
|
value: code.fizz.buzz
|
||||||
|
- name: SHA
|
||||||
|
value: "$(tasks.fetch-repository.results.commit)"
|
||||||
|
- name: DESCRIPTION
|
||||||
|
value: "Build $(params.JOB_NAME) has succeeded"
|
||||||
|
- name: STATE
|
||||||
|
value: success
|
||||||
|
- name: TARGET_URL
|
||||||
|
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
|
||||||
|
- name: report-failure
|
||||||
|
when:
|
||||||
|
- input: "$(tasks.status)"
|
||||||
|
operator: in
|
||||||
|
values: ["Failed"]
|
||||||
|
taskRef:
|
||||||
|
name: gitea-set-status
|
||||||
|
params:
|
||||||
|
- name: CONTEXT
|
||||||
|
value: "$(params.JOB_NAME)"
|
||||||
|
- name: REPO_FULL_NAME
|
||||||
|
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
|
||||||
|
- name: GITEA_HOST_URL
|
||||||
|
value: code.fizz.buzz
|
||||||
|
- name: SHA
|
||||||
|
value: "$(tasks.fetch-repository.results.commit)"
|
||||||
|
- name: DESCRIPTION
|
||||||
|
value: "Build $(params.JOB_NAME) has failed"
|
||||||
|
- name: STATE
|
||||||
|
value: failure
|
||||||
|
- name: TARGET_URL
|
||||||
|
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
|
||||||
|
- name: cargo-cache-autoclean
|
||||||
|
taskRef:
|
||||||
|
name: run-docker-image
|
||||||
|
workspaces:
|
||||||
|
- name: source
|
||||||
|
workspace: git-source
|
||||||
|
- name: cargo-cache
|
||||||
|
workspace: cargo-cache
|
||||||
|
params:
|
||||||
|
- name: command
|
||||||
|
value: [cargo, cache, --autoclean]
|
||||||
|
- name: args
|
||||||
|
value: []
|
||||||
|
- name: docker-image
|
||||||
|
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
|
||||||
|
workspaces:
|
||||||
|
- name: git-source
|
||||||
|
- name: docker-credentials
|
||||||
|
- name: cargo-cache
|
||||||
|
workspaces:
|
||||||
|
- name: git-source
|
||||||
|
volumeClaimTemplate:
|
||||||
|
spec:
|
||||||
|
storageClassName: "nfs-client"
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 10Gi
|
||||||
|
subPath: rust-source
|
||||||
|
- name: cargo-cache
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: organic-cargo-cache-test-foreign-document
|
||||||
|
- name: docker-credentials
|
||||||
|
secret:
|
||||||
|
secretName: harbor-plain
|
||||||
|
serviceAccountName: build-bot
|
||||||
|
params:
|
||||||
|
- name: image-name
|
||||||
|
value: "harbor.fizz.buzz/private/organic-test-foreign-document"
|
||||||
|
- name: path-to-image-context
|
||||||
|
value: docker/organic_test/
|
||||||
|
- name: path-to-dockerfile
|
||||||
|
value: docker/organic_test/Dockerfile
|
||||||
@@ -83,6 +83,7 @@ spec:
|
|||||||
value: "gcr.io/kaniko-project/executor:v1.12.1"
|
value: "gcr.io/kaniko-project/executor:v1.12.1"
|
||||||
- name: EXTRA_ARGS
|
- name: EXTRA_ARGS
|
||||||
value:
|
value:
|
||||||
|
- --target=tester
|
||||||
- --cache=true
|
- --cache=true
|
||||||
- --cache-copy-layers
|
- --cache-copy-layers
|
||||||
- --cache-repo=harbor.fizz.buzz/kanikocache/cache
|
- --cache-repo=harbor.fizz.buzz/kanikocache/cache
|
||||||
@@ -110,7 +111,16 @@ spec:
|
|||||||
- build-image
|
- build-image
|
||||||
params:
|
params:
|
||||||
- name: args
|
- name: args
|
||||||
value: [--no-fail-fast, --lib, --test, test_loader]
|
value:
|
||||||
|
[
|
||||||
|
--no-default-features,
|
||||||
|
--features,
|
||||||
|
compare,
|
||||||
|
--no-fail-fast,
|
||||||
|
--lib,
|
||||||
|
--test,
|
||||||
|
test_loader,
|
||||||
|
]
|
||||||
- name: docker-image
|
- name: docker-image
|
||||||
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
|
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ spec:
|
|||||||
skip_branches:
|
skip_branches:
|
||||||
# We already run on every commit, so running when the semver tags get pushed is causing needless double-processing.
|
# We already run on every commit, so running when the semver tags get pushed is causing needless double-processing.
|
||||||
- "^v[0-9]+\\.[0-9]+\\.[0-9]+$"
|
- "^v[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||||
|
- name: rust-foreign-document-test
|
||||||
|
source: "pipeline-foreign-document-test.yaml"
|
||||||
|
# Override https-based url from lighthouse events.
|
||||||
|
clone_uri: "git@code.fizz.buzz:talexander/organic.git"
|
||||||
|
skip_branches:
|
||||||
|
# We already run on every commit, so running when the semver tags get pushed is causing needless double-processing.
|
||||||
|
- "^v[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||||
- name: rust-build
|
- name: rust-build
|
||||||
source: "pipeline-rust-build.yaml"
|
source: "pipeline-rust-build.yaml"
|
||||||
# Override https-based url from lighthouse events.
|
# Override https-based url from lighthouse events.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "organic"
|
name = "organic"
|
||||||
version = "0.1.3"
|
version = "0.1.5"
|
||||||
authors = ["Tom Alexander <tom@fizz.buzz>"]
|
authors = ["Tom Alexander <tom@fizz.buzz>"]
|
||||||
description = "An org-mode parser."
|
description = "An org-mode parser."
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -13,9 +13,7 @@ resolver = "2"
|
|||||||
include = [
|
include = [
|
||||||
"LICENSE",
|
"LICENSE",
|
||||||
"**/*.rs",
|
"**/*.rs",
|
||||||
"Cargo.toml",
|
"Cargo.toml"
|
||||||
"tests/*",
|
|
||||||
"org_mode_samples/"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
@@ -24,7 +22,7 @@ path = "src/lib.rs"
|
|||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
# This bin exists for development purposes only. The real target of this crate is the library.
|
# This bin exists for development purposes only. The real target of this crate is the library.
|
||||||
name = "compare"
|
name = "parse"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
14
Makefile
14
Makefile
@@ -35,12 +35,16 @@ clean:
|
|||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test:
|
||||||
> cargo test --no-fail-fast --lib --test test_loader -- --test-threads $(TESTJOBS)
|
> cargo test --no-default-features --features compare --no-fail-fast --lib --test test_loader -- --test-threads $(TESTJOBS)
|
||||||
|
|
||||||
.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-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: foreign_document_test
|
||||||
|
foreign_document_test:
|
||||||
|
> $(MAKE) -C docker/organic_test run_foreign_document_test
|
||||||
|
|
||||||
.PHONY: dockerclean
|
.PHONY: dockerclean
|
||||||
dockerclean:
|
dockerclean:
|
||||||
@@ -49,18 +53,18 @@ dockerclean:
|
|||||||
|
|
||||||
.PHONY: integrationtest
|
.PHONY: integrationtest
|
||||||
integrationtest:
|
integrationtest:
|
||||||
> cargo test --no-fail-fast --test test_loader -- --test-threads $(TESTJOBS)
|
> cargo test --no-default-features --features compare --no-fail-fast --test test_loader -- --test-threads $(TESTJOBS)
|
||||||
|
|
||||||
.PHONY: unittest
|
.PHONY: unittest
|
||||||
unittest:
|
unittest:
|
||||||
> cargo test --lib -- --test-threads $(TESTJOBS)
|
> cargo test --no-default-features --lib -- --test-threads $(TESTJOBS)
|
||||||
|
|
||||||
.PHONY: jaeger
|
.PHONY: jaeger
|
||||||
jaeger:
|
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:
|
||||||
|
|||||||
17
build.rs
17
build.rs
@@ -1,10 +1,16 @@
|
|||||||
|
#[cfg(feature = "compare")]
|
||||||
use std::env;
|
use std::env;
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
fn main() {
|
fn main() {
|
||||||
let out_dir = env::var("OUT_DIR").unwrap();
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
let destination = Path::new(&out_dir).join("tests.rs");
|
let destination = Path::new(&out_dir).join("tests.rs");
|
||||||
@@ -31,6 +37,10 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "compare"))]
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
fn write_test(test_file: &mut File, test: &walkdir::DirEntry) {
|
fn write_test(test_file: &mut File, test: &walkdir::DirEntry) {
|
||||||
let test_name = test
|
let test_name = test
|
||||||
.path()
|
.path()
|
||||||
@@ -55,14 +65,15 @@ fn write_test(test_file: &mut File, test: &walkdir::DirEntry) {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
fn write_header(test_file: &mut File) {
|
fn write_header(test_file: &mut File) {
|
||||||
write!(
|
write!(
|
||||||
test_file,
|
test_file,
|
||||||
r#"
|
r#"
|
||||||
#[feature(exit_status_error)]
|
#[feature(exit_status_error)]
|
||||||
use organic::compare_document;
|
use organic::compare_document;
|
||||||
use organic::parser::document;
|
use organic::parser::parse;
|
||||||
use organic::emacs_parse_org_document;
|
use organic::emacs_parse_anonymous_org_document;
|
||||||
use organic::parser::sexp::sexp_with_padding;
|
use organic::parser::sexp::sexp_with_padding;
|
||||||
|
|
||||||
"#
|
"#
|
||||||
@@ -70,12 +81,12 @@ use organic::parser::sexp::sexp_with_padding;
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
fn is_expect_fail(name: &str) -> Option<&str> {
|
fn is_expect_fail(name: &str) -> Option<&str> {
|
||||||
match name {
|
match name {
|
||||||
"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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ all: build push
|
|||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build:
|
build:
|
||||||
docker build -t $(IMAGE_NAME) -f Dockerfile ../../
|
docker build -t $(IMAGE_NAME) -f Dockerfile .
|
||||||
|
|
||||||
.PHONY: push
|
.PHONY: push
|
||||||
push:
|
push:
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ all: build push
|
|||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build:
|
build:
|
||||||
docker build -t $(IMAGE_NAME) -f Dockerfile ../../
|
docker build -t $(IMAGE_NAME) -f Dockerfile .
|
||||||
|
|
||||||
.PHONY: push
|
.PHONY: push
|
||||||
push:
|
push:
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -25,10 +25,24 @@ RUN make compile
|
|||||||
RUN make DESTDIR="/root/dist" install
|
RUN make DESTDIR="/root/dist" install
|
||||||
|
|
||||||
|
|
||||||
FROM rustlang/rust:nightly-alpine3.17
|
FROM rustlang/rust:nightly-alpine3.17 AS tester
|
||||||
|
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/ /
|
||||||
COPY --from=build-org-mode /root/dist/ /
|
COPY --from=build-org-mode /root/dist/ /
|
||||||
|
|
||||||
ENTRYPOINT ["cargo", "test"]
|
ENTRYPOINT ["cargo", "test"]
|
||||||
|
|
||||||
|
|
||||||
|
FROM build as foreign-document-gather
|
||||||
|
RUN mkdir /foreign_documents
|
||||||
|
|
||||||
|
|
||||||
|
FROM tester as foreign-document-test
|
||||||
|
RUN apk add --no-cache bash
|
||||||
|
RUN mkdir /foreign_documents
|
||||||
|
COPY --from=build-org-mode /root/org-mode/doc /foreign_documents/org-mode
|
||||||
|
COPY foreign_document_test_entrypoint.sh /entrypoint.sh
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ all: build push
|
|||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build:
|
build:
|
||||||
docker build -t $(IMAGE_NAME) -f Dockerfile ../../
|
docker build -t $(IMAGE_NAME) -f Dockerfile --target tester .
|
||||||
|
|
||||||
|
.PHONY: build_foreign_document_test
|
||||||
|
build_foreign_document_test:
|
||||||
|
docker build -t $(IMAGE_NAME)-foreign-document -f Dockerfile --target foreign-document-test .
|
||||||
|
|
||||||
.PHONY: push
|
.PHONY: push
|
||||||
push:
|
push:
|
||||||
@@ -29,8 +33,12 @@ 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-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)
|
||||||
|
|
||||||
|
.PHONY: run_foreign_document_test
|
||||||
|
run_foreign_document_test: build_foreign_document_test
|
||||||
|
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)-foreign-document
|
||||||
|
|||||||
57
docker/organic_test/foreign_document_test_entrypoint.sh
Normal file
57
docker/organic_test/foreign_document_test_entrypoint.sh
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Run the Organic compare script against a series of documents sourced from exterior places.
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
function log {
|
||||||
|
(>&2 echo "${@}")
|
||||||
|
}
|
||||||
|
|
||||||
|
function die {
|
||||||
|
local status_code="$1"
|
||||||
|
shift
|
||||||
|
(>&2 echo "${@}")
|
||||||
|
exit "$status_code"
|
||||||
|
}
|
||||||
|
|
||||||
|
function main {
|
||||||
|
cargo build --no-default-features --features compare --profile release-lto
|
||||||
|
if [ "${CARGO_TARGET_DIR:-}" = "" ]; then
|
||||||
|
CARGO_TARGET_DIR=$(realpath target/)
|
||||||
|
fi
|
||||||
|
PARSE="${CARGO_TARGET_DIR}/release-lto/parse"
|
||||||
|
|
||||||
|
run_compare "org-mode/org-guide.org" "/foreign_documents/org-mode/org-guide.org"
|
||||||
|
run_compare "org-mode/org-manual.org" "/foreign_documents/org-mode/org-manual.org"
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_compare {
|
||||||
|
local name="$1"
|
||||||
|
local target_document="$2"
|
||||||
|
set +e
|
||||||
|
$PARSE "$target_document" &> /dev/null
|
||||||
|
local status=$?
|
||||||
|
set -e
|
||||||
|
if [ "$status" -eq 0 ]; then
|
||||||
|
echo "$(green_text "GOOD") $name"
|
||||||
|
else
|
||||||
|
echo "$(red_text "FAIL") $name"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function green_text {
|
||||||
|
(IFS=' '; printf '\x1b[38;2;0;255;0m%s\x1b[0m' "${*}")
|
||||||
|
}
|
||||||
|
|
||||||
|
function red_text {
|
||||||
|
(IFS=' '; printf '\x1b[38;2;255;0;0m%s\x1b[0m' "${*}")
|
||||||
|
}
|
||||||
|
|
||||||
|
function yellow_text {
|
||||||
|
(IFS=' '; printf '\x1b[38;2;255;255;0m%s\x1b[0m' "${*}")
|
||||||
|
}
|
||||||
|
|
||||||
|
main "${@}"
|
||||||
1
org_mode_samples/README.org
Normal file
1
org_mode_samples/README.org
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This folder contains org-mode documents that get automatically included as tests using build.rs.
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#+begin_defun
|
||||||
|
foo
|
||||||
|
#+begin_lorem
|
||||||
|
ipsum
|
||||||
|
#+end_lorem
|
||||||
|
bar
|
||||||
|
#+begin_center
|
||||||
|
#+begin_quote
|
||||||
|
baz
|
||||||
|
#+end_quote
|
||||||
|
#+end_center
|
||||||
|
#+end_defun
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#+begin_defun
|
||||||
|
foo
|
||||||
|
|
||||||
|
{{{bar(baz)}}}
|
||||||
|
#+end_defun
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
- {{{foo(bar)}}} :: baz
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
- foo
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
%%(foo bar) ; baz
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
mailto:foo@bar.baz .
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
foo ==>bar=.
|
||||||
|
|
||||||
|
# This uses a zero-width space to escape the equals signs to make the verbatim not end.
|
||||||
|
=lorem == ipsum=
|
||||||
@@ -7,7 +7,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|||||||
cd "$DIR/../"
|
cd "$DIR/../"
|
||||||
|
|
||||||
RUSTFLAGS="-C opt-level=0" cargo build --no-default-features
|
RUSTFLAGS="-C opt-level=0" cargo build --no-default-features
|
||||||
valgrind --tool=callgrind --callgrind-out-file=callgrind.out target/debug/compare
|
valgrind --tool=callgrind --callgrind-out-file=callgrind.out target/debug/parse
|
||||||
|
|
||||||
echo "You probably want to run:"
|
echo "You probably want to run:"
|
||||||
echo "callgrind_annotate --auto=yes callgrind.out"
|
echo "callgrind_annotate --auto=yes callgrind.out"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ function main {
|
|||||||
additional_flags+=(--profile "$PROFILE")
|
additional_flags+=(--profile "$PROFILE")
|
||||||
fi
|
fi
|
||||||
cargo build --no-default-features "${additional_flags[@]}"
|
cargo build --no-default-features "${additional_flags[@]}"
|
||||||
perf record --freq=2000 --call-graph dwarf --output=perf.data target/${PROFILE}/compare
|
perf record --freq=2000 --call-graph dwarf --output=perf.data target/${PROFILE}/parse
|
||||||
|
|
||||||
# Convert to a format firefox will read
|
# Convert to a format firefox will read
|
||||||
# flags to consider --show-info
|
# flags to consider --show-info
|
||||||
|
|||||||
@@ -9,14 +9,13 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|||||||
: ${BACKTRACE:="NO"} # or YES to print a rust backtrace when panicking
|
: ${BACKTRACE:="NO"} # or YES to print a rust backtrace when panicking
|
||||||
: ${NO_COLOR:=""} # Set to anything to disable color output
|
: ${NO_COLOR:=""} # Set to anything to disable color output
|
||||||
|
|
||||||
|
|
||||||
cd "$DIR/../"
|
cd "$DIR/../"
|
||||||
REALPATH=$(command -v uu-realpath || command -v realpath)
|
REALPATH=$(command -v uu-realpath || command -v realpath)
|
||||||
MAKE=$(command -v gmake || command -v make)
|
MAKE=$(command -v gmake || command -v make)
|
||||||
|
|
||||||
function main {
|
function main {
|
||||||
build_container
|
build_container
|
||||||
launch_container
|
launch_container "${@}"
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_container {
|
function build_container {
|
||||||
@@ -41,6 +40,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 +50,17 @@ 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[@]}"
|
if [ $# -gt 0 ]; then
|
||||||
|
# If we passed in args, we need to forward them along
|
||||||
|
for path in "${@}"; do
|
||||||
|
local full_path=$($REALPATH "$path")
|
||||||
|
local containing_folder=$(dirname "$full_path")
|
||||||
|
local file_name=$(basename "$full_path")
|
||||||
|
docker run "${additional_flags[@]}" --init --rm -i --mount type=tmpfs,destination=/tmp -v "${containing_folder}:/input:ro" -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[@]}" -- "/input/$file_name"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
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[@]}"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
main "${@}"
|
main "${@}"
|
||||||
|
|||||||
93
scripts/run_docker_compare_bisect.bash
Executable file
93
scripts/run_docker_compare_bisect.bash
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Bisect parsing a file at various line cut-off points to see which line causes the parse to differ from emacs.
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
cd "$DIR/../"
|
||||||
|
REALPATH=$(command -v uu-realpath || command -v realpath)
|
||||||
|
|
||||||
|
############## Setup #########################
|
||||||
|
|
||||||
|
function cleanup {
|
||||||
|
for f in "${folders[@]}"; do
|
||||||
|
log "Deleting $f"
|
||||||
|
rm -rf "$f"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
folders=()
|
||||||
|
for sig in EXIT INT QUIT HUP TERM; do
|
||||||
|
trap "set +e; cleanup" "$sig"
|
||||||
|
done
|
||||||
|
|
||||||
|
function die {
|
||||||
|
local status_code="$1"
|
||||||
|
shift
|
||||||
|
(>&2 echo "${@}")
|
||||||
|
exit "$status_code"
|
||||||
|
}
|
||||||
|
|
||||||
|
function log {
|
||||||
|
(>&2 echo "${@}")
|
||||||
|
}
|
||||||
|
|
||||||
|
############## Program #########################
|
||||||
|
|
||||||
|
function main {
|
||||||
|
log "Is is recommended that the output of \`mktemp -d -t 'compare_bisect.XXXXXXXX'\` is inside a tmpfs filesystem since this script will make many writes to these folders."
|
||||||
|
|
||||||
|
local target_full_path=$($REALPATH "$1")
|
||||||
|
SOURCE_FOLDER=$(dirname "$target_full_path")
|
||||||
|
TARGET_DOCUMENT=$(basename "$target_full_path")
|
||||||
|
|
||||||
|
|
||||||
|
local good=0
|
||||||
|
local bad=$(wc -l "$SOURCE_FOLDER/$TARGET_DOCUMENT" | awk '{print $1}')
|
||||||
|
|
||||||
|
set +e
|
||||||
|
run_parse "$bad" &> /dev/null
|
||||||
|
local status=$?
|
||||||
|
set -e
|
||||||
|
if [ $status -eq 0 ]; then
|
||||||
|
log "Entire file passes."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
while [[ "$((bad - good))" -gt 1 ]]; do
|
||||||
|
local next_line=$((((bad - good) / 2) + good))
|
||||||
|
log "Testing line $next_line"
|
||||||
|
set +e
|
||||||
|
run_parse "$next_line" &> /dev/null
|
||||||
|
local status=$?
|
||||||
|
set -e
|
||||||
|
if [ $status -eq 0 ]; then
|
||||||
|
good="$next_line"
|
||||||
|
log "Line $next_line good"
|
||||||
|
else
|
||||||
|
bad="$next_line"
|
||||||
|
log "Line $next_line bad"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "Bad line: $bad"
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_temp_dir {
|
||||||
|
local temp_dir=$(mktemp -d -t 'compare_bisect.XXXXXXXX')
|
||||||
|
cp -r "$SOURCE_FOLDER/"* "$temp_dir/"
|
||||||
|
echo "$temp_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_parse {
|
||||||
|
local lines="$1"
|
||||||
|
local temp_dir=$(setup_temp_dir)
|
||||||
|
folders+=("$temp_dir")
|
||||||
|
cat "$SOURCE_FOLDER/$TARGET_DOCUMENT" | head -n "$lines" > "$temp_dir/$TARGET_DOCUMENT"
|
||||||
|
"${DIR}/run_docker_compare.bash" "$temp_dir/$TARGET_DOCUMENT"
|
||||||
|
local status=$?
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
# TODO: Remove temp_dir from folders
|
||||||
|
return "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "${@}"
|
||||||
@@ -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
|
||||||
@@ -52,11 +52,11 @@ function launch_container {
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
IFS=\$'\n\t'
|
IFS=\$'\n\t'
|
||||||
|
|
||||||
cargo test --no-fail-fast --lib --test test_loader "$test" -- --show-output
|
cargo test --no-default-features --features compare --no-fail-fast --lib --test test_loader "$test" -- --show-output
|
||||||
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"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ function main {
|
|||||||
|
|
||||||
local test
|
local test
|
||||||
while read test; do
|
while read test; do
|
||||||
cargo test --no-fail-fast --test test_loader "$test" -- --show-output
|
cargo test --no-default-features --features compare --no-fail-fast --test test_loader "$test" -- --show-output
|
||||||
done<<<"$test_names"
|
done<<<"$test_names"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function main {
|
|||||||
additional_flags+=(--profile "$PROFILE")
|
additional_flags+=(--profile "$PROFILE")
|
||||||
fi
|
fi
|
||||||
cargo build --no-default-features "${additional_flags[@]}"
|
cargo build --no-default-features "${additional_flags[@]}"
|
||||||
time ./target/${PROFILE}/compare
|
time ./target/${PROFILE}/parse "${@}"
|
||||||
}
|
}
|
||||||
|
|
||||||
main "${@}"
|
main "${@}"
|
||||||
|
|||||||
@@ -5,64 +5,65 @@ use super::util::assert_name;
|
|||||||
use super::util::get_property;
|
use super::util::get_property;
|
||||||
use crate::parser::sexp::unquote;
|
use crate::parser::sexp::unquote;
|
||||||
use crate::parser::sexp::Token;
|
use crate::parser::sexp::Token;
|
||||||
use crate::parser::AngleLink;
|
use crate::types::AngleLink;
|
||||||
use crate::parser::Bold;
|
use crate::types::Bold;
|
||||||
use crate::parser::Citation;
|
use crate::types::Citation;
|
||||||
use crate::parser::CitationReference;
|
use crate::types::CitationReference;
|
||||||
use crate::parser::Clock;
|
use crate::types::Clock;
|
||||||
use crate::parser::Code;
|
use crate::types::Code;
|
||||||
use crate::parser::Comment;
|
use crate::types::Comment;
|
||||||
use crate::parser::CommentBlock;
|
use crate::types::CommentBlock;
|
||||||
use crate::parser::DiarySexp;
|
use crate::types::DiarySexp;
|
||||||
use crate::parser::Document;
|
use crate::types::Document;
|
||||||
use crate::parser::DocumentElement;
|
use crate::types::DocumentElement;
|
||||||
use crate::parser::Drawer;
|
use crate::types::Drawer;
|
||||||
use crate::parser::DynamicBlock;
|
use crate::types::DynamicBlock;
|
||||||
use crate::parser::Element;
|
use crate::types::Element;
|
||||||
use crate::parser::Entity;
|
use crate::types::Entity;
|
||||||
use crate::parser::ExampleBlock;
|
use crate::types::ExampleBlock;
|
||||||
use crate::parser::ExportBlock;
|
use crate::types::ExportBlock;
|
||||||
use crate::parser::ExportSnippet;
|
use crate::types::ExportSnippet;
|
||||||
use crate::parser::FixedWidthArea;
|
use crate::types::FixedWidthArea;
|
||||||
use crate::parser::FootnoteDefinition;
|
use crate::types::FootnoteDefinition;
|
||||||
use crate::parser::FootnoteReference;
|
use crate::types::FootnoteReference;
|
||||||
use crate::parser::GreaterBlock;
|
use crate::types::GreaterBlock;
|
||||||
use crate::parser::Heading;
|
use crate::types::Heading;
|
||||||
use crate::parser::HorizontalRule;
|
use crate::types::HorizontalRule;
|
||||||
use crate::parser::InlineBabelCall;
|
use crate::types::InlineBabelCall;
|
||||||
use crate::parser::InlineSourceBlock;
|
use crate::types::InlineSourceBlock;
|
||||||
use crate::parser::Italic;
|
use crate::types::Italic;
|
||||||
use crate::parser::Keyword;
|
use crate::types::Keyword;
|
||||||
use crate::parser::LatexEnvironment;
|
use crate::types::LatexEnvironment;
|
||||||
use crate::parser::LatexFragment;
|
use crate::types::LatexFragment;
|
||||||
use crate::parser::LineBreak;
|
use crate::types::LineBreak;
|
||||||
use crate::parser::Object;
|
use crate::types::Object;
|
||||||
use crate::parser::OrgMacro;
|
use crate::types::OrgMacro;
|
||||||
use crate::parser::Paragraph;
|
use crate::types::Paragraph;
|
||||||
use crate::parser::PlainLink;
|
use crate::types::PlainLink;
|
||||||
use crate::parser::PlainList;
|
use crate::types::PlainList;
|
||||||
use crate::parser::PlainListItem;
|
use crate::types::PlainListItem;
|
||||||
use crate::parser::PlainText;
|
use crate::types::PlainText;
|
||||||
use crate::parser::Planning;
|
use crate::types::Planning;
|
||||||
use crate::parser::PropertyDrawer;
|
use crate::types::PropertyDrawer;
|
||||||
use crate::parser::RadioLink;
|
use crate::types::RadioLink;
|
||||||
use crate::parser::RadioTarget;
|
use crate::types::RadioTarget;
|
||||||
use crate::parser::RegularLink;
|
use crate::types::RegularLink;
|
||||||
use crate::parser::Section;
|
use crate::types::Section;
|
||||||
use crate::parser::Source;
|
use crate::types::Source;
|
||||||
use crate::parser::SrcBlock;
|
use crate::types::SrcBlock;
|
||||||
use crate::parser::StatisticsCookie;
|
use crate::types::StatisticsCookie;
|
||||||
use crate::parser::StrikeThrough;
|
use crate::types::StrikeThrough;
|
||||||
use crate::parser::Subscript;
|
use crate::types::Subscript;
|
||||||
use crate::parser::Superscript;
|
use crate::types::Superscript;
|
||||||
use crate::parser::Table;
|
use crate::types::Table;
|
||||||
use crate::parser::TableCell;
|
use crate::types::TableCell;
|
||||||
use crate::parser::TableRow;
|
use crate::types::TableRow;
|
||||||
use crate::parser::Target;
|
use crate::types::Target;
|
||||||
use crate::parser::Timestamp;
|
use crate::types::Timestamp;
|
||||||
use crate::parser::Underline;
|
use crate::types::TodoKeywordType;
|
||||||
use crate::parser::Verbatim;
|
use crate::types::Underline;
|
||||||
use crate::parser::VerseBlock;
|
use crate::types::Verbatim;
|
||||||
|
use crate::types::VerseBlock;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DiffEntry<'s> {
|
pub enum DiffEntry<'s> {
|
||||||
@@ -510,9 +511,9 @@ fn compare_heading<'s>(
|
|||||||
.map(Token::as_atom)
|
.map(Token::as_atom)
|
||||||
.map_or(Ok(None), |r| r.map(Some))?
|
.map_or(Ok(None), |r| r.map(Some))?
|
||||||
.unwrap_or("nil");
|
.unwrap_or("nil");
|
||||||
match (todo_keyword, rust.todo_keyword, unquote(todo_keyword)) {
|
match (todo_keyword, &rust.todo_keyword, unquote(todo_keyword)) {
|
||||||
("nil", None, _) => {}
|
("nil", None, _) => {}
|
||||||
(_, Some(rust_todo), Ok(emacs_todo)) if emacs_todo == rust_todo => {}
|
(_, Some((_rust_todo_type, rust_todo)), Ok(emacs_todo)) if emacs_todo == *rust_todo => {}
|
||||||
(emacs_todo, rust_todo, _) => {
|
(emacs_todo, rust_todo, _) => {
|
||||||
this_status = DiffStatus::Bad;
|
this_status = DiffStatus::Bad;
|
||||||
message = Some(format!(
|
message = Some(format!(
|
||||||
@@ -521,6 +522,24 @@ fn compare_heading<'s>(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// Compare todo-type
|
||||||
|
let todo_type = get_property(emacs, ":todo-type")?
|
||||||
|
.map(Token::as_atom)
|
||||||
|
.map_or(Ok(None), |r| r.map(Some))?
|
||||||
|
.unwrap_or("nil");
|
||||||
|
// todo-type is an unquoted string either todo, done, or nil
|
||||||
|
match (todo_type, &rust.todo_keyword) {
|
||||||
|
("nil", None) => {}
|
||||||
|
("todo", Some((TodoKeywordType::Todo, _))) => {}
|
||||||
|
("done", Some((TodoKeywordType::Done, _))) => {}
|
||||||
|
(emacs_todo, rust_todo) => {
|
||||||
|
this_status = DiffStatus::Bad;
|
||||||
|
message = Some(format!(
|
||||||
|
"(emacs != rust) {:?} != {:?}",
|
||||||
|
emacs_todo, rust_todo
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Compare title
|
// Compare title
|
||||||
let title = get_property(emacs, ":title")?.ok_or("Missing :title attribute.")?;
|
let title = get_property(emacs, ":title")?.ok_or("Missing :title attribute.")?;
|
||||||
@@ -532,7 +551,7 @@ fn compare_heading<'s>(
|
|||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
child_status.push(artificial_diff_scope("title".to_owned(), title_status)?);
|
child_status.push(artificial_diff_scope("title".to_owned(), title_status)?);
|
||||||
|
|
||||||
// TODO: Compare todo-type, priority, :footnote-section-p, :archivedp, :commentedp
|
// TODO: Compare priority, :footnote-section-p, :archivedp, :commentedp
|
||||||
|
|
||||||
// Compare section
|
// Compare section
|
||||||
let section_status = children
|
let section_status = children
|
||||||
@@ -737,7 +756,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;
|
||||||
@@ -1392,6 +1411,31 @@ fn compare_keyword<'s>(
|
|||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let key = unquote(
|
||||||
|
get_property(emacs, ":key")?
|
||||||
|
.ok_or("Emacs keywords should have a :key")?
|
||||||
|
.as_atom()?,
|
||||||
|
)?;
|
||||||
|
if key != rust.key.to_uppercase() {
|
||||||
|
this_status = DiffStatus::Bad;
|
||||||
|
message = Some(format!(
|
||||||
|
"Mismatchs keyword keys (emacs != rust) {:?} != {:?}",
|
||||||
|
key, rust.key
|
||||||
|
))
|
||||||
|
}
|
||||||
|
let value = unquote(
|
||||||
|
get_property(emacs, ":value")?
|
||||||
|
.ok_or("Emacs keywords should have a :value")?
|
||||||
|
.as_atom()?,
|
||||||
|
)?;
|
||||||
|
if value != rust.value {
|
||||||
|
this_status = DiffStatus::Bad;
|
||||||
|
message = Some(format!(
|
||||||
|
"Mismatchs keyword values (emacs != rust) {:?} != {:?}",
|
||||||
|
value, rust.value
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
Ok(DiffResult {
|
Ok(DiffResult {
|
||||||
status: this_status,
|
status: this_status,
|
||||||
name: emacs_name.to_owned(),
|
name: emacs_name.to_owned(),
|
||||||
@@ -1457,7 +1501,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) {:?} != {:?}",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ mod diff;
|
|||||||
mod parse;
|
mod parse;
|
||||||
mod util;
|
mod util;
|
||||||
pub use diff::compare_document;
|
pub use diff::compare_document;
|
||||||
pub use parse::emacs_parse_org_document;
|
pub use parse::emacs_parse_anonymous_org_document;
|
||||||
|
pub use parse::emacs_parse_file_org_document;
|
||||||
pub use parse::get_emacs_version;
|
pub use parse::get_emacs_version;
|
||||||
pub use parse::get_org_mode_version;
|
pub use parse::get_org_mode_version;
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn emacs_parse_org_document<C>(file_contents: C) -> Result<String, Box<dyn std::error::Error>>
|
pub fn emacs_parse_anonymous_org_document<C>(
|
||||||
|
file_contents: C,
|
||||||
|
) -> Result<String, Box<dyn std::error::Error>>
|
||||||
where
|
where
|
||||||
C: AsRef<str>,
|
C: AsRef<str>,
|
||||||
{
|
{
|
||||||
@@ -15,14 +18,46 @@ where
|
|||||||
escaped_file_contents = escaped_file_contents
|
escaped_file_contents = escaped_file_contents
|
||||||
);
|
);
|
||||||
let mut cmd = Command::new("emacs");
|
let mut cmd = Command::new("emacs");
|
||||||
let proc = cmd
|
let cmd = cmd
|
||||||
.arg("-q")
|
.arg("-q")
|
||||||
.arg("--no-site-file")
|
.arg("--no-site-file")
|
||||||
.arg("--no-splash")
|
.arg("--no-splash")
|
||||||
.arg("--batch")
|
.arg("--batch")
|
||||||
.arg("--eval")
|
.arg("--eval")
|
||||||
.arg(elisp_script);
|
.arg(elisp_script);
|
||||||
let out = proc.output()?;
|
let out = cmd.output()?;
|
||||||
|
out.status.exit_ok()?;
|
||||||
|
let org_sexp = out.stderr;
|
||||||
|
Ok(String::from_utf8(org_sexp)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn emacs_parse_file_org_document<P>(file_path: P) -> Result<String, Box<dyn std::error::Error>>
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
{
|
||||||
|
let file_path = file_path.as_ref().canonicalize()?;
|
||||||
|
let containing_directory = file_path.parent().ok_or(format!(
|
||||||
|
"Failed to get containing directory for path {}",
|
||||||
|
file_path.display()
|
||||||
|
))?;
|
||||||
|
let elisp_script = format!(
|
||||||
|
r#"(progn
|
||||||
|
(org-mode)
|
||||||
|
(message "%s" (pp-to-string (org-element-parse-buffer)))
|
||||||
|
)"#
|
||||||
|
);
|
||||||
|
let mut cmd = Command::new("emacs");
|
||||||
|
let cmd = cmd
|
||||||
|
.current_dir(containing_directory)
|
||||||
|
.arg("-q")
|
||||||
|
.arg("--no-site-file")
|
||||||
|
.arg("--no-splash")
|
||||||
|
.arg("--batch")
|
||||||
|
.arg("--insert")
|
||||||
|
.arg(file_path.as_os_str())
|
||||||
|
.arg("--eval")
|
||||||
|
.arg(elisp_script);
|
||||||
|
let out = cmd.output()?;
|
||||||
out.status.exit_ok()?;
|
out.status.exit_ok()?;
|
||||||
let org_sexp = out.stderr;
|
let org_sexp = out.stderr;
|
||||||
Ok(String::from_utf8(org_sexp)?)
|
Ok(String::from_utf8(org_sexp)?)
|
||||||
@@ -55,7 +90,7 @@ pub fn get_emacs_version() -> Result<String, Box<dyn std::error::Error>> {
|
|||||||
(message "%s" (version))
|
(message "%s" (version))
|
||||||
)"#;
|
)"#;
|
||||||
let mut cmd = Command::new("emacs");
|
let mut cmd = Command::new("emacs");
|
||||||
let proc = cmd
|
let cmd = cmd
|
||||||
.arg("-q")
|
.arg("-q")
|
||||||
.arg("--no-site-file")
|
.arg("--no-site-file")
|
||||||
.arg("--no-splash")
|
.arg("--no-splash")
|
||||||
@@ -63,7 +98,7 @@ pub fn get_emacs_version() -> Result<String, Box<dyn std::error::Error>> {
|
|||||||
.arg("--eval")
|
.arg("--eval")
|
||||||
.arg(elisp_script);
|
.arg(elisp_script);
|
||||||
|
|
||||||
let out = proc.output()?;
|
let out = cmd.output()?;
|
||||||
out.status.exit_ok()?;
|
out.status.exit_ok()?;
|
||||||
Ok(String::from_utf8(out.stderr)?)
|
Ok(String::from_utf8(out.stderr)?)
|
||||||
}
|
}
|
||||||
@@ -74,7 +109,7 @@ pub fn get_org_mode_version() -> Result<String, Box<dyn std::error::Error>> {
|
|||||||
(message "%s" (org-version nil t nil))
|
(message "%s" (org-version nil t nil))
|
||||||
)"#;
|
)"#;
|
||||||
let mut cmd = Command::new("emacs");
|
let mut cmd = Command::new("emacs");
|
||||||
let proc = cmd
|
let cmd = cmd
|
||||||
.arg("-q")
|
.arg("-q")
|
||||||
.arg("--no-site-file")
|
.arg("--no-site-file")
|
||||||
.arg("--no-splash")
|
.arg("--no-splash")
|
||||||
@@ -82,7 +117,7 @@ pub fn get_org_mode_version() -> Result<String, Box<dyn std::error::Error>> {
|
|||||||
.arg("--eval")
|
.arg("--eval")
|
||||||
.arg(elisp_script);
|
.arg(elisp_script);
|
||||||
|
|
||||||
let out = proc.output()?;
|
let out = cmd.output()?;
|
||||||
out.status.exit_ok()?;
|
out.status.exit_ok()?;
|
||||||
Ok(String::from_utf8(out.stderr)?)
|
Ok(String::from_utf8(out.stderr)?)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::parser::sexp::Token;
|
use crate::parser::sexp::Token;
|
||||||
use crate::parser::Source;
|
use crate::types::Source;
|
||||||
|
|
||||||
/// Check if the child string slice is a slice of the parent string slice.
|
/// Check if the child string slice is a slice of the parent string slice.
|
||||||
fn is_slice_of(parent: &str, child: &str) -> bool {
|
fn is_slice_of(parent: &str, child: &str) -> bool {
|
||||||
@@ -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(())
|
||||||
|
|||||||
181
src/context/context.rs
Normal file
181
src/context/context.rs
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use nom::combinator::eof;
|
||||||
|
use nom::IResult;
|
||||||
|
|
||||||
|
use super::exiting::ExitClass;
|
||||||
|
use super::global_settings::GlobalSettings;
|
||||||
|
use super::list::List;
|
||||||
|
use super::DynContextMatcher;
|
||||||
|
use super::RefContext;
|
||||||
|
use crate::error::CustomError;
|
||||||
|
use crate::error::MyError;
|
||||||
|
use crate::error::Res;
|
||||||
|
use crate::parser::OrgSource;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ContextElement<'r, 's> {
|
||||||
|
/// Stores a parser that indicates that children should exit upon matching an exit matcher.
|
||||||
|
ExitMatcherNode(ExitMatcherNode<'r>),
|
||||||
|
|
||||||
|
/// Stores the name of the current element to prevent directly nesting elements of the same type.
|
||||||
|
Context(&'r str),
|
||||||
|
|
||||||
|
/// Indicates if elements should consume the whitespace after them.
|
||||||
|
ConsumeTrailingWhitespace(bool),
|
||||||
|
|
||||||
|
/// This is just here to use the 's lifetime until I'm sure we can eliminate it from ContextElement.
|
||||||
|
Placeholder(PhantomData<&'s str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ExitMatcherNode<'r> {
|
||||||
|
// TODO: Should this be "&'r DynContextMatcher<'c>" ?
|
||||||
|
pub exit_matcher: &'r DynContextMatcher<'r>,
|
||||||
|
pub class: ExitClass,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> std::fmt::Debug for ExitMatcherNode<'r> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let mut formatter = f.debug_struct("ExitMatcherNode");
|
||||||
|
formatter.field("class", &self.class.to_string());
|
||||||
|
formatter.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Context<'g, 'r, 's> {
|
||||||
|
global_settings: &'g GlobalSettings<'g, 's>,
|
||||||
|
tree: List<'r, &'r ContextElement<'r, 's>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'g, 'r, 's> Context<'g, 'r, 's> {
|
||||||
|
pub fn new(
|
||||||
|
global_settings: &'g GlobalSettings<'g, 's>,
|
||||||
|
tree: List<'r, &'r ContextElement<'r, 's>>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
global_settings,
|
||||||
|
tree,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_additional_node(&'r self, new_element: &'r ContextElement<'r, 's>) -> Self {
|
||||||
|
let new_tree = self.tree.push(new_element);
|
||||||
|
Self::new(self.global_settings, new_tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&'r self) -> super::list::Iter<'r, &'r ContextElement<'r, 's>> {
|
||||||
|
self.tree.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_context(&'r self) -> Iter<'g, 'r, 's> {
|
||||||
|
Iter {
|
||||||
|
next: self.tree.iter_list(),
|
||||||
|
global_settings: self.global_settings,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_parent(&'r self) -> Option<Self> {
|
||||||
|
self.tree.get_parent().map(|parent_tree| Self {
|
||||||
|
global_settings: self.global_settings,
|
||||||
|
tree: parent_tree.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_data(&self) -> &ContextElement<'r, 's> {
|
||||||
|
self.tree.get_data()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_global_settings(&self) -> &'g GlobalSettings<'g, 's> {
|
||||||
|
self.global_settings
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_global_settings<'gg>(
|
||||||
|
&self,
|
||||||
|
new_settings: &'gg GlobalSettings<'gg, 's>,
|
||||||
|
) -> Context<'gg, 'r, 's> {
|
||||||
|
Context {
|
||||||
|
global_settings: new_settings,
|
||||||
|
tree: self.tree.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
|
pub fn check_exit_matcher(
|
||||||
|
&'r self,
|
||||||
|
i: OrgSource<'s>,
|
||||||
|
) -> IResult<OrgSource<'s>, OrgSource<'s>, CustomError<OrgSource<'s>>> {
|
||||||
|
let mut current_class_filter = ExitClass::Gamma;
|
||||||
|
for current_node in self.iter_context() {
|
||||||
|
let context_element = current_node.get_data();
|
||||||
|
match context_element {
|
||||||
|
ContextElement::ExitMatcherNode(exit_matcher) => {
|
||||||
|
if exit_matcher.class as u32 <= current_class_filter as u32 {
|
||||||
|
current_class_filter = exit_matcher.class;
|
||||||
|
let local_result = (exit_matcher.exit_matcher)(¤t_node, i);
|
||||||
|
if local_result.is_ok() {
|
||||||
|
return local_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// TODO: Make this a specific error instead of just a generic MyError
|
||||||
|
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
||||||
|
"NoExit".into(),
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates if elements should consume the whitespace after them.
|
||||||
|
///
|
||||||
|
/// Defaults to true.
|
||||||
|
pub fn should_consume_trailing_whitespace(&self) -> bool {
|
||||||
|
self._should_consume_trailing_whitespace().unwrap_or(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _should_consume_trailing_whitespace(&self) -> Option<bool> {
|
||||||
|
for current_node in self.iter() {
|
||||||
|
match current_node {
|
||||||
|
ContextElement::ConsumeTrailingWhitespace(should) => {
|
||||||
|
return Some(*should);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
|
fn document_end<'b, 'g, 'r, 's>(
|
||||||
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
|
eof(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Iter<'g, 'r, 's> {
|
||||||
|
global_settings: &'g GlobalSettings<'g, 's>,
|
||||||
|
next: super::list::IterList<'r, &'r ContextElement<'r, 's>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'g, 'r, 's> Iterator for Iter<'g, 'r, 's> {
|
||||||
|
type Item = Context<'g, 'r, 's>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let next_tree = self.next.next();
|
||||||
|
let ret =
|
||||||
|
next_tree.map(|parent_tree| Context::new(self.global_settings, parent_tree.clone()));
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r, 's> ContextElement<'r, 's> {
|
||||||
|
pub fn document_context() -> Self {
|
||||||
|
Self::ExitMatcherNode(ExitMatcherNode {
|
||||||
|
exit_matcher: &document_end,
|
||||||
|
class: ExitClass::Document,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/context/file_access_interface.rs
Normal file
23
src/context/file_access_interface.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub trait FileAccessInterface: Debug {
|
||||||
|
fn read_file(&self, path: &str) -> Result<String, std::io::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct LocalFileAccessInterface {
|
||||||
|
pub working_directory: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileAccessInterface for LocalFileAccessInterface {
|
||||||
|
fn read_file(&self, path: &str) -> Result<String, std::io::Error> {
|
||||||
|
let final_path = self
|
||||||
|
.working_directory
|
||||||
|
.as_ref()
|
||||||
|
.map(PathBuf::as_path)
|
||||||
|
.map(|pb| pb.join(path))
|
||||||
|
.unwrap_or_else(|| PathBuf::from(path));
|
||||||
|
Ok(std::fs::read_to_string(final_path)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/context/global_settings.rs
Normal file
34
src/context/global_settings.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
use super::FileAccessInterface;
|
||||||
|
use super::LocalFileAccessInterface;
|
||||||
|
use crate::types::Object;
|
||||||
|
|
||||||
|
// TODO: Ultimately, I think we'll need most of this: https://orgmode.org/manual/In_002dbuffer-Settings.html
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct GlobalSettings<'g, 's> {
|
||||||
|
pub radio_targets: Vec<&'g Vec<Object<'s>>>,
|
||||||
|
pub file_access: &'g dyn FileAccessInterface,
|
||||||
|
pub in_progress_todo_keywords: BTreeSet<String>,
|
||||||
|
pub complete_todo_keywords: BTreeSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'g, 's> GlobalSettings<'g, 's> {
|
||||||
|
pub fn new() -> GlobalSettings<'g, 's> {
|
||||||
|
GlobalSettings {
|
||||||
|
radio_targets: Vec::new(),
|
||||||
|
file_access: &LocalFileAccessInterface {
|
||||||
|
working_directory: None,
|
||||||
|
},
|
||||||
|
in_progress_todo_keywords: BTreeSet::new(),
|
||||||
|
complete_todo_keywords: BTreeSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'g, 's> Default for GlobalSettings<'g, 's> {
|
||||||
|
fn default() -> GlobalSettings<'g, 's> {
|
||||||
|
GlobalSettings::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/context/list.rs
Normal file
69
src/context/list.rs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct List<'parent, T> {
|
||||||
|
data: T,
|
||||||
|
parent: Link<'parent, T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Link<'parent, T> = Option<&'parent List<'parent, T>>;
|
||||||
|
|
||||||
|
impl<'parent, T> List<'parent, T> {
|
||||||
|
pub fn new(first_item: T) -> Self {
|
||||||
|
Self {
|
||||||
|
data: first_item,
|
||||||
|
parent: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_data(&self) -> &T {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_parent(&'parent self) -> Link<'parent, T> {
|
||||||
|
self.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> Iter<'_, T> {
|
||||||
|
Iter { next: Some(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_list(&self) -> IterList<'_, T> {
|
||||||
|
IterList { next: Some(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&'parent self, item: T) -> Self {
|
||||||
|
Self {
|
||||||
|
data: item,
|
||||||
|
parent: Some(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Iter<'a, T> {
|
||||||
|
next: Link<'a, T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Iterator for Iter<'a, T> {
|
||||||
|
type Item = &'a T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let ret = self.next.map(|link| link.get_data());
|
||||||
|
self.next = self.next.map(|link| link.get_parent()).flatten();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IterList<'a, T> {
|
||||||
|
next: Link<'a, T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Iterator for IterList<'a, T> {
|
||||||
|
type Item = &'a List<'a, T>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let ret = self.next;
|
||||||
|
self.next = self.next.map(|this| this.get_parent()).flatten();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/context/mod.rs
Normal file
29
src/context/mod.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
use crate::error::Res;
|
||||||
|
use crate::parser::OrgSource;
|
||||||
|
|
||||||
|
mod context;
|
||||||
|
mod exiting;
|
||||||
|
mod file_access_interface;
|
||||||
|
mod global_settings;
|
||||||
|
mod list;
|
||||||
|
mod parser_with_context;
|
||||||
|
|
||||||
|
pub type RefContext<'b, 'g, 'r, 's> = &'b Context<'g, 'r, 's>;
|
||||||
|
pub trait ContextMatcher = for<'b, 'g, 'r, 's> Fn(
|
||||||
|
RefContext<'b, 'g, 'r, 's>,
|
||||||
|
OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, OrgSource<'s>>;
|
||||||
|
pub type DynContextMatcher<'c> = dyn ContextMatcher + 'c;
|
||||||
|
pub trait Matcher = for<'s> Fn(OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>>;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub type DynMatcher<'c> = dyn Matcher + 'c;
|
||||||
|
|
||||||
|
pub use context::Context;
|
||||||
|
pub use context::ContextElement;
|
||||||
|
pub use context::ExitMatcherNode;
|
||||||
|
pub use exiting::ExitClass;
|
||||||
|
pub use file_access_interface::FileAccessInterface;
|
||||||
|
pub use file_access_interface::LocalFileAccessInterface;
|
||||||
|
pub use global_settings::GlobalSettings;
|
||||||
|
pub use list::List;
|
||||||
|
pub(crate) use parser_with_context::parser_with_context;
|
||||||
@@ -5,13 +5,14 @@ use nom::IResult;
|
|||||||
pub type Res<T, U> = IResult<T, U, CustomError<T>>;
|
pub type Res<T, U> = IResult<T, U, CustomError<T>>;
|
||||||
|
|
||||||
// TODO: MyError probably shouldn't be based on the same type as the input type since it's used exclusively with static strings right now.
|
// TODO: MyError probably shouldn't be based on the same type as the input type since it's used exclusively with static strings right now.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug)]
|
||||||
pub enum CustomError<I> {
|
pub enum CustomError<I> {
|
||||||
MyError(MyError<I>),
|
MyError(MyError<I>),
|
||||||
Nom(I, ErrorKind),
|
Nom(I, ErrorKind),
|
||||||
|
IO(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug)]
|
||||||
pub struct MyError<I>(pub I);
|
pub struct MyError<I>(pub I);
|
||||||
|
|
||||||
impl<I> ParseError<I> for CustomError<I> {
|
impl<I> ParseError<I> for CustomError<I> {
|
||||||
@@ -24,3 +25,9 @@ impl<I> ParseError<I> for CustomError<I> {
|
|||||||
other
|
other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I> From<std::io::Error> for CustomError<I> {
|
||||||
|
fn from(value: std::io::Error) -> Self {
|
||||||
|
CustomError::IO(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
10
src/lib.rs
10
src/lib.rs
@@ -1,16 +1,24 @@
|
|||||||
#![feature(round_char_boundary)]
|
#![feature(round_char_boundary)]
|
||||||
#![feature(exit_status_error)]
|
#![feature(exit_status_error)]
|
||||||
|
#![feature(trait_alias)]
|
||||||
|
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
mod compare;
|
mod compare;
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
pub use compare::compare_document;
|
pub use compare::compare_document;
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
pub use compare::emacs_parse_org_document;
|
pub use compare::emacs_parse_anonymous_org_document;
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
|
pub use compare::emacs_parse_file_org_document;
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
pub use compare::get_emacs_version;
|
pub use compare::get_emacs_version;
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
pub use compare::get_org_mode_version;
|
pub use compare::get_org_mode_version;
|
||||||
|
|
||||||
|
mod context;
|
||||||
mod error;
|
mod error;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
pub use context::GlobalSettings;
|
||||||
|
pub use context::LocalFileAccessInterface;
|
||||||
|
|||||||
102
src/main.rs
102
src/main.rs
@@ -1,17 +1,24 @@
|
|||||||
#![feature(round_char_boundary)]
|
#![feature(round_char_boundary)]
|
||||||
|
#![feature(exact_size_is_empty)]
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use ::organic::parser::document;
|
use ::organic::parser::parse;
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
use organic::compare_document;
|
use organic::compare_document;
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
use organic::emacs_parse_org_document;
|
use organic::emacs_parse_anonymous_org_document;
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
|
use organic::emacs_parse_file_org_document;
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
use organic::get_emacs_version;
|
use organic::get_emacs_version;
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
use organic::get_org_mode_version;
|
use organic::get_org_mode_version;
|
||||||
|
use organic::parser::parse_with_settings;
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
use organic::parser::sexp::sexp_with_padding;
|
use organic::parser::sexp::sexp_with_padding;
|
||||||
|
use organic::GlobalSettings;
|
||||||
|
use organic::LocalFileAccessInterface;
|
||||||
|
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
use crate::init_tracing::init_telemetry;
|
use crate::init_tracing::init_telemetry;
|
||||||
@@ -39,8 +46,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn main_body() -> Result<(), Box<dyn std::error::Error>> {
|
fn main_body() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let org_contents = read_stdin_to_string()?;
|
let args = std::env::args().skip(1);
|
||||||
run_compare(org_contents)
|
if args.is_empty() {
|
||||||
|
let org_contents = read_stdin_to_string()?;
|
||||||
|
run_anonymous_parse(org_contents)
|
||||||
|
} else {
|
||||||
|
for arg in args {
|
||||||
|
run_parse_on_file(arg)?
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_stdin_to_string() -> Result<String, Box<dyn std::error::Error>> {
|
fn read_stdin_to_string() -> Result<String, Box<dyn std::error::Error>> {
|
||||||
@@ -52,14 +67,12 @@ fn read_stdin_to_string() -> Result<String, Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
fn run_compare<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error::Error>> {
|
fn run_anonymous_parse<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let emacs_version = get_emacs_version()?;
|
|
||||||
let org_mode_version = get_org_mode_version()?;
|
|
||||||
let org_contents = org_contents.as_ref();
|
let org_contents = org_contents.as_ref();
|
||||||
eprintln!("Using emacs version: {}", emacs_version.trim());
|
eprintln!("Using emacs version: {}", get_emacs_version()?.trim());
|
||||||
eprintln!("Using org-mode version: {}", org_mode_version.trim());
|
eprintln!("Using org-mode version: {}", get_org_mode_version()?.trim());
|
||||||
let (remaining, rust_parsed) = document(org_contents).map_err(|e| e.to_string())?;
|
let rust_parsed = parse(org_contents)?;
|
||||||
let org_sexp = emacs_parse_org_document(org_contents)?;
|
let org_sexp = emacs_parse_anonymous_org_document(org_contents)?;
|
||||||
let (_remaining, parsed_sexp) =
|
let (_remaining, parsed_sexp) =
|
||||||
sexp_with_padding(org_sexp.as_str()).map_err(|e| e.to_string())?;
|
sexp_with_padding(org_sexp.as_str()).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
@@ -74,19 +87,78 @@ fn run_compare<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error:
|
|||||||
if diff_result.is_bad() {
|
if diff_result.is_bad() {
|
||||||
Err("Diff results do not match.")?;
|
Err("Diff results do not match.")?;
|
||||||
}
|
}
|
||||||
if remaining != "" {
|
|
||||||
Err(format!("There was unparsed text remaining: {}", remaining))?;
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "compare"))]
|
||||||
|
fn run_anonymous_parse<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
eprintln!(
|
||||||
|
"This program was built with compare disabled. Only parsing with organic, not comparing."
|
||||||
|
);
|
||||||
|
let rust_parsed = parse(org_contents.as_ref())?;
|
||||||
|
println!("{:#?}", rust_parsed);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "compare")]
|
||||||
|
fn run_parse_on_file<P: AsRef<Path>>(org_path: P) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let org_path = org_path.as_ref();
|
||||||
|
eprintln!("Using emacs version: {}", get_emacs_version()?.trim());
|
||||||
|
eprintln!("Using org-mode version: {}", get_org_mode_version()?.trim());
|
||||||
|
let parent_directory = org_path
|
||||||
|
.parent()
|
||||||
|
.ok_or("Should be contained inside a directory.")?;
|
||||||
|
let org_contents = std::fs::read_to_string(org_path)?;
|
||||||
|
let org_contents = org_contents.as_str();
|
||||||
|
let file_access_interface = LocalFileAccessInterface {
|
||||||
|
working_directory: Some(parent_directory.to_path_buf()),
|
||||||
|
};
|
||||||
|
let global_settings = {
|
||||||
|
let mut global_settings = GlobalSettings::default();
|
||||||
|
global_settings.file_access = &file_access_interface;
|
||||||
|
global_settings
|
||||||
|
};
|
||||||
|
let rust_parsed = parse_with_settings(org_contents, &global_settings)?;
|
||||||
|
let org_sexp = emacs_parse_file_org_document(org_path)?;
|
||||||
|
let (_remaining, parsed_sexp) =
|
||||||
|
sexp_with_padding(org_sexp.as_str()).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
println!("{}\n\n\n", org_contents);
|
||||||
|
println!("{}", org_sexp);
|
||||||
|
println!("{:#?}", rust_parsed);
|
||||||
|
|
||||||
|
// We do the diffing after printing out both parsed forms in case the diffing panics
|
||||||
|
let diff_result = compare_document(&parsed_sexp, &rust_parsed)?;
|
||||||
|
diff_result.print(org_contents)?;
|
||||||
|
|
||||||
|
if diff_result.is_bad() {
|
||||||
|
Err("Diff results do not match.")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "compare"))]
|
#[cfg(not(feature = "compare"))]
|
||||||
fn run_compare<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error::Error>> {
|
fn run_parse_on_file<P: AsRef<Path>>(org_path: P) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let org_path = org_path.as_ref();
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"This program was built with compare disabled. Only parsing with organic, not comparing."
|
"This program was built with compare disabled. Only parsing with organic, not comparing."
|
||||||
);
|
);
|
||||||
let (_remaining, rust_parsed) = document(org_contents.as_ref()).map_err(|e| e.to_string())?;
|
let parent_directory = org_path
|
||||||
|
.parent()
|
||||||
|
.ok_or("Should be contained inside a directory.")?;
|
||||||
|
let org_contents = std::fs::read_to_string(org_path)?;
|
||||||
|
let org_contents = org_contents.as_str();
|
||||||
|
let file_access_interface = LocalFileAccessInterface {
|
||||||
|
working_directory: Some(parent_directory.to_path_buf()),
|
||||||
|
};
|
||||||
|
let global_settings = {
|
||||||
|
let mut global_settings = GlobalSettings::default();
|
||||||
|
global_settings.file_access = &file_access_interface;
|
||||||
|
global_settings
|
||||||
|
};
|
||||||
|
let rust_parsed = parse_with_settings(org_contents, &global_settings)?;
|
||||||
println!("{:#?}", rust_parsed);
|
println!("{:#?}", rust_parsed);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,20 +5,21 @@ 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::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::plain_link::protocol;
|
use crate::parser::plain_link::protocol;
|
||||||
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::AngleLink;
|
use crate::types::AngleLink;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn angle_link<'r, 's>(
|
pub fn angle_link<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, AngleLink<'s>> {
|
) -> Res<OrgSource<'s>, AngleLink<'s>> {
|
||||||
let (remaining, _) = tag("<")(input)?;
|
let (remaining, _) = tag("<")(input)?;
|
||||||
@@ -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,
|
||||||
@@ -38,15 +41,15 @@ pub fn angle_link<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn path_angle<'r, 's>(
|
fn path_angle<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &path_angle_end,
|
||||||
exit_matcher: &path_angle_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
|
|
||||||
@@ -55,8 +58,8 @@ fn path_angle<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn path_angle_end<'r, 's>(
|
fn path_angle_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
tag(">")(input)
|
tag(">")(input)
|
||||||
|
|||||||
@@ -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,24 +13,26 @@ 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::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::citation_reference::citation_reference;
|
use crate::parser::citation_reference::citation_reference;
|
||||||
use crate::parser::citation_reference::citation_reference_key;
|
use crate::parser::citation_reference::citation_reference_key;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::object::Citation;
|
|
||||||
use crate::parser::object_parser::standard_set_object;
|
use crate::parser::object_parser::standard_set_object;
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::Object;
|
use crate::types::Citation;
|
||||||
|
use crate::types::Object;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn citation<'r, 's>(
|
pub fn citation<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Citation<'s>> {
|
) -> Res<OrgSource<'s>, Citation<'s>> {
|
||||||
// TODO: Despite being a standard object, citations cannot exist inside the global prefix/suffix for other citations because citations must contain something that matches @key which is forbidden inside the global prefix/suffix. This TODO is to evaluate if its worth putting in an explicit check for this (which can be easily accomplished by checking the output of `get_bracket_depth()`). I suspect its not worth it because I expect, outside of intentionally crafted inputs, this parser will exit immediately inside a citation since it is unlikely to find the "[cite" substring inside a citation global prefix/suffix.
|
// TODO: Despite being a standard object, citations cannot exist inside the global prefix/suffix for other citations because citations must contain something that matches @key which is forbidden inside the global prefix/suffix. This TODO is to evaluate if its worth putting in an explicit check for this (which can be easily accomplished by checking the output of `get_bracket_depth()`). I suspect its not worth it because I expect, outside of intentionally crafted inputs, this parser will exit immediately inside a citation since it is unlikely to find the "[cite" substring inside a citation global prefix/suffix.
|
||||||
@@ -48,7 +49,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,
|
||||||
@@ -59,7 +61,7 @@ pub fn citation<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn citestyle<'r, 's>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
fn citestyle<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _) = tuple((tag("/"), style))(input)?;
|
let (remaining, _) = tuple((tag("/"), style))(input)?;
|
||||||
let (remaining, _) = opt(tuple((tag("/"), variant)))(remaining)?;
|
let (remaining, _) = opt(tuple((tag("/"), variant)))(remaining)?;
|
||||||
let source = get_consumed(input, remaining);
|
let source = get_consumed(input, remaining);
|
||||||
@@ -67,30 +69,30 @@ fn citestyle<'r, 's>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn style<'r, 's>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
fn style<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(many1(verify(anychar, |c| {
|
recognize(many1(verify(anychar, |c| {
|
||||||
c.is_alphanumeric() || "_-".contains(*c)
|
c.is_alphanumeric() || "_-".contains(*c)
|
||||||
})))(input)
|
})))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn variant<'r, 's>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
fn variant<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(many1(verify(anychar, |c| {
|
recognize(many1(verify(anychar, |c| {
|
||||||
c.is_alphanumeric() || "_-/".contains(*c)
|
c.is_alphanumeric() || "_-/".contains(*c)
|
||||||
})))(input)
|
})))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn global_prefix<'r, 's>(
|
fn global_prefix<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||||
let exit_with_depth = global_prefix_end(input.get_bracket_depth());
|
let exit_with_depth = global_prefix_end(input.get_bracket_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, (children, _exit_contents)) = verify(
|
let (remaining, (children, _exit_contents)) = verify(
|
||||||
many_till(
|
many_till(
|
||||||
parser_with_context!(standard_set_object)(&parser_context),
|
parser_with_context!(standard_set_object)(&parser_context),
|
||||||
@@ -102,17 +104,13 @@ fn global_prefix<'r, 's>(
|
|||||||
Ok((remaining, children))
|
Ok((remaining, children))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_prefix_end(
|
fn global_prefix_end(starting_bracket_depth: BracketDepth) -> impl ContextMatcher {
|
||||||
starting_bracket_depth: BracketDepth,
|
move |context, input: OrgSource<'_>| _global_prefix_end(context, input, starting_bracket_depth)
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
|
||||||
_global_prefix_end(context, input, starting_bracket_depth)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _global_prefix_end<'r, 's>(
|
fn _global_prefix_end<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
starting_bracket_depth: BracketDepth,
|
starting_bracket_depth: BracketDepth,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
@@ -134,16 +132,16 @@ fn _global_prefix_end<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn global_suffix<'r, 's>(
|
fn global_suffix<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||||
let exit_with_depth = global_suffix_end(input.get_bracket_depth());
|
let exit_with_depth = global_suffix_end(input.get_bracket_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, (children, _exit_contents)) = verify(
|
let (remaining, (children, _exit_contents)) = verify(
|
||||||
many_till(
|
many_till(
|
||||||
parser_with_context!(standard_set_object)(&parser_context),
|
parser_with_context!(standard_set_object)(&parser_context),
|
||||||
@@ -154,17 +152,13 @@ fn global_suffix<'r, 's>(
|
|||||||
Ok((remaining, children))
|
Ok((remaining, children))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_suffix_end(
|
fn global_suffix_end(starting_bracket_depth: BracketDepth) -> impl ContextMatcher {
|
||||||
starting_bracket_depth: BracketDepth,
|
move |context, input: OrgSource<'_>| _global_suffix_end(context, input, starting_bracket_depth)
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
|
||||||
_global_suffix_end(context, input, starting_bracket_depth)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _global_suffix_end<'r, 's>(
|
fn _global_suffix_end<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
starting_bracket_depth: BracketDepth,
|
starting_bracket_depth: BracketDepth,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
@@ -188,19 +182,23 @@ fn _global_suffix_end<'r, 's>(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::context::Context;
|
||||||
|
use crate::context::GlobalSettings;
|
||||||
|
use crate::context::List;
|
||||||
use crate::parser::element_parser::element;
|
use crate::parser::element_parser::element;
|
||||||
use crate::parser::parser_context::ContextTree;
|
use crate::types::Element;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
use crate::types::Source;
|
||||||
use crate::parser::source::Source;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn citation_simple() {
|
fn citation_simple() {
|
||||||
let input = OrgSource::new("[cite:@foo]");
|
let input = OrgSource::new("[cite:@foo]");
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let paragraph_matcher = parser_with_context!(element(true))(&initial_context);
|
let paragraph_matcher = parser_with_context!(element(true))(&initial_context);
|
||||||
let (remaining, first_paragraph) = paragraph_matcher(input).expect("Parse first paragraph");
|
let (remaining, first_paragraph) = paragraph_matcher(input).expect("Parse first paragraph");
|
||||||
let first_paragraph = match first_paragraph {
|
let first_paragraph = match first_paragraph {
|
||||||
crate::parser::Element::Paragraph(paragraph) => paragraph,
|
Element::Paragraph(paragraph) => paragraph,
|
||||||
_ => panic!("Should be a paragraph!"),
|
_ => panic!("Should be a paragraph!"),
|
||||||
};
|
};
|
||||||
assert_eq!(Into::<&str>::into(remaining), "");
|
assert_eq!(Into::<&str>::into(remaining), "");
|
||||||
|
|||||||
@@ -12,24 +12,25 @@ use nom::sequence::tuple;
|
|||||||
|
|
||||||
use super::org_source::BracketDepth;
|
use super::org_source::BracketDepth;
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::object::CitationReference;
|
|
||||||
use crate::parser::object_parser::minimal_set_object;
|
use crate::parser::object_parser::minimal_set_object;
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::WORD_CONSTITUENT_CHARACTERS;
|
use crate::parser::util::WORD_CONSTITUENT_CHARACTERS;
|
||||||
use crate::parser::Object;
|
use crate::types::CitationReference;
|
||||||
|
use crate::types::Object;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn citation_reference<'r, 's>(
|
pub fn citation_reference<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, CitationReference<'s>> {
|
) -> Res<OrgSource<'s>, CitationReference<'s>> {
|
||||||
let (remaining, _prefix) =
|
let (remaining, _prefix) =
|
||||||
@@ -48,8 +49,8 @@ pub fn citation_reference<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn citation_reference_key<'r, 's>(
|
pub fn citation_reference_key<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, source) = recognize(tuple((
|
let (remaining, source) = recognize(tuple((
|
||||||
@@ -68,16 +69,16 @@ pub fn citation_reference_key<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn key_prefix<'r, 's>(
|
fn key_prefix<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||||
let exit_with_depth = key_prefix_end(input.get_bracket_depth());
|
let exit_with_depth = key_prefix_end(input.get_bracket_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, (children, _exit_contents)) = verify(
|
let (remaining, (children, _exit_contents)) = verify(
|
||||||
many_till(
|
many_till(
|
||||||
parser_with_context!(minimal_set_object)(&parser_context),
|
parser_with_context!(minimal_set_object)(&parser_context),
|
||||||
@@ -89,16 +90,16 @@ fn key_prefix<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn key_suffix<'r, 's>(
|
fn key_suffix<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||||
let exit_with_depth = key_suffix_end(input.get_bracket_depth());
|
let exit_with_depth = key_suffix_end(input.get_bracket_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, (children, _exit_contents)) = verify(
|
let (remaining, (children, _exit_contents)) = verify(
|
||||||
many_till(
|
many_till(
|
||||||
parser_with_context!(minimal_set_object)(&parser_context),
|
parser_with_context!(minimal_set_object)(&parser_context),
|
||||||
@@ -109,17 +110,13 @@ fn key_suffix<'r, 's>(
|
|||||||
Ok((remaining, children))
|
Ok((remaining, children))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_prefix_end(
|
fn key_prefix_end(starting_bracket_depth: BracketDepth) -> impl ContextMatcher {
|
||||||
starting_bracket_depth: BracketDepth,
|
move |context, input: OrgSource<'_>| _key_prefix_end(context, input, starting_bracket_depth)
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
|
||||||
_key_prefix_end(context, input, starting_bracket_depth)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _key_prefix_end<'r, 's>(
|
fn _key_prefix_end<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
starting_bracket_depth: BracketDepth,
|
starting_bracket_depth: BracketDepth,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
@@ -140,17 +137,13 @@ fn _key_prefix_end<'r, 's>(
|
|||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_suffix_end(
|
fn key_suffix_end(starting_bracket_depth: BracketDepth) -> impl ContextMatcher {
|
||||||
starting_bracket_depth: BracketDepth,
|
move |context, input: OrgSource<'_>| _key_suffix_end(context, input, starting_bracket_depth)
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
|
||||||
_key_suffix_end(context, input, starting_bracket_depth)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _key_suffix_end<'r, 's>(
|
fn _key_suffix_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
starting_bracket_depth: BracketDepth,
|
starting_bracket_depth: BracketDepth,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
|
|||||||
@@ -12,16 +12,16 @@ use nom::combinator::verify;
|
|||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::Clock;
|
use crate::types::Clock;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn clock<'r, 's>(
|
pub fn clock<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Clock<'s>> {
|
) -> Res<OrgSource<'s>, Clock<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
@@ -44,8 +44,8 @@ pub fn clock<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn inactive_timestamp_range_duration<'r, 's>(
|
fn inactive_timestamp_range_duration<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(tuple((
|
recognize(tuple((
|
||||||
@@ -66,8 +66,8 @@ fn inactive_timestamp_range_duration<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn inactive_timestamp<'r, 's>(
|
fn inactive_timestamp<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(tuple((
|
recognize(tuple((
|
||||||
|
|||||||
@@ -13,20 +13,20 @@ use nom::sequence::tuple;
|
|||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::util::get_consumed;
|
use super::util::get_consumed;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::util::exit_matcher_parser;
|
use crate::parser::util::exit_matcher_parser;
|
||||||
use crate::parser::util::immediate_in_section;
|
use crate::parser::util::immediate_in_section;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::Comment;
|
use crate::types::Comment;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn comment<'r, 's>(
|
pub fn comment<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Comment<'s>> {
|
) -> Res<OrgSource<'s>, Comment<'s>> {
|
||||||
if immediate_in_section(context, "comment") {
|
if immediate_in_section(context, "comment") {
|
||||||
@@ -34,7 +34,8 @@ pub fn comment<'r, 's>(
|
|||||||
"Cannot nest objects of the same element".into(),
|
"Cannot nest objects of the same element".into(),
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
let parser_context = context.with_additional_node(ContextElement::Context("comment"));
|
let parser_context = ContextElement::Context("comment");
|
||||||
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let comment_line_matcher = parser_with_context!(comment_line)(&parser_context);
|
let comment_line_matcher = parser_with_context!(comment_line)(&parser_context);
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
let (remaining, _first_line) = comment_line_matcher(input)?;
|
let (remaining, _first_line) = comment_line_matcher(input)?;
|
||||||
@@ -51,8 +52,8 @@ pub fn comment<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn comment_line<'r, 's>(
|
fn comment_line<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
@@ -69,8 +70,10 @@ fn comment_line<'r, 's>(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::parser::parser_context::ContextTree;
|
use crate::context::Context;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::GlobalSettings;
|
||||||
|
use crate::context::List;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn require_space_after_hash() {
|
fn require_space_after_hash() {
|
||||||
@@ -79,7 +82,9 @@ mod tests {
|
|||||||
#not a comment
|
#not a comment
|
||||||
# Comment again",
|
# Comment again",
|
||||||
);
|
);
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let comment_matcher = parser_with_context!(comment)(&initial_context);
|
let comment_matcher = parser_with_context!(comment)(&initial_context);
|
||||||
let (remaining, first_comment) = comment_matcher(input).expect("Parse first comment");
|
let (remaining, first_comment) = comment_matcher(input).expect("Parse first comment");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -1,22 +1,25 @@
|
|||||||
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;
|
||||||
use super::sexp::sexp;
|
use super::sexp::sexp;
|
||||||
use super::Context;
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::DiarySexp;
|
use crate::types::DiarySexp;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn diary_sexp<'r, 's>(
|
pub fn diary_sexp<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, DiarySexp<'s>> {
|
) -> Res<OrgSource<'s>, DiarySexp<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
@@ -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)?;
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ 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::character::complete::space1;
|
use nom::character::complete::space1;
|
||||||
|
use nom::combinator::all_consuming;
|
||||||
use nom::combinator::eof;
|
use nom::combinator::eof;
|
||||||
use nom::combinator::map;
|
use nom::combinator::map;
|
||||||
use nom::combinator::not;
|
use nom::combinator::not;
|
||||||
@@ -17,96 +18,126 @@ use nom::multi::many_till;
|
|||||||
use nom::multi::separated_list1;
|
use nom::multi::separated_list1;
|
||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use super::element::Element;
|
use super::in_buffer_settings::apply_in_buffer_settings;
|
||||||
use super::object::Object;
|
use super::in_buffer_settings::scan_for_in_buffer_settings;
|
||||||
use super::org_source::convert_error;
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::parser_with_context::parser_with_context;
|
|
||||||
use super::source::Source;
|
|
||||||
use super::token::AllTokensIterator;
|
use super::token::AllTokensIterator;
|
||||||
use super::token::Token;
|
use super::token::Token;
|
||||||
use super::util::exit_matcher_parser;
|
use super::util::exit_matcher_parser;
|
||||||
use super::util::get_consumed;
|
use super::util::get_consumed;
|
||||||
use super::util::start_of_line;
|
use super::util::start_of_line;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::Context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::GlobalSettings;
|
||||||
|
use crate::context::List;
|
||||||
|
use crate::context::RefContext;
|
||||||
|
use crate::error::CustomError;
|
||||||
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::comment::comment;
|
use crate::parser::comment::comment;
|
||||||
use crate::parser::element_parser::element;
|
use crate::parser::element_parser::element;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::object_parser::standard_set_object;
|
use crate::parser::object_parser::standard_set_object;
|
||||||
use crate::parser::parser_context::ContextElement;
|
use crate::parser::org_source::convert_error;
|
||||||
use crate::parser::parser_context::ContextTree;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::planning::planning;
|
use crate::parser::planning::planning;
|
||||||
use crate::parser::property_drawer::property_drawer;
|
use crate::parser::property_drawer::property_drawer;
|
||||||
use crate::parser::util::blank_line;
|
use crate::parser::util::blank_line;
|
||||||
use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting;
|
use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::types::Document;
|
||||||
|
use crate::types::DocumentElement;
|
||||||
|
use crate::types::Element;
|
||||||
|
use crate::types::Heading;
|
||||||
|
use crate::types::Object;
|
||||||
|
use crate::types::Section;
|
||||||
|
use crate::types::TodoKeywordType;
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Parse a full org-mode document.
|
||||||
pub struct Document<'s> {
|
///
|
||||||
pub source: &'s str,
|
/// This is the main entry point for Organic. It will parse the full contents of the input string as an org-mode document.
|
||||||
pub zeroth_section: Option<Section<'s>>,
|
#[allow(dead_code)]
|
||||||
pub children: Vec<Heading<'s>>,
|
pub fn parse<'s>(input: &'s str) -> Result<Document<'s>, String> {
|
||||||
|
parse_with_settings(input, &GlobalSettings::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Parse a full org-mode document with starting settings.
|
||||||
pub struct Heading<'s> {
|
///
|
||||||
pub source: &'s str,
|
/// This is the secondary entry point for Organic. It will parse the full contents of the input string as an org-mode document starting with the settings you supplied.
|
||||||
pub stars: usize,
|
///
|
||||||
pub todo_keyword: Option<&'s str>,
|
/// This will not prevent additional settings from being learned during parsing, for example when encountering a "#+TODO".
|
||||||
// TODO: add todo-type enum
|
#[allow(dead_code)]
|
||||||
pub title: Vec<Object<'s>>,
|
pub fn parse_with_settings<'g, 's>(
|
||||||
pub tags: Vec<&'s str>,
|
input: &'s str,
|
||||||
pub children: Vec<DocumentElement<'s>>,
|
global_settings: &'g GlobalSettings<'g, 's>,
|
||||||
|
) -> Result<Document<'s>, String> {
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(global_settings, List::new(&initial_context));
|
||||||
|
let wrapped_input = OrgSource::new(input);
|
||||||
|
let ret =
|
||||||
|
all_consuming(parser_with_context!(document_org_source)(&initial_context))(wrapped_input)
|
||||||
|
.map_err(|err| err.to_string())
|
||||||
|
.map(|(_remaining, parsed_document)| parsed_document);
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Parse a full org-mode document.
|
||||||
pub struct Section<'s> {
|
///
|
||||||
pub source: &'s str,
|
/// Use this entry point when you want to have direct control over the starting context or if you want to use this integrated with other nom parsers. For general-purpose usage, the `parse` and `parse_with_settings` functions are a lot simpler.
|
||||||
pub children: Vec<Element<'s>>,
|
///
|
||||||
}
|
/// This will not prevent additional settings from being learned during parsing, for example when encountering a "#+TODO".
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
pub fn document<'b, 'g, 'r, 's>(
|
||||||
pub enum DocumentElement<'s> {
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
Heading(Heading<'s>),
|
input: &'s str,
|
||||||
Section(Section<'s>),
|
) -> Res<&'s str, Document<'s>> {
|
||||||
}
|
let (remaining, doc) = document_org_source(context, input.into()).map_err(convert_error)?;
|
||||||
|
Ok((Into::<&str>::into(remaining), doc))
|
||||||
impl<'s> Source<'s> for Document<'s> {
|
|
||||||
fn get_source(&'s self) -> &'s str {
|
|
||||||
self.source
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s> Source<'s> for DocumentElement<'s> {
|
|
||||||
fn get_source(&'s self) -> &'s str {
|
|
||||||
match self {
|
|
||||||
DocumentElement::Heading(obj) => obj.source,
|
|
||||||
DocumentElement::Section(obj) => obj.source,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s> Source<'s> for Section<'s> {
|
|
||||||
fn get_source(&'s self) -> &'s str {
|
|
||||||
self.source
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s> Source<'s> for Heading<'s> {
|
|
||||||
fn get_source(&'s self) -> &'s str {
|
|
||||||
self.source
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn document(input: &str) -> Res<&str, Document> {
|
fn document_org_source<'b, 'g, 'r, 's>(
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
let wrapped_input = OrgSource::new(input);
|
input: OrgSource<'s>,
|
||||||
let (remaining, document) = _document(&initial_context, wrapped_input)
|
) -> Res<OrgSource<'s>, Document<'s>> {
|
||||||
.map(|(rem, out)| (Into::<&str>::into(rem), out))
|
let mut final_settings = Vec::new();
|
||||||
.map_err(convert_error)?;
|
let (_, document_settings) = scan_for_in_buffer_settings(input)?;
|
||||||
|
let setup_files: Vec<String> = document_settings
|
||||||
|
.iter()
|
||||||
|
.filter(|kw| kw.key.eq_ignore_ascii_case("setupfile"))
|
||||||
|
.map(|kw| kw.value)
|
||||||
|
.map(|setup_file| {
|
||||||
|
context
|
||||||
|
.get_global_settings()
|
||||||
|
.file_access
|
||||||
|
.read_file(setup_file)
|
||||||
|
.map_err(|err| nom::Err::<CustomError<OrgSource<'_>>>::Failure(err.into()))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
for setup_file in setup_files.iter().map(String::as_str) {
|
||||||
|
let (_, setup_file_settings) =
|
||||||
|
scan_for_in_buffer_settings(setup_file.into()).map_err(|_err| {
|
||||||
|
nom::Err::Error(CustomError::MyError(MyError(
|
||||||
|
"TODO: make this take an owned string so I can dump err.to_string() into it."
|
||||||
|
.into(),
|
||||||
|
)))
|
||||||
|
})?;
|
||||||
|
final_settings.extend(setup_file_settings);
|
||||||
|
}
|
||||||
|
final_settings.extend(document_settings);
|
||||||
|
let new_settings = apply_in_buffer_settings(final_settings, context.get_global_settings())
|
||||||
|
.map_err(|_err| {
|
||||||
|
nom::Err::Error(CustomError::MyError(MyError(
|
||||||
|
"TODO: make this take an owned string so I can dump err.to_string() into it."
|
||||||
|
.into(),
|
||||||
|
)))
|
||||||
|
})?;
|
||||||
|
let new_context = context.with_global_settings(&new_settings);
|
||||||
|
let context = &new_context;
|
||||||
|
|
||||||
|
let (remaining, document) =
|
||||||
|
_document(context, input).map(|(rem, out)| (Into::<&str>::into(rem), out))?;
|
||||||
{
|
{
|
||||||
// If there are radio targets in this document then we need to parse the entire document again with the knowledge of the radio targets.
|
// If there are radio targets in this document then we need to parse the entire document again with the knowledge of the radio targets.
|
||||||
let all_radio_targets: Vec<&Vec<Object<'_>>> = document
|
let all_radio_targets: Vec<&Vec<Object<'_>>> = document
|
||||||
@@ -122,11 +153,11 @@ pub fn document(input: &str) -> Res<&str, Document> {
|
|||||||
.map(|rt| &rt.children)
|
.map(|rt| &rt.children)
|
||||||
.collect();
|
.collect();
|
||||||
if !all_radio_targets.is_empty() {
|
if !all_radio_targets.is_empty() {
|
||||||
let initial_context = initial_context
|
let mut new_global_settings = context.get_global_settings().clone();
|
||||||
.with_additional_node(ContextElement::RadioTarget(all_radio_targets));
|
new_global_settings.radio_targets = all_radio_targets;
|
||||||
let (remaining, document) = _document(&initial_context, wrapped_input)
|
let parser_context = context.with_global_settings(&new_global_settings);
|
||||||
.map(|(rem, out)| (Into::<&str>::into(rem), out))
|
let (remaining, document) = _document(&parser_context, input)
|
||||||
.map_err(convert_error)?;
|
.map(|(rem, out)| (Into::<&str>::into(rem), out))?;
|
||||||
return Ok((remaining.into(), document));
|
return Ok((remaining.into(), document));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,8 +165,8 @@ pub fn document(input: &str) -> Res<&str, Document> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _document<'r, 's>(
|
fn _document<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Document<'s>> {
|
) -> Res<OrgSource<'s>, Document<'s>> {
|
||||||
let zeroth_section_matcher = parser_with_context!(zeroth_section)(context);
|
let zeroth_section_matcher = parser_with_context!(zeroth_section)(context);
|
||||||
@@ -155,20 +186,25 @@ fn _document<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn zeroth_section<'r, 's>(
|
fn zeroth_section<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Section<'s>> {
|
) -> Res<OrgSource<'s>, Section<'s>> {
|
||||||
// TODO: The zeroth section is specialized so it probably needs its own parser
|
// TODO: The zeroth section is specialized so it probably needs its own parser
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("section"))
|
ContextElement::Context("section"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Document,
|
class: ExitClass::Document,
|
||||||
exit_matcher: §ion_end,
|
exit_matcher: §ion_end,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
|
let without_consuming_whitespace_context = ContextElement::ConsumeTrailingWhitespace(false);
|
||||||
let without_consuming_whitespace_context =
|
let without_consuming_whitespace_context =
|
||||||
parser_context.with_additional_node(ContextElement::ConsumeTrailingWhitespace(false));
|
parser_context.with_additional_node(&without_consuming_whitespace_context);
|
||||||
|
|
||||||
let element_matcher = parser_with_context!(element(true))(&parser_context);
|
let element_matcher = parser_with_context!(element(true))(&parser_context);
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
@@ -209,18 +245,22 @@ fn zeroth_section<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn section<'r, 's>(
|
fn section<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
mut input: OrgSource<'s>,
|
mut input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Section<'s>> {
|
) -> Res<OrgSource<'s>, Section<'s>> {
|
||||||
// TODO: The zeroth section is specialized so it probably needs its own parser
|
// TODO: The zeroth section is specialized so it probably needs its own parser
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("section"))
|
ContextElement::Context("section"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Document,
|
class: ExitClass::Document,
|
||||||
exit_matcher: §ion_end,
|
exit_matcher: §ion_end,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
let element_matcher = parser_with_context!(element(true))(&parser_context);
|
let element_matcher = parser_with_context!(element(true))(&parser_context);
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
let (mut remaining, (planning_element, property_drawer_element)) = tuple((
|
let (mut remaining, (planning_element, property_drawer_element)) = tuple((
|
||||||
@@ -259,8 +299,8 @@ fn section<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn section_end<'r, 's>(
|
fn section_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(detect_headline)(input)
|
recognize(detect_headline)(input)
|
||||||
@@ -268,13 +308,16 @@ fn section_end<'r, 's>(
|
|||||||
|
|
||||||
const fn heading(
|
const fn heading(
|
||||||
parent_stars: usize,
|
parent_stars: usize,
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, Heading<'s>> {
|
) -> impl for<'b, 'g, 'r, 's> Fn(
|
||||||
move |context: Context, input: OrgSource<'_>| _heading(context, input, parent_stars)
|
RefContext<'b, 'g, 'r, 's>,
|
||||||
|
OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, Heading<'s>> {
|
||||||
|
move |context, input: OrgSource<'_>| _heading(context, input, parent_stars)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _heading<'r, 's>(
|
fn _heading<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
parent_stars: usize,
|
parent_stars: usize,
|
||||||
) -> Res<OrgSource<'s>, Heading<'s>> {
|
) -> Res<OrgSource<'s>, Heading<'s>> {
|
||||||
@@ -304,8 +347,9 @@ fn _heading<'r, 's>(
|
|||||||
Heading {
|
Heading {
|
||||||
source: source.into(),
|
source: source.into(),
|
||||||
stars: star_count,
|
stars: star_count,
|
||||||
todo_keyword: maybe_todo_keyword
|
todo_keyword: maybe_todo_keyword.map(|((todo_keyword_type, todo_keyword), _ws)| {
|
||||||
.map(|(todo_keyword, _ws)| Into::<&str>::into(todo_keyword)),
|
(todo_keyword_type, Into::<&str>::into(todo_keyword))
|
||||||
|
}),
|
||||||
title,
|
title,
|
||||||
tags: heading_tags,
|
tags: heading_tags,
|
||||||
children,
|
children,
|
||||||
@@ -320,8 +364,8 @@ fn detect_headline<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn headline<'r, 's>(
|
fn headline<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
parent_stars: usize,
|
parent_stars: usize,
|
||||||
) -> Res<
|
) -> Res<
|
||||||
@@ -329,17 +373,16 @@ fn headline<'r, 's>(
|
|||||||
(
|
(
|
||||||
usize,
|
usize,
|
||||||
OrgSource<'s>,
|
OrgSource<'s>,
|
||||||
Option<(OrgSource<'s>, OrgSource<'s>)>,
|
Option<((TodoKeywordType, OrgSource<'s>), OrgSource<'s>)>,
|
||||||
Vec<Object<'s>>,
|
Vec<Object<'s>>,
|
||||||
Vec<&'s str>,
|
Vec<&'s str>,
|
||||||
),
|
),
|
||||||
> {
|
> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Document,
|
||||||
class: ExitClass::Document,
|
exit_matcher: &headline_title_end,
|
||||||
exit_matcher: &headline_title_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let standard_set_object_matcher = parser_with_context!(standard_set_object)(&parser_context);
|
|
||||||
|
|
||||||
let (
|
let (
|
||||||
remaining,
|
remaining,
|
||||||
@@ -350,8 +393,11 @@ fn headline<'r, 's>(
|
|||||||
*star_count > parent_stars
|
*star_count > parent_stars
|
||||||
}),
|
}),
|
||||||
space1,
|
space1,
|
||||||
opt(tuple((heading_keyword, space1))),
|
opt(tuple((
|
||||||
many1(standard_set_object_matcher),
|
parser_with_context!(heading_keyword)(&parser_context),
|
||||||
|
space1,
|
||||||
|
))),
|
||||||
|
many1(parser_with_context!(standard_set_object)(&parser_context)),
|
||||||
opt(tuple((space0, tags))),
|
opt(tuple((space0, tags))),
|
||||||
space0,
|
space0,
|
||||||
alt((line_ending, eof)),
|
alt((line_ending, eof)),
|
||||||
@@ -375,8 +421,8 @@ fn headline<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn headline_title_end<'r, 's>(
|
fn headline_title_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(tuple((
|
recognize(tuple((
|
||||||
@@ -400,9 +446,49 @@ fn single_tag<'r, 's>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn heading_keyword<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
fn heading_keyword<'b, 'g, 'r, 's>(
|
||||||
// TODO: This should take into account the value of "#+TODO:" ref https://orgmode.org/manual/Per_002dfile-keywords.html and possibly the configurable variable org-todo-keywords ref https://orgmode.org/manual/Workflow-states.html. Case is significant.
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
alt((tag("TODO"), tag("DONE")))(input)
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, (TodoKeywordType, OrgSource<'s>)> {
|
||||||
|
let global_settings = context.get_global_settings();
|
||||||
|
if global_settings.in_progress_todo_keywords.is_empty()
|
||||||
|
&& global_settings.complete_todo_keywords.is_empty()
|
||||||
|
{
|
||||||
|
alt((
|
||||||
|
map(tag("TODO"), |capture| (TodoKeywordType::Todo, capture)),
|
||||||
|
map(tag("DONE"), |capture| (TodoKeywordType::Done, capture)),
|
||||||
|
))(input)
|
||||||
|
} else {
|
||||||
|
for todo_keyword in global_settings
|
||||||
|
.in_progress_todo_keywords
|
||||||
|
.iter()
|
||||||
|
.map(String::as_str)
|
||||||
|
{
|
||||||
|
let result = tag::<_, _, CustomError<_>>(todo_keyword)(input);
|
||||||
|
match result {
|
||||||
|
Ok((remaining, ent)) => {
|
||||||
|
return Ok((remaining, (TodoKeywordType::Todo, ent)));
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for todo_keyword in global_settings
|
||||||
|
.complete_todo_keywords
|
||||||
|
.iter()
|
||||||
|
.map(String::as_str)
|
||||||
|
{
|
||||||
|
let result = tag::<_, _, CustomError<_>>(todo_keyword)(input);
|
||||||
|
match result {
|
||||||
|
Ok((remaining, ent)) => {
|
||||||
|
return Ok((remaining, (TodoKeywordType::Done, ent)));
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(nom::Err::Error(CustomError::MyError(MyError(
|
||||||
|
"NoTodoKeyword".into(),
|
||||||
|
))))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Document<'s> {
|
impl<'s> Document<'s> {
|
||||||
|
|||||||
@@ -11,29 +11,29 @@ 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::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::element_parser::element;
|
use crate::parser::element_parser::element;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::immediate_in_section;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::util::WORD_CONSTITUENT_CHARACTERS;
|
use crate::parser::util::WORD_CONSTITUENT_CHARACTERS;
|
||||||
use crate::parser::Drawer;
|
use crate::types::Drawer;
|
||||||
use crate::parser::Element;
|
use crate::types::Element;
|
||||||
use crate::parser::Paragraph;
|
use crate::types::Paragraph;
|
||||||
|
use crate::types::SetSource;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn drawer<'r, 's>(
|
pub fn drawer<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Drawer<'s>> {
|
) -> Res<OrgSource<'s>, Drawer<'s>> {
|
||||||
if immediate_in_section(context, "drawer") {
|
if immediate_in_section(context, "drawer") {
|
||||||
@@ -50,13 +50,17 @@ pub fn drawer<'r, 's>(
|
|||||||
recognize(tuple((space0, line_ending))),
|
recognize(tuple((space0, line_ending))),
|
||||||
))(remaining)?;
|
))(remaining)?;
|
||||||
|
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("drawer"))
|
ContextElement::Context("drawer"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Alpha,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &drawer_end,
|
exit_matcher: &drawer_end,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
|
|
||||||
let element_matcher = parser_with_context!(element(true))(&parser_context);
|
let element_matcher = parser_with_context!(element(true))(&parser_context);
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
@@ -98,8 +102,8 @@ fn name<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn drawer_end<'r, 's>(
|
fn drawer_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
|
|||||||
@@ -12,28 +12,28 @@ 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::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::element_parser::element;
|
use crate::parser::element_parser::element;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::greater_element::DynamicBlock;
|
|
||||||
use crate::parser::lesser_element::Paragraph;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::immediate_in_section;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::Element;
|
use crate::types::DynamicBlock;
|
||||||
|
use crate::types::Element;
|
||||||
|
use crate::types::Paragraph;
|
||||||
|
use crate::types::SetSource;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn dynamic_block<'r, 's>(
|
pub fn dynamic_block<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, DynamicBlock<'s>> {
|
) -> Res<OrgSource<'s>, DynamicBlock<'s>> {
|
||||||
// TODO: Do I need to differentiate between different dynamic block types.
|
// TODO: Do I need to differentiate between different dynamic block types.
|
||||||
@@ -50,13 +50,17 @@ pub fn dynamic_block<'r, 's>(
|
|||||||
opt(tuple((space1, parameters))),
|
opt(tuple((space1, parameters))),
|
||||||
line_ending,
|
line_ending,
|
||||||
))(remaining)?;
|
))(remaining)?;
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("dynamic block"))
|
ContextElement::Context("dynamic block"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Alpha,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &dynamic_block_end,
|
exit_matcher: &dynamic_block_end,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
let parameters = match parameters {
|
let parameters = match parameters {
|
||||||
Some((_ws, parameters)) => Some(parameters),
|
Some((_ws, parameters)) => Some(parameters),
|
||||||
None => None,
|
None => None,
|
||||||
@@ -106,8 +110,8 @@ fn parameters<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn dynamic_block_end<'r, 's>(
|
fn dynamic_block_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use super::comment::comment;
|
|||||||
use super::diary_sexp::diary_sexp;
|
use super::diary_sexp::diary_sexp;
|
||||||
use super::drawer::drawer;
|
use super::drawer::drawer;
|
||||||
use super::dynamic_block::dynamic_block;
|
use super::dynamic_block::dynamic_block;
|
||||||
use super::element::Element;
|
|
||||||
use super::fixed_width_area::fixed_width_area;
|
use super::fixed_width_area::fixed_width_area;
|
||||||
use super::footnote_definition::footnote_definition;
|
use super::footnote_definition::footnote_definition;
|
||||||
use super::greater_block::greater_block;
|
use super::greater_block::greater_block;
|
||||||
@@ -24,25 +23,29 @@ use super::org_source::OrgSource;
|
|||||||
use super::paragraph::paragraph;
|
use super::paragraph::paragraph;
|
||||||
use super::plain_list::detect_plain_list;
|
use super::plain_list::detect_plain_list;
|
||||||
use super::plain_list::plain_list;
|
use super::plain_list::plain_list;
|
||||||
use super::source::SetSource;
|
|
||||||
use super::util::get_consumed;
|
use super::util::get_consumed;
|
||||||
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
|
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::table::org_mode_table;
|
use crate::parser::table::org_mode_table;
|
||||||
|
use crate::types::Element;
|
||||||
|
use crate::types::SetSource;
|
||||||
|
|
||||||
pub const fn element(
|
pub const fn element(
|
||||||
can_be_paragraph: bool,
|
can_be_paragraph: bool,
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, Element<'s>> {
|
) -> impl for<'b, 'g, 'r, 's> Fn(
|
||||||
move |context: Context, input: OrgSource<'_>| _element(context, input, can_be_paragraph)
|
RefContext<'b, 'g, 'r, 's>,
|
||||||
|
OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, Element<'s>> {
|
||||||
|
move |context, input: OrgSource<'_>| _element(context, input, can_be_paragraph)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _element<'r, 's>(
|
fn _element<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
can_be_paragraph: bool,
|
can_be_paragraph: bool,
|
||||||
) -> Res<OrgSource<'s>, Element<'s>> {
|
) -> Res<OrgSource<'s>, Element<'s>> {
|
||||||
@@ -118,17 +121,18 @@ fn _element<'r, 's>(
|
|||||||
|
|
||||||
pub const fn detect_element(
|
pub const fn detect_element(
|
||||||
can_be_paragraph: bool,
|
can_be_paragraph: bool,
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
) -> impl for<'b, 'g, 'r, 's> Fn(RefContext<'b, 'g, 'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, ()>
|
||||||
move |context: Context, input: OrgSource<'_>| _detect_element(context, input, can_be_paragraph)
|
{
|
||||||
|
move |context, input: OrgSource<'_>| _detect_element(context, input, can_be_paragraph)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _detect_element<'r, 's>(
|
fn _detect_element<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, '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() {
|
||||||
|
|||||||
@@ -2,18 +2,18 @@ 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::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::object::Entity;
|
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
|
use crate::types::Entity;
|
||||||
|
|
||||||
// TODO: Make this a user-provided variable corresponding to elisp's org-entities
|
// TODO: Make this a user-provided variable corresponding to elisp's org-entities
|
||||||
const ORG_ENTITIES: [&'static str; 413] = [
|
const ORG_ENTITIES: [&'static str; 413] = [
|
||||||
@@ -433,14 +433,15 @@ const ORG_ENTITIES: [&'static str; 413] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn entity<'r, 's>(
|
pub fn entity<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'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, _) = 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((
|
||||||
@@ -453,8 +454,8 @@ pub fn entity<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn name<'r, 's>(
|
fn name<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'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
|
||||||
|
|||||||
@@ -8,33 +8,36 @@ 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::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::ExportSnippet;
|
use crate::types::ExportSnippet;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn export_snippet<'r, 's>(
|
pub fn export_snippet<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, ExportSnippet<'s>> {
|
) -> Res<OrgSource<'s>, ExportSnippet<'s>> {
|
||||||
let (remaining, _) = tag("@@")(input)?;
|
let (remaining, _) = tag("@@")(input)?;
|
||||||
let (remaining, backend_name) = backend(context, remaining)?;
|
let (remaining, backend_name) = backend(context, remaining)?;
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &export_snippet_end,
|
||||||
exit_matcher: &export_snippet_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, backend_contents) = opt(tuple((
|
let (remaining, backend_contents) = opt(tuple((
|
||||||
tag(":"),
|
tag(":"),
|
||||||
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,
|
||||||
@@ -47,8 +50,8 @@ pub fn export_snippet<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn backend<'r, 's>(
|
fn backend<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, backend_name) =
|
let (remaining, backend_name) =
|
||||||
@@ -58,8 +61,8 @@ fn backend<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn contents<'r, 's>(
|
fn contents<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, source) = recognize(verify(
|
let (remaining, source) = recognize(verify(
|
||||||
@@ -70,8 +73,8 @@ fn contents<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn export_snippet_end<'r, 's>(
|
fn export_snippet_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
tag("@@")(input)
|
tag("@@")(input)
|
||||||
|
|||||||
@@ -12,17 +12,17 @@ use nom::sequence::preceded;
|
|||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::FixedWidthArea;
|
use crate::types::FixedWidthArea;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn fixed_width_area<'r, 's>(
|
pub fn fixed_width_area<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, FixedWidthArea<'s>> {
|
) -> Res<OrgSource<'s>, FixedWidthArea<'s>> {
|
||||||
let fixed_width_area_line_matcher = parser_with_context!(fixed_width_area_line)(context);
|
let fixed_width_area_line_matcher = parser_with_context!(fixed_width_area_line)(context);
|
||||||
@@ -41,8 +41,8 @@ pub fn fixed_width_area<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn fixed_width_area_line<'r, 's>(
|
fn fixed_width_area_line<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
|
|||||||
@@ -12,26 +12,26 @@ use nom::sequence::tuple;
|
|||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::util::WORD_CONSTITUENT_CHARACTERS;
|
use super::util::WORD_CONSTITUENT_CHARACTERS;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::element_parser::element;
|
use crate::parser::element_parser::element;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::greater_element::FootnoteDefinition;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::immediate_in_section;
|
||||||
use crate::parser::util::maybe_consume_trailing_whitespace;
|
use crate::parser::util::maybe_consume_trailing_whitespace;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
|
use crate::types::FootnoteDefinition;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn footnote_definition<'r, 's>(
|
pub fn footnote_definition<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, FootnoteDefinition<'s>> {
|
) -> Res<OrgSource<'s>, FootnoteDefinition<'s>> {
|
||||||
if immediate_in_section(context, "footnote definition") {
|
if immediate_in_section(context, "footnote definition") {
|
||||||
@@ -43,13 +43,17 @@ pub fn footnote_definition<'r, 's>(
|
|||||||
// Cannot be indented.
|
// Cannot be indented.
|
||||||
let (remaining, (_lead_in, lbl, _lead_out, _ws)) =
|
let (remaining, (_lead_in, lbl, _lead_out, _ws)) =
|
||||||
tuple((tag_no_case("[fn:"), label, tag("]"), space0))(input)?;
|
tuple((tag_no_case("[fn:"), label, tag("]"), space0))(input)?;
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("footnote definition"))
|
ContextElement::Context("footnote definition"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Alpha,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &footnote_definition_end,
|
exit_matcher: &footnote_definition_end,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
// TODO: The problem is we are not accounting for trailing whitespace like we do in section. Maybe it would be easier if we passed down whether or not to parse trailing whitespace into the element matcher similar to how tag takes in parameters.
|
// TODO: The problem is we are not accounting for trailing whitespace like we do in section. Maybe it would be easier if we passed down whether or not to parse trailing whitespace into the element matcher similar to how tag takes in parameters.
|
||||||
let element_matcher = parser_with_context!(element(true))(&parser_context);
|
let element_matcher = parser_with_context!(element(true))(&parser_context);
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
@@ -76,25 +80,14 @@ pub fn label<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn footnote_definition_end<'r, 's>(
|
fn footnote_definition_end<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, '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,12 +100,19 @@ 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::*;
|
||||||
use crate::parser::parser_context::ContextTree;
|
use crate::context::Context;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
use crate::context::GlobalSettings;
|
||||||
use crate::parser::Source;
|
use crate::context::List;
|
||||||
|
use crate::types::Source;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn two_paragraphs() {
|
fn two_paragraphs() {
|
||||||
@@ -123,7 +123,9 @@ mod tests {
|
|||||||
|
|
||||||
line footnote.",
|
line footnote.",
|
||||||
);
|
);
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let footnote_definition_matcher = parser_with_context!(element(true))(&initial_context);
|
let footnote_definition_matcher = parser_with_context!(element(true))(&initial_context);
|
||||||
let (remaining, first_footnote_definition) =
|
let (remaining, first_footnote_definition) =
|
||||||
footnote_definition_matcher(input).expect("Parse first footnote_definition");
|
footnote_definition_matcher(input).expect("Parse first footnote_definition");
|
||||||
@@ -154,7 +156,9 @@ line footnote.
|
|||||||
|
|
||||||
not in the footnote.",
|
not in the footnote.",
|
||||||
);
|
);
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let footnote_definition_matcher = parser_with_context!(element(true))(&initial_context);
|
let footnote_definition_matcher = parser_with_context!(element(true))(&initial_context);
|
||||||
let (remaining, first_footnote_definition) =
|
let (remaining, first_footnote_definition) =
|
||||||
footnote_definition_matcher(input).expect("Parse first footnote_definition");
|
footnote_definition_matcher(input).expect("Parse first footnote_definition");
|
||||||
|
|||||||
@@ -1,29 +1,30 @@
|
|||||||
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::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::footnote_definition::label;
|
use crate::parser::footnote_definition::label;
|
||||||
use crate::parser::object_parser::standard_set_object;
|
use crate::parser::object_parser::standard_set_object;
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::FootnoteReference;
|
use crate::types::FootnoteReference;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn footnote_reference<'r, 's>(
|
pub fn footnote_reference<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, FootnoteReference<'s>> {
|
) -> Res<OrgSource<'s>, FootnoteReference<'s>> {
|
||||||
alt((
|
alt((
|
||||||
@@ -34,17 +35,17 @@ pub fn footnote_reference<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn anonymous_footnote<'r, 's>(
|
fn anonymous_footnote<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, '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 exit_with_depth = footnote_definition_end(remaining.get_bracket_depth());
|
let exit_with_depth = footnote_definition_end(remaining.get_bracket_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Beta,
|
||||||
class: ExitClass::Beta,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, (children, _exit_contents)) = verify(
|
let (remaining, (children, _exit_contents)) = verify(
|
||||||
many_till(
|
many_till(
|
||||||
parser_with_context!(standard_set_object)(&parser_context),
|
parser_with_context!(standard_set_object)(&parser_context),
|
||||||
@@ -54,7 +55,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,
|
||||||
@@ -67,19 +69,19 @@ fn anonymous_footnote<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn inline_footnote<'r, 's>(
|
fn inline_footnote<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, '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 exit_with_depth = footnote_definition_end(remaining.get_bracket_depth());
|
let exit_with_depth = footnote_definition_end(remaining.get_bracket_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Beta,
|
||||||
class: ExitClass::Beta,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, (children, _exit_contents)) = verify(
|
let (remaining, (children, _exit_contents)) = verify(
|
||||||
many_till(
|
many_till(
|
||||||
parser_with_context!(standard_set_object)(&parser_context),
|
parser_with_context!(standard_set_object)(&parser_context),
|
||||||
@@ -89,7 +91,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,
|
||||||
@@ -102,14 +105,15 @@ 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<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
context: RefContext<'b, 'g, '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,
|
||||||
@@ -121,17 +125,15 @@ fn footnote_reference_only<'r, 's>(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn footnote_definition_end(
|
fn footnote_definition_end(starting_bracket_depth: BracketDepth) -> impl ContextMatcher {
|
||||||
starting_bracket_depth: BracketDepth,
|
move |context, input: OrgSource<'_>| {
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
|
||||||
_footnote_definition_end(context, input, starting_bracket_depth)
|
_footnote_definition_end(context, input, starting_bracket_depth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _footnote_definition_end<'r, 's>(
|
fn _footnote_definition_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
starting_bracket_depth: BracketDepth,
|
starting_bracket_depth: BracketDepth,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
|
|||||||
@@ -12,28 +12,29 @@ 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::Context;
|
use super::util::in_section;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::element_parser::element;
|
use crate::parser::element_parser::element;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::greater_element::GreaterBlock;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::types::Element;
|
||||||
use crate::parser::Paragraph;
|
use crate::types::GreaterBlock;
|
||||||
|
use crate::types::Paragraph;
|
||||||
|
use crate::types::SetSource;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn greater_block<'r, 's>(
|
pub fn greater_block<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, GreaterBlock<'s>> {
|
) -> Res<OrgSource<'s>, GreaterBlock<'s>> {
|
||||||
// TODO: Do I need to differentiate between different greater block types.
|
// TODO: Do I need to differentiate between different greater block types.
|
||||||
@@ -49,11 +50,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(),
|
||||||
))));
|
))));
|
||||||
@@ -61,13 +62,17 @@ pub fn greater_block<'r, 's>(
|
|||||||
let exit_with_name = greater_block_end(name.into());
|
let exit_with_name = greater_block_end(name.into());
|
||||||
let (remaining, parameters) = opt(tuple((space1, parameters)))(remaining)?;
|
let (remaining, parameters) = opt(tuple((space1, parameters)))(remaining)?;
|
||||||
let (remaining, _nl) = line_ending(remaining)?;
|
let (remaining, _nl) = line_ending(remaining)?;
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context(context_name))
|
ContextElement::Context(context_name.as_str()),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Alpha,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &exit_with_name,
|
exit_matcher: &exit_with_name,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
let parameters = match parameters {
|
let parameters = match parameters {
|
||||||
Some((_ws, parameters)) => Some(parameters),
|
Some((_ws, parameters)) => Some(parameters),
|
||||||
None => None,
|
None => None,
|
||||||
@@ -120,19 +125,16 @@ fn parameters<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|||||||
is_not("\r\n")(input)
|
is_not("\r\n")(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn greater_block_end<'x>(
|
fn greater_block_end<'c>(name: &'c str) -> impl ContextMatcher + 'c {
|
||||||
name: &'x str,
|
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
// TODO: Can this be done without making an owned copy?
|
// TODO: Can this be done without making an owned copy?
|
||||||
let name = name.to_owned();
|
move |context, input: OrgSource<'_>| _greater_block_end(context, input, name)
|
||||||
move |context: Context, input: OrgSource<'_>| _greater_block_end(context, input, name.as_str())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _greater_block_end<'r, 's, 'x>(
|
fn _greater_block_end<'b, 'g, 'r, 's, 'c>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
name: &'x str,
|
name: &'c str,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
let (remaining, _leading_whitespace) = space0(input)?;
|
let (remaining, _leading_whitespace) = space0(input)?;
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ use nom::multi::many1_count;
|
|||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::Context;
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::HorizontalRule;
|
use crate::types::HorizontalRule;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn horizontal_rule<'r, 's>(
|
pub fn horizontal_rule<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, HorizontalRule<'s>> {
|
) -> Res<OrgSource<'s>, HorizontalRule<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
|
|||||||
69
src/parser/in_buffer_settings.rs
Normal file
69
src/parser/in_buffer_settings.rs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
use nom::branch::alt;
|
||||||
|
use nom::bytes::complete::tag_no_case;
|
||||||
|
use nom::character::complete::anychar;
|
||||||
|
use nom::combinator::map;
|
||||||
|
use nom::multi::many0;
|
||||||
|
use nom::multi::many_till;
|
||||||
|
|
||||||
|
use super::keyword::filtered_keyword;
|
||||||
|
use super::keyword_todo::todo_keywords;
|
||||||
|
use super::OrgSource;
|
||||||
|
use crate::error::Res;
|
||||||
|
use crate::types::Keyword;
|
||||||
|
use crate::GlobalSettings;
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
|
pub fn scan_for_in_buffer_settings<'s>(
|
||||||
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, Vec<Keyword<'s>>> {
|
||||||
|
// TODO: Optimization idea: since this is slicing the OrgSource at each character, it might be more efficient to do a parser that uses a search function like take_until, and wrap it in a function similar to consumed but returning the input along with the normal output, then pass all of that into a verify that confirms we were at the start of a line using the input we just returned.
|
||||||
|
|
||||||
|
let keywords = many0(map(
|
||||||
|
many_till(anychar, filtered_keyword(in_buffer_settings_key)),
|
||||||
|
|(_, kw)| kw,
|
||||||
|
))(input);
|
||||||
|
keywords
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
|
fn in_buffer_settings_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
|
alt((
|
||||||
|
tag_no_case("archive"),
|
||||||
|
tag_no_case("category"),
|
||||||
|
tag_no_case("columns"),
|
||||||
|
tag_no_case("filetags"),
|
||||||
|
tag_no_case("link"),
|
||||||
|
tag_no_case("priorities"),
|
||||||
|
tag_no_case("property"),
|
||||||
|
tag_no_case("seq_todo"),
|
||||||
|
tag_no_case("setupfile"),
|
||||||
|
tag_no_case("startup"),
|
||||||
|
tag_no_case("tags"),
|
||||||
|
tag_no_case("todo"),
|
||||||
|
tag_no_case("typ_todo"),
|
||||||
|
))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_in_buffer_settings<'g, 's, 'sf>(
|
||||||
|
keywords: Vec<Keyword<'sf>>,
|
||||||
|
original_settings: &'g GlobalSettings<'g, 's>,
|
||||||
|
) -> Result<GlobalSettings<'g, 's>, String> {
|
||||||
|
let mut new_settings = original_settings.clone();
|
||||||
|
|
||||||
|
for kw in keywords.iter().filter(|kw| {
|
||||||
|
kw.key.eq_ignore_ascii_case("todo")
|
||||||
|
|| kw.key.eq_ignore_ascii_case("seq_todo")
|
||||||
|
|| kw.key.eq_ignore_ascii_case("typ_todo")
|
||||||
|
}) {
|
||||||
|
let (_, (in_progress_words, complete_words)) =
|
||||||
|
todo_keywords(kw.value).map_err(|err| err.to_string())?;
|
||||||
|
new_settings
|
||||||
|
.in_progress_todo_keywords
|
||||||
|
.extend(in_progress_words.into_iter().map(str::to_string));
|
||||||
|
new_settings
|
||||||
|
.complete_todo_keywords
|
||||||
|
.extend(complete_words.into_iter().map(str::to_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(new_settings)
|
||||||
|
}
|
||||||
@@ -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,21 +11,23 @@ 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::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::InlineBabelCall;
|
use crate::types::InlineBabelCall;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn inline_babel_call<'r, 's>(
|
pub fn inline_babel_call<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, InlineBabelCall<'s>> {
|
) -> Res<OrgSource<'s>, InlineBabelCall<'s>> {
|
||||||
let (remaining, _) = tag_no_case("call_")(input)?;
|
let (remaining, _) = tag_no_case("call_")(input)?;
|
||||||
@@ -34,7 +35,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,
|
||||||
@@ -45,15 +47,15 @@ pub fn inline_babel_call<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn name<'r, 's>(
|
fn name<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &name_end,
|
||||||
exit_matcher: &name_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, name) = recognize(many_till(
|
let (remaining, name) = recognize(many_till(
|
||||||
verify(anychar, |c| !(c.is_whitespace() || "[]()".contains(*c))),
|
verify(anychar, |c| !(c.is_whitespace() || "[]()".contains(*c))),
|
||||||
parser_with_context!(exit_matcher_parser)(&parser_context),
|
parser_with_context!(exit_matcher_parser)(&parser_context),
|
||||||
@@ -62,26 +64,26 @@ fn name<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn name_end<'r, 's>(
|
fn name_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(one_of("[("))(input)
|
recognize(one_of("[("))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn header<'r, 's>(
|
fn header<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _) = tag("[")(input)?;
|
let (remaining, _) = tag("[")(input)?;
|
||||||
|
|
||||||
let exit_with_depth = header_end(remaining.get_bracket_depth());
|
let exit_with_depth = header_end(remaining.get_bracket_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, name) = recognize(many_till(
|
let (remaining, name) = recognize(many_till(
|
||||||
anychar,
|
anychar,
|
||||||
@@ -91,17 +93,13 @@ fn header<'r, 's>(
|
|||||||
Ok((remaining, name))
|
Ok((remaining, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_end(
|
fn header_end(starting_bracket_depth: BracketDepth) -> impl ContextMatcher {
|
||||||
starting_bracket_depth: BracketDepth,
|
move |context, input: OrgSource<'_>| _header_end(context, input, starting_bracket_depth)
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
|
||||||
_header_end(context, input, starting_bracket_depth)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _header_end<'r, 's>(
|
fn _header_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
starting_bracket_depth: BracketDepth,
|
starting_bracket_depth: BracketDepth,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
@@ -120,18 +118,18 @@ fn _header_end<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn argument<'r, 's>(
|
fn argument<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _) = tag("(")(input)?;
|
let (remaining, _) = tag("(")(input)?;
|
||||||
|
|
||||||
let exit_with_depth = argument_end(remaining.get_parenthesis_depth());
|
let exit_with_depth = argument_end(remaining.get_parenthesis_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, name) = recognize(many_till(
|
let (remaining, name) = recognize(many_till(
|
||||||
anychar,
|
anychar,
|
||||||
@@ -141,17 +139,13 @@ fn argument<'r, 's>(
|
|||||||
Ok((remaining, name))
|
Ok((remaining, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn argument_end(
|
fn argument_end(starting_parenthesis_depth: BracketDepth) -> impl ContextMatcher {
|
||||||
starting_parenthesis_depth: BracketDepth,
|
move |context, input: OrgSource<'_>| _argument_end(context, input, starting_parenthesis_depth)
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
|
||||||
_argument_end(context, input, starting_parenthesis_depth)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _argument_end<'r, 's>(
|
fn _argument_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
starting_parenthesis_depth: BracketDepth,
|
starting_parenthesis_depth: BracketDepth,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
|
|||||||
@@ -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,28 +13,31 @@ 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::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::InlineSourceBlock;
|
use crate::types::InlineSourceBlock;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn inline_source_block<'r, 's>(
|
pub fn inline_source_block<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, InlineSourceBlock<'s>> {
|
) -> Res<OrgSource<'s>, InlineSourceBlock<'s>> {
|
||||||
let (remaining, _) = tag_no_case("src_")(input)?;
|
let (remaining, _) = tag_no_case("src_")(input)?;
|
||||||
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,
|
||||||
@@ -46,15 +48,15 @@ pub fn inline_source_block<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn lang<'r, 's>(
|
fn lang<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Beta,
|
||||||
class: ExitClass::Beta,
|
exit_matcher: &lang_end,
|
||||||
exit_matcher: &lang_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, lang) = recognize(many_till(
|
let (remaining, lang) = recognize(many_till(
|
||||||
verify(anychar, |c| !(c.is_whitespace() || "[{".contains(*c))),
|
verify(anychar, |c| !(c.is_whitespace() || "[{".contains(*c))),
|
||||||
parser_with_context!(exit_matcher_parser)(&parser_context),
|
parser_with_context!(exit_matcher_parser)(&parser_context),
|
||||||
@@ -63,26 +65,26 @@ fn lang<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn lang_end<'r, 's>(
|
fn lang_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(one_of("[{"))(input)
|
recognize(one_of("[{"))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn header<'r, 's>(
|
fn header<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _) = tag("[")(input)?;
|
let (remaining, _) = tag("[")(input)?;
|
||||||
|
|
||||||
let exit_with_depth = header_end(remaining.get_bracket_depth());
|
let exit_with_depth = header_end(remaining.get_bracket_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Beta,
|
||||||
class: ExitClass::Beta,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, header_contents) = recognize(many_till(
|
let (remaining, header_contents) = recognize(many_till(
|
||||||
anychar,
|
anychar,
|
||||||
@@ -92,17 +94,13 @@ fn header<'r, 's>(
|
|||||||
Ok((remaining, header_contents))
|
Ok((remaining, header_contents))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_end(
|
fn header_end(starting_bracket_depth: BracketDepth) -> impl ContextMatcher {
|
||||||
starting_bracket_depth: BracketDepth,
|
move |context, input: OrgSource<'_>| _header_end(context, input, starting_bracket_depth)
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
|
||||||
_header_end(context, input, starting_bracket_depth)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _header_end<'r, 's>(
|
fn _header_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
starting_bracket_depth: BracketDepth,
|
starting_bracket_depth: BracketDepth,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
@@ -121,18 +119,18 @@ fn _header_end<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn body<'r, 's>(
|
fn body<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _) = tag("{")(input)?;
|
let (remaining, _) = tag("{")(input)?;
|
||||||
|
|
||||||
let exit_with_depth = body_end(remaining.get_brace_depth());
|
let exit_with_depth = body_end(remaining.get_brace_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Beta,
|
||||||
class: ExitClass::Beta,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, body_contents) = recognize(many_till(
|
let (remaining, body_contents) = recognize(many_till(
|
||||||
anychar,
|
anychar,
|
||||||
@@ -152,15 +150,13 @@ fn body<'r, 's>(
|
|||||||
Ok((remaining, body_contents))
|
Ok((remaining, body_contents))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn body_end(
|
fn body_end(starting_brace_depth: BracketDepth) -> impl ContextMatcher {
|
||||||
starting_brace_depth: BracketDepth,
|
move |context, input: OrgSource<'_>| _body_end(context, input, starting_brace_depth)
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| _body_end(context, input, starting_brace_depth)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _body_end<'r, 's>(
|
fn _body_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
starting_brace_depth: BracketDepth,
|
starting_brace_depth: BracketDepth,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ 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::character::complete::space1;
|
use nom::character::complete::space1;
|
||||||
|
use nom::combinator::consumed;
|
||||||
use nom::combinator::eof;
|
use nom::combinator::eof;
|
||||||
use nom::combinator::not;
|
use nom::combinator::not;
|
||||||
use nom::combinator::peek;
|
use nom::combinator::peek;
|
||||||
@@ -16,12 +17,13 @@ use nom::sequence::tuple;
|
|||||||
|
|
||||||
use super::org_source::BracketDepth;
|
use super::org_source::BracketDepth;
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::Context;
|
use crate::context::Matcher;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::Keyword;
|
use crate::types::Keyword;
|
||||||
|
|
||||||
const ORG_ELEMENT_AFFILIATED_KEYWORDS: [&'static str; 13] = [
|
const ORG_ELEMENT_AFFILIATED_KEYWORDS: [&'static str; 13] = [
|
||||||
"caption", "data", "header", "headers", "label", "name", "plot", "resname", "result",
|
"caption", "data", "header", "headers", "label", "name", "plot", "resname", "result",
|
||||||
@@ -29,53 +31,80 @@ const ORG_ELEMENT_AFFILIATED_KEYWORDS: [&'static str; 13] = [
|
|||||||
];
|
];
|
||||||
const ORG_ELEMENT_DUAL_KEYWORDS: [&'static str; 2] = ["caption", "results"];
|
const ORG_ELEMENT_DUAL_KEYWORDS: [&'static str; 2] = ["caption", "results"];
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
pub fn filtered_keyword<F: Matcher>(
|
||||||
pub fn keyword<'r, 's>(
|
key_parser: F,
|
||||||
_context: Context<'r, 's>,
|
) -> impl for<'s> Fn(OrgSource<'s>) -> Res<OrgSource<'s>, Keyword<'s>> {
|
||||||
|
move |input| _filtered_keyword(&key_parser, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "tracing",
|
||||||
|
tracing::instrument(ret, level = "debug", skip(key_parser))
|
||||||
|
)]
|
||||||
|
fn _filtered_keyword<'s, F: Matcher>(
|
||||||
|
key_parser: F,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Keyword<'s>> {
|
) -> Res<OrgSource<'s>, Keyword<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
// TODO: When key is a member of org-element-parsed-keywords, value can contain the standard set objects, excluding footnote references.
|
// TODO: When key is a member of org-element-parsed-keywords, value can contain the standard set objects, excluding footnote references.
|
||||||
let (remaining, rule) = recognize(tuple((
|
let (remaining, (consumed_input, (_, _, parsed_key, _))) =
|
||||||
space0,
|
consumed(tuple((space0, tag("#+"), key_parser, tag(":"))))(input)?;
|
||||||
tag("#+"),
|
match tuple((
|
||||||
not(peek(tag_no_case("call"))),
|
space0::<OrgSource<'_>, CustomError<OrgSource<'_>>>,
|
||||||
not(peek(tag_no_case("begin"))),
|
|
||||||
is_not(" \t\r\n:"),
|
|
||||||
tag(":"),
|
|
||||||
alt((recognize(tuple((space1, is_not("\r\n")))), space0)),
|
|
||||||
alt((line_ending, eof)),
|
alt((line_ending, eof)),
|
||||||
)))(input)?;
|
))(remaining)
|
||||||
|
{
|
||||||
|
Ok((remaining, _)) => {
|
||||||
|
return Ok((
|
||||||
|
remaining,
|
||||||
|
Keyword {
|
||||||
|
source: consumed_input.into(),
|
||||||
|
key: parsed_key.into(),
|
||||||
|
value: "".into(),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
};
|
||||||
|
let (remaining, _ws) = space1(remaining)?;
|
||||||
|
let (remaining, parsed_value) = recognize(many_till(
|
||||||
|
anychar,
|
||||||
|
peek(tuple((space0, alt((line_ending, eof))))),
|
||||||
|
))(remaining)?;
|
||||||
|
let (remaining, _ws) = tuple((space0, alt((line_ending, eof))))(remaining)?;
|
||||||
Ok((
|
Ok((
|
||||||
remaining,
|
remaining,
|
||||||
Keyword {
|
Keyword {
|
||||||
source: rule.into(),
|
source: consumed_input.into(),
|
||||||
|
key: parsed_key.into(),
|
||||||
|
value: parsed_value.into(),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn affiliated_keyword<'r, 's>(
|
pub fn keyword<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Keyword<'s>> {
|
) -> Res<OrgSource<'s>, Keyword<'s>> {
|
||||||
start_of_line(input)?;
|
filtered_keyword(regular_keyword_key)(input)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: When key is a member of org-element-parsed-keywords, value can contain the standard set objects, excluding footnote references.
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
let (remaining, rule) = recognize(tuple((
|
pub fn affiliated_keyword<'b, 'g, 'r, 's>(
|
||||||
space0,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
tag("#+"),
|
input: OrgSource<'s>,
|
||||||
affiliated_key,
|
) -> Res<OrgSource<'s>, Keyword<'s>> {
|
||||||
tag(":"),
|
filtered_keyword(affiliated_key)(input)
|
||||||
alt((recognize(tuple((space1, is_not("\r\n")))), space0)),
|
}
|
||||||
alt((line_ending, eof)),
|
|
||||||
)))(input)?;
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
Ok((
|
fn regular_keyword_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
remaining,
|
recognize(tuple((
|
||||||
Keyword {
|
not(peek(tag_no_case("call"))),
|
||||||
source: rule.into(),
|
not(peek(tag_no_case("begin"))),
|
||||||
},
|
is_not(" \t\r\n:"),
|
||||||
))
|
)))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
|
|||||||
94
src/parser/keyword_todo.rs
Normal file
94
src/parser/keyword_todo.rs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
use nom::branch::alt;
|
||||||
|
use nom::bytes::complete::tag;
|
||||||
|
use nom::bytes::complete::take_till;
|
||||||
|
use nom::character::complete::line_ending;
|
||||||
|
use nom::character::complete::space0;
|
||||||
|
use nom::character::complete::space1;
|
||||||
|
use nom::combinator::eof;
|
||||||
|
use nom::combinator::opt;
|
||||||
|
use nom::combinator::verify;
|
||||||
|
use nom::multi::separated_list0;
|
||||||
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
|
use crate::error::Res;
|
||||||
|
|
||||||
|
// ref https://orgmode.org/manual/Per_002dfile-keywords.html
|
||||||
|
// ref https://orgmode.org/manual/Workflow-states.html
|
||||||
|
// Case is significant.
|
||||||
|
|
||||||
|
/// Parses the text in the value of a #+TODO keyword.
|
||||||
|
///
|
||||||
|
/// Example input: "foo bar baz | lorem ipsum"
|
||||||
|
pub fn todo_keywords<'s>(input: &'s str) -> Res<&'s str, (Vec<&'s str>, Vec<&'s str>)> {
|
||||||
|
let (remaining, mut before_pipe_words) = separated_list0(space1, todo_keyword_word)(input)?;
|
||||||
|
let (remaining, after_pipe_words) = opt(tuple((
|
||||||
|
tuple((space0, tag("|"), space0)),
|
||||||
|
separated_list0(space1, todo_keyword_word),
|
||||||
|
)))(remaining)?;
|
||||||
|
let (remaining, _eol) = alt((line_ending, eof))(remaining)?;
|
||||||
|
if let Some((_pipe, after_pipe_words)) = after_pipe_words {
|
||||||
|
Ok((remaining, (before_pipe_words, after_pipe_words)))
|
||||||
|
} else if !before_pipe_words.is_empty() {
|
||||||
|
// If there was no pipe, then the last word becomes a completion state instead.
|
||||||
|
let mut after_pipe_words = Vec::with_capacity(1);
|
||||||
|
after_pipe_words.push(
|
||||||
|
before_pipe_words
|
||||||
|
.pop()
|
||||||
|
.expect("If-statement proves this is Some."),
|
||||||
|
);
|
||||||
|
Ok((remaining, (before_pipe_words, after_pipe_words)))
|
||||||
|
} else {
|
||||||
|
// No words founds
|
||||||
|
Ok((remaining, (Vec::new(), Vec::new())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn todo_keyword_word<'s>(input: &'s str) -> Res<&'s str, &'s str> {
|
||||||
|
verify(take_till(|c| " \t\r\n|".contains(c)), |result: &str| {
|
||||||
|
!result.is_empty()
|
||||||
|
})(input)
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn before_and_after() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let input = "foo bar baz | lorem ipsum";
|
||||||
|
let (remaining, (before_pipe_words, after_pipe_words)) = todo_keywords(input)?;
|
||||||
|
assert_eq!(remaining, "");
|
||||||
|
assert_eq!(before_pipe_words, vec!["foo", "bar", "baz"]);
|
||||||
|
assert_eq!(after_pipe_words, vec!["lorem", "ipsum"]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_pipe() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let input = "foo bar baz";
|
||||||
|
let (remaining, (before_pipe_words, after_pipe_words)) = todo_keywords(input)?;
|
||||||
|
assert_eq!(remaining, "");
|
||||||
|
assert_eq!(before_pipe_words, vec!["foo", "bar"]);
|
||||||
|
assert_eq!(after_pipe_words, vec!["baz"]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn early_pipe() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let input = "| foo bar baz";
|
||||||
|
let (remaining, (before_pipe_words, after_pipe_words)) = todo_keywords(input)?;
|
||||||
|
assert_eq!(remaining, "");
|
||||||
|
assert_eq!(before_pipe_words, Vec::<&str>::new());
|
||||||
|
assert_eq!(after_pipe_words, vec!["foo", "bar", "baz"]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn late_pipe() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let input = "foo bar baz |";
|
||||||
|
let (remaining, (before_pipe_words, after_pipe_words)) = todo_keywords(input)?;
|
||||||
|
assert_eq!(remaining, "");
|
||||||
|
assert_eq!(before_pipe_words, vec!["foo", "bar", "baz"]);
|
||||||
|
assert_eq!(after_pipe_words, Vec::<&str>::new());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,19 +13,20 @@ use nom::sequence::tuple;
|
|||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::util::get_consumed;
|
use super::util::get_consumed;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::util::exit_matcher_parser;
|
use crate::parser::util::exit_matcher_parser;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::LatexEnvironment;
|
use crate::types::LatexEnvironment;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn latex_environment<'r, 's>(
|
pub fn latex_environment<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, LatexEnvironment<'s>> {
|
) -> Res<OrgSource<'s>, LatexEnvironment<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
@@ -39,13 +40,13 @@ pub fn latex_environment<'r, 's>(
|
|||||||
))(remaining)?;
|
))(remaining)?;
|
||||||
|
|
||||||
let latex_environment_end_specialized = latex_environment_end(name.into());
|
let latex_environment_end_specialized = latex_environment_end(name.into());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Beta,
|
||||||
class: ExitClass::Beta,
|
exit_matcher: &latex_environment_end_specialized,
|
||||||
exit_matcher: &latex_environment_end_specialized,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, _contents) = contents(&latex_environment_end_specialized, context, remaining)?;
|
let (remaining, _contents) = contents(&latex_environment_end_specialized)(context, remaining)?;
|
||||||
let (remaining, _end) = latex_environment_end_specialized(&parser_context, remaining)?;
|
let (remaining, _end) = latex_environment_end_specialized(&parser_context, remaining)?;
|
||||||
|
|
||||||
let source = get_consumed(input, remaining);
|
let source = get_consumed(input, remaining);
|
||||||
@@ -62,44 +63,42 @@ fn name<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|||||||
take_while1(|c: char| c.is_alphanumeric() || c == '*')(input)
|
take_while1(|c: char| c.is_alphanumeric() || c == '*')(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn contents<F: ContextMatcher>(end_matcher: F) -> impl ContextMatcher {
|
||||||
|
move |context, input| _contents(&end_matcher, context, input)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "tracing",
|
feature = "tracing",
|
||||||
tracing::instrument(ret, level = "debug", skip(end_matcher))
|
tracing::instrument(ret, level = "debug", skip(end_matcher))
|
||||||
)]
|
)]
|
||||||
pub fn contents<
|
fn _contents<'b, 'g, 'r, 's, F: ContextMatcher>(
|
||||||
'r,
|
|
||||||
's,
|
|
||||||
F: Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>>,
|
|
||||||
>(
|
|
||||||
end_matcher: F,
|
end_matcher: F,
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, source) = recognize(many_till(
|
let (remaining, source) = recognize(many_till(
|
||||||
anychar,
|
anychar,
|
||||||
peek(alt((
|
peek(alt((
|
||||||
parser_with_context!(exit_matcher_parser)(context),
|
parser_with_context!(exit_matcher_parser)(context),
|
||||||
parser_with_context!(end_matcher)(context),
|
parser_with_context!(&end_matcher)(context),
|
||||||
))),
|
))),
|
||||||
))(input)?;
|
))(input)?;
|
||||||
|
|
||||||
Ok((remaining, source))
|
Ok((remaining, source))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn latex_environment_end(
|
fn latex_environment_end(current_name: &str) -> impl ContextMatcher {
|
||||||
current_name: &str,
|
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
let current_name_lower = current_name.to_lowercase();
|
let current_name_lower = current_name.to_lowercase();
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
move |context, input: OrgSource<'_>| {
|
||||||
_latex_environment_end(context, input, current_name_lower.as_str())
|
_latex_environment_end(context, input, current_name_lower.as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _latex_environment_end<'r, 's, 'x>(
|
fn _latex_environment_end<'b, 'g, 'r, 's, 'c>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
current_name_lower: &'x str,
|
current_name_lower: &'c str,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
let (remaining, _leading_whitespace) = space0(input)?;
|
let (remaining, _leading_whitespace) = space0(input)?;
|
||||||
|
|||||||
@@ -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,18 +13,19 @@ 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::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::LatexFragment;
|
use crate::types::LatexFragment;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn latex_fragment<'r, 's>(
|
pub fn latex_fragment<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, LatexFragment<'s>> {
|
) -> Res<OrgSource<'s>, LatexFragment<'s>> {
|
||||||
let (remaining, _) = alt((
|
let (remaining, _) = alt((
|
||||||
@@ -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,
|
||||||
@@ -47,8 +48,8 @@ pub fn latex_fragment<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn raw_latex_fragment<'r, 's>(
|
fn raw_latex_fragment<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _) = tag("\\")(input)?;
|
let (remaining, _) = tag("\\")(input)?;
|
||||||
@@ -60,16 +61,16 @@ fn raw_latex_fragment<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn name<'r, 's>(
|
fn name<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
alpha1(input)
|
alpha1(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn brackets<'r, 's>(
|
fn brackets<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, body) = alt((
|
let (remaining, body) = alt((
|
||||||
@@ -100,8 +101,8 @@ fn brackets<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn escaped_parenthesis_fragment<'r, 's>(
|
fn escaped_parenthesis_fragment<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _) = tag("\\(")(input)?;
|
let (remaining, _) = tag("\\(")(input)?;
|
||||||
@@ -119,8 +120,8 @@ fn escaped_parenthesis_fragment<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn escaped_bracket_fragment<'r, 's>(
|
fn escaped_bracket_fragment<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _) = tag("\\[")(input)?;
|
let (remaining, _) = tag("\\[")(input)?;
|
||||||
@@ -138,8 +139,8 @@ fn escaped_bracket_fragment<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn double_dollar_fragment<'r, 's>(
|
fn double_dollar_fragment<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
// TODO: The documentation on the dollar sign versions is incomplete. Test to figure out what the real requirements are. For example, can this span more than 3 lines and can this contain a single $ since its terminated by $$?
|
// TODO: The documentation on the dollar sign versions is incomplete. Test to figure out what the real requirements are. For example, can this span more than 3 lines and can this contain a single $ since its terminated by $$?
|
||||||
@@ -158,8 +159,8 @@ fn double_dollar_fragment<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn dollar_char_fragment<'r, 's>(
|
fn dollar_char_fragment<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (_, _) = pre(context, input)?;
|
let (_, _) = pre(context, input)?;
|
||||||
@@ -173,7 +174,10 @@ fn dollar_char_fragment<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn pre<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
pub fn pre<'b, 'g, 'r, 's>(
|
||||||
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, ()> {
|
||||||
let preceding_character = input.get_preceding_character();
|
let preceding_character = input.get_preceding_character();
|
||||||
if let Some('$') = preceding_character {
|
if let Some('$') = preceding_character {
|
||||||
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
||||||
@@ -184,7 +188,10 @@ 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<'b, 'g, 'r, 's>(
|
||||||
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, ()> {
|
||||||
// TODO: What about eof? Test to find out.
|
// TODO: What about eof? Test to find out.
|
||||||
|
|
||||||
// TODO: Figure out which punctuation characters should be included.
|
// TODO: Figure out which punctuation characters should be included.
|
||||||
@@ -193,8 +200,8 @@ pub fn post<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgS
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn bordered_dollar_fragment<'r, 's>(
|
fn bordered_dollar_fragment<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (_, _) = pre(context, input)?;
|
let (_, _) = pre(context, input)?;
|
||||||
@@ -219,16 +226,16 @@ fn bordered_dollar_fragment<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn open_border<'r, 's>(
|
pub fn open_border<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(verify(none_of(".,;$"), |c| !c.is_whitespace()))(input)
|
recognize(verify(none_of(".,;$"), |c| !c.is_whitespace()))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn close_border<'r, 's>(
|
pub fn close_border<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, ()> {
|
) -> Res<OrgSource<'s>, ()> {
|
||||||
let preceding_character = input.get_preceding_character();
|
let preceding_character = input.get_preceding_character();
|
||||||
|
|||||||
@@ -12,42 +12,47 @@ 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::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::lesser_element::CommentBlock;
|
|
||||||
use crate::parser::lesser_element::ExampleBlock;
|
|
||||||
use crate::parser::lesser_element::ExportBlock;
|
|
||||||
use crate::parser::lesser_element::SrcBlock;
|
|
||||||
use crate::parser::lesser_element::VerseBlock;
|
|
||||||
use crate::parser::object::Object;
|
|
||||||
use crate::parser::object::PlainText;
|
|
||||||
use crate::parser::object_parser::standard_set_object;
|
use crate::parser::object_parser::standard_set_object;
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::util::text_until_exit;
|
use crate::parser::util::text_until_exit;
|
||||||
|
use crate::types::CommentBlock;
|
||||||
|
use crate::types::ExampleBlock;
|
||||||
|
use crate::types::ExportBlock;
|
||||||
|
use crate::types::Object;
|
||||||
|
use crate::types::PlainText;
|
||||||
|
use crate::types::SrcBlock;
|
||||||
|
use crate::types::VerseBlock;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn verse_block<'r, 's>(
|
pub fn verse_block<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, VerseBlock<'s>> {
|
) -> Res<OrgSource<'s>, VerseBlock<'s>> {
|
||||||
let (remaining, name) = lesser_block_begin("verse")(context, input)?;
|
let (remaining, name) = lesser_block_begin("verse")(context, input)?;
|
||||||
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
|
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
|
||||||
let (remaining, _nl) = line_ending(remaining)?;
|
let (remaining, _nl) = line_ending(remaining)?;
|
||||||
let lesser_block_end_specialized = lesser_block_end("verse");
|
let lesser_block_end_specialized = lesser_block_end("verse");
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("lesser block"))
|
ContextElement::Context("lesser block"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Beta,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &lesser_block_end_specialized,
|
exit_matcher: &lesser_block_end_specialized,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
let parameters = match parameters {
|
let parameters = match parameters {
|
||||||
Some((_ws, parameters)) => Some(parameters),
|
Some((_ws, parameters)) => Some(parameters),
|
||||||
None => None,
|
None => None,
|
||||||
@@ -84,21 +89,25 @@ pub fn verse_block<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn comment_block<'r, 's>(
|
pub fn comment_block<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, CommentBlock<'s>> {
|
) -> Res<OrgSource<'s>, CommentBlock<'s>> {
|
||||||
let (remaining, name) = lesser_block_begin("comment")(context, input)?;
|
let (remaining, name) = lesser_block_begin("comment")(context, input)?;
|
||||||
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
|
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
|
||||||
let (remaining, _nl) = line_ending(remaining)?;
|
let (remaining, _nl) = line_ending(remaining)?;
|
||||||
let lesser_block_end_specialized = lesser_block_end("comment");
|
let lesser_block_end_specialized = lesser_block_end("comment");
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("lesser block"))
|
ContextElement::Context("lesser block"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Beta,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &lesser_block_end_specialized,
|
exit_matcher: &lesser_block_end_specialized,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
let parameters = match parameters {
|
let parameters = match parameters {
|
||||||
Some((_ws, parameters)) => Some(parameters),
|
Some((_ws, parameters)) => Some(parameters),
|
||||||
None => None,
|
None => None,
|
||||||
@@ -120,21 +129,25 @@ pub fn comment_block<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn example_block<'r, 's>(
|
pub fn example_block<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, ExampleBlock<'s>> {
|
) -> Res<OrgSource<'s>, ExampleBlock<'s>> {
|
||||||
let (remaining, _name) = lesser_block_begin("example")(context, input)?;
|
let (remaining, _name) = lesser_block_begin("example")(context, input)?;
|
||||||
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
|
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
|
||||||
let (remaining, _nl) = line_ending(remaining)?;
|
let (remaining, _nl) = line_ending(remaining)?;
|
||||||
let lesser_block_end_specialized = lesser_block_end("example");
|
let lesser_block_end_specialized = lesser_block_end("example");
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("lesser block"))
|
ContextElement::Context("lesser block"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Beta,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &lesser_block_end_specialized,
|
exit_matcher: &lesser_block_end_specialized,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
let parameters = match parameters {
|
let parameters = match parameters {
|
||||||
Some((_ws, parameters)) => Some(parameters),
|
Some((_ws, parameters)) => Some(parameters),
|
||||||
None => None,
|
None => None,
|
||||||
@@ -156,8 +169,8 @@ pub fn example_block<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn export_block<'r, 's>(
|
pub fn export_block<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, ExportBlock<'s>> {
|
) -> Res<OrgSource<'s>, ExportBlock<'s>> {
|
||||||
let (remaining, name) = lesser_block_begin("export")(context, input)?;
|
let (remaining, name) = lesser_block_begin("export")(context, input)?;
|
||||||
@@ -165,13 +178,17 @@ pub fn export_block<'r, 's>(
|
|||||||
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
|
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
|
||||||
let (remaining, _nl) = line_ending(remaining)?;
|
let (remaining, _nl) = line_ending(remaining)?;
|
||||||
let lesser_block_end_specialized = lesser_block_end("export");
|
let lesser_block_end_specialized = lesser_block_end("export");
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("lesser block"))
|
ContextElement::Context("lesser block"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Beta,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &lesser_block_end_specialized,
|
exit_matcher: &lesser_block_end_specialized,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
let parameters = match parameters {
|
let parameters = match parameters {
|
||||||
Some((_ws, parameters)) => Some(parameters),
|
Some((_ws, parameters)) => Some(parameters),
|
||||||
None => None,
|
None => None,
|
||||||
@@ -193,8 +210,8 @@ pub fn export_block<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn src_block<'r, 's>(
|
pub fn src_block<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, SrcBlock<'s>> {
|
) -> Res<OrgSource<'s>, SrcBlock<'s>> {
|
||||||
let (remaining, name) = lesser_block_begin("src")(context, input)?;
|
let (remaining, name) = lesser_block_begin("src")(context, input)?;
|
||||||
@@ -202,13 +219,17 @@ pub fn src_block<'r, 's>(
|
|||||||
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
|
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
|
||||||
let (remaining, _nl) = line_ending(remaining)?;
|
let (remaining, _nl) = line_ending(remaining)?;
|
||||||
let lesser_block_end_specialized = lesser_block_end("src");
|
let lesser_block_end_specialized = lesser_block_end("src");
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("lesser block"))
|
ContextElement::Context("lesser block"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Alpha,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &lesser_block_end_specialized,
|
exit_matcher: &lesser_block_end_specialized,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
let parameters = match parameters {
|
let parameters = match parameters {
|
||||||
Some((_ws, parameters)) => Some(parameters),
|
Some((_ws, parameters)) => Some(parameters),
|
||||||
None => None,
|
None => None,
|
||||||
@@ -239,20 +260,18 @@ fn data<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|||||||
is_not("\r\n")(input)
|
is_not("\r\n")(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lesser_block_end(
|
fn lesser_block_end(current_name: &str) -> impl ContextMatcher {
|
||||||
current_name: &str,
|
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
let current_name_lower = current_name.to_lowercase();
|
let current_name_lower = current_name.to_lowercase();
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
move |context, input: OrgSource<'_>| {
|
||||||
_lesser_block_end(context, input, current_name_lower.as_str())
|
_lesser_block_end(context, input, current_name_lower.as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _lesser_block_end<'r, 's, 'x>(
|
fn _lesser_block_end<'b, 'g, 'r, 's, 'c>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
current_name_lower: &'x str,
|
current_name_lower: &'c str,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
let (remaining, _leading_whitespace) = space0(input)?;
|
let (remaining, _leading_whitespace) = space0(input)?;
|
||||||
@@ -268,18 +287,16 @@ fn _lesser_block_end<'r, 's, 'x>(
|
|||||||
/// Parser for the beginning of a lesser block
|
/// Parser for the beginning of a lesser block
|
||||||
///
|
///
|
||||||
/// current_name MUST be lowercase. We do not do the conversion ourselves because it is not allowed in a const fn.
|
/// current_name MUST be lowercase. We do not do the conversion ourselves because it is not allowed in a const fn.
|
||||||
const fn lesser_block_begin(
|
const fn lesser_block_begin<'c>(current_name: &'c str) -> impl ContextMatcher + 'c {
|
||||||
current_name: &'static str,
|
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
// TODO: Since this is a const fn, is there ANY way to "generate" functions at compile time?
|
// TODO: Since this is a const fn, is there ANY way to "generate" functions at compile time?
|
||||||
move |context: Context, input: OrgSource<'_>| _lesser_block_begin(context, input, current_name)
|
move |context, input: OrgSource<'_>| _lesser_block_begin(context, input, current_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _lesser_block_begin<'r, 's, 'x>(
|
fn _lesser_block_begin<'b, 'g, 'r, 's, 'c>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
current_name_lower: &'x str,
|
current_name_lower: &'c str,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
let (remaining, _leading_whitespace) = space0(input)?;
|
let (remaining, _leading_whitespace) = space0(input)?;
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ use nom::combinator::recognize;
|
|||||||
use nom::multi::many0;
|
use nom::multi::many0;
|
||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::Context;
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
use crate::parser::LineBreak;
|
use crate::types::LineBreak;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn line_break<'r, 's>(
|
pub fn line_break<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, LineBreak<'s>> {
|
) -> Res<OrgSource<'s>, LineBreak<'s>> {
|
||||||
let (remaining, _) = pre(context, input)?;
|
let (remaining, _) = pre(context, input)?;
|
||||||
@@ -31,7 +31,10 @@ pub fn line_break<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn pre<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
fn pre<'b, 'g, 'r, 's>(
|
||||||
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, ()> {
|
||||||
let preceding_character = input.get_preceding_character();
|
let preceding_character = input.get_preceding_character();
|
||||||
match preceding_character {
|
match preceding_character {
|
||||||
// If None, we are at the start of the file
|
// If None, we are at the start of the file
|
||||||
|
|||||||
@@ -1,183 +0,0 @@
|
|||||||
use std::fmt::Debug;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct List<T> {
|
|
||||||
head: Option<Rc<Node<T>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Clone for List<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
List {
|
|
||||||
head: self.head.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Node<T> {
|
|
||||||
data: T,
|
|
||||||
parent: Option<Rc<Node<T>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Node<T> {
|
|
||||||
pub fn get_data(&self) -> &T {
|
|
||||||
&self.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> List<T> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
List { head: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn branch_from(trunk: &Rc<Node<T>>) -> Self {
|
|
||||||
List {
|
|
||||||
head: Some(trunk.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_front(&self, data: T) -> List<T> {
|
|
||||||
List {
|
|
||||||
head: Some(Rc::new(Node {
|
|
||||||
data: data,
|
|
||||||
parent: self.head.clone(),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_front(&mut self) -> (Option<T>, List<T>) {
|
|
||||||
match self.head.take() {
|
|
||||||
None => (None, List::new()),
|
|
||||||
Some(popped_node) => {
|
|
||||||
let extracted_node = match Rc::try_unwrap(popped_node) {
|
|
||||||
Ok(node) => node,
|
|
||||||
Err(_) => panic!("try_unwrap failed on Rc in pop_front on List."),
|
|
||||||
};
|
|
||||||
(
|
|
||||||
Some(extracted_node.data),
|
|
||||||
List {
|
|
||||||
head: extracted_node.parent,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn without_front(&self) -> List<T> {
|
|
||||||
List {
|
|
||||||
head: self.head.as_ref().map(|node| node.parent.clone()).flatten(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn get_data(&self) -> Option<&T> {
|
|
||||||
self.head.as_ref().map(|rc_node| &rc_node.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.head.is_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ptr_eq(&self, other: &List<T>) -> bool {
|
|
||||||
match (self.head.as_ref(), other.head.as_ref()) {
|
|
||||||
(None, None) => true,
|
|
||||||
(None, Some(_)) | (Some(_), None) => false,
|
|
||||||
(Some(me), Some(them)) => Rc::ptr_eq(me, them),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &Rc<Node<T>>> {
|
|
||||||
NodeIter {
|
|
||||||
position: &self.head,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn iter_until<'a>(&'a self, other: &'a List<T>) -> impl Iterator<Item = &Rc<Node<T>>> {
|
|
||||||
NodeIterUntil {
|
|
||||||
position: &self.head,
|
|
||||||
stop: &other.head,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn into_iter_until<'a>(self, other: &'a List<T>) -> impl Iterator<Item = T> + 'a {
|
|
||||||
NodeIntoIterUntil {
|
|
||||||
position: self,
|
|
||||||
stop: &other,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NodeIter<'a, T> {
|
|
||||||
position: &'a Option<Rc<Node<T>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Iterator for NodeIter<'a, T> {
|
|
||||||
type Item = &'a Rc<Node<T>>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
let (return_value, next_position) = match &self.position {
|
|
||||||
None => return None,
|
|
||||||
Some(rc_node) => {
|
|
||||||
let next_position = &rc_node.parent;
|
|
||||||
let return_value = rc_node;
|
|
||||||
(return_value, next_position)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.position = next_position;
|
|
||||||
Some(return_value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NodeIterUntil<'a, T> {
|
|
||||||
position: &'a Option<Rc<Node<T>>>,
|
|
||||||
stop: &'a Option<Rc<Node<T>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Iterator for NodeIterUntil<'a, T> {
|
|
||||||
type Item = &'a Rc<Node<T>>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
match (self.position, self.stop) {
|
|
||||||
(_, None) => {}
|
|
||||||
(None, _) => {}
|
|
||||||
(Some(this_rc), Some(stop_rc)) => {
|
|
||||||
if Rc::ptr_eq(this_rc, stop_rc) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let (return_value, next_position) = match &self.position {
|
|
||||||
None => return None,
|
|
||||||
Some(rc_node) => {
|
|
||||||
let next_position = &rc_node.parent;
|
|
||||||
let return_value = rc_node;
|
|
||||||
(return_value, next_position)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.position = next_position;
|
|
||||||
Some(return_value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NodeIntoIterUntil<'a, T> {
|
|
||||||
position: List<T>,
|
|
||||||
stop: &'a List<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Iterator for NodeIntoIterUntil<'a, T> {
|
|
||||||
type Item = T;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if self.position.ptr_eq(self.stop) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let (popped_element, new_position) = self.position.pop_front();
|
|
||||||
self.position = new_position;
|
|
||||||
popped_element
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,33 +7,27 @@ mod diary_sexp;
|
|||||||
mod document;
|
mod document;
|
||||||
mod drawer;
|
mod drawer;
|
||||||
mod dynamic_block;
|
mod dynamic_block;
|
||||||
mod element;
|
|
||||||
mod element_parser;
|
mod element_parser;
|
||||||
mod entity;
|
mod entity;
|
||||||
mod exiting;
|
|
||||||
mod export_snippet;
|
mod export_snippet;
|
||||||
mod fixed_width_area;
|
mod fixed_width_area;
|
||||||
mod footnote_definition;
|
mod footnote_definition;
|
||||||
mod footnote_reference;
|
mod footnote_reference;
|
||||||
mod greater_block;
|
mod greater_block;
|
||||||
mod greater_element;
|
|
||||||
mod horizontal_rule;
|
mod horizontal_rule;
|
||||||
|
mod in_buffer_settings;
|
||||||
mod inline_babel_call;
|
mod inline_babel_call;
|
||||||
mod inline_source_block;
|
mod inline_source_block;
|
||||||
mod keyword;
|
mod keyword;
|
||||||
|
mod keyword_todo;
|
||||||
mod latex_environment;
|
mod latex_environment;
|
||||||
mod latex_fragment;
|
mod latex_fragment;
|
||||||
mod lesser_block;
|
mod lesser_block;
|
||||||
mod lesser_element;
|
|
||||||
mod line_break;
|
mod line_break;
|
||||||
mod list;
|
|
||||||
mod object;
|
|
||||||
mod object_parser;
|
mod object_parser;
|
||||||
mod org_macro;
|
mod org_macro;
|
||||||
mod org_source;
|
mod org_source;
|
||||||
mod paragraph;
|
mod paragraph;
|
||||||
mod parser_context;
|
|
||||||
mod parser_with_context;
|
|
||||||
mod plain_link;
|
mod plain_link;
|
||||||
mod plain_list;
|
mod plain_list;
|
||||||
mod plain_text;
|
mod plain_text;
|
||||||
@@ -42,7 +36,6 @@ mod property_drawer;
|
|||||||
mod radio_link;
|
mod radio_link;
|
||||||
mod regular_link;
|
mod regular_link;
|
||||||
pub mod sexp;
|
pub mod sexp;
|
||||||
mod source;
|
|
||||||
mod statistics_cookie;
|
mod statistics_cookie;
|
||||||
mod subscript_and_superscript;
|
mod subscript_and_superscript;
|
||||||
mod table;
|
mod table;
|
||||||
@@ -52,62 +45,6 @@ mod timestamp;
|
|||||||
mod token;
|
mod token;
|
||||||
mod util;
|
mod util;
|
||||||
pub use document::document;
|
pub use document::document;
|
||||||
pub use document::Document;
|
pub use document::parse;
|
||||||
pub use document::DocumentElement;
|
pub use document::parse_with_settings;
|
||||||
pub use document::Heading;
|
pub use org_source::OrgSource;
|
||||||
pub use document::Section;
|
|
||||||
pub use element::Element;
|
|
||||||
pub use greater_element::Drawer;
|
|
||||||
pub use greater_element::DynamicBlock;
|
|
||||||
pub use greater_element::FootnoteDefinition;
|
|
||||||
pub use greater_element::GreaterBlock;
|
|
||||||
pub use greater_element::PlainList;
|
|
||||||
pub use greater_element::PlainListItem;
|
|
||||||
pub use greater_element::PropertyDrawer;
|
|
||||||
pub use greater_element::Table;
|
|
||||||
pub use greater_element::TableRow;
|
|
||||||
pub use lesser_element::Clock;
|
|
||||||
pub use lesser_element::Comment;
|
|
||||||
pub use lesser_element::CommentBlock;
|
|
||||||
pub use lesser_element::DiarySexp;
|
|
||||||
pub use lesser_element::ExampleBlock;
|
|
||||||
pub use lesser_element::ExportBlock;
|
|
||||||
pub use lesser_element::FixedWidthArea;
|
|
||||||
pub use lesser_element::HorizontalRule;
|
|
||||||
pub use lesser_element::Keyword;
|
|
||||||
pub use lesser_element::LatexEnvironment;
|
|
||||||
pub use lesser_element::Paragraph;
|
|
||||||
pub use lesser_element::Planning;
|
|
||||||
pub use lesser_element::SrcBlock;
|
|
||||||
pub use lesser_element::TableCell;
|
|
||||||
pub use lesser_element::VerseBlock;
|
|
||||||
pub use object::AngleLink;
|
|
||||||
pub use object::Bold;
|
|
||||||
pub use object::Citation;
|
|
||||||
pub use object::CitationReference;
|
|
||||||
pub use object::Code;
|
|
||||||
pub use object::Entity;
|
|
||||||
pub use object::ExportSnippet;
|
|
||||||
pub use object::FootnoteReference;
|
|
||||||
pub use object::InlineBabelCall;
|
|
||||||
pub use object::InlineSourceBlock;
|
|
||||||
pub use object::Italic;
|
|
||||||
pub use object::LatexFragment;
|
|
||||||
pub use object::LineBreak;
|
|
||||||
pub use object::Object;
|
|
||||||
pub use object::OrgMacro;
|
|
||||||
pub use object::PlainLink;
|
|
||||||
pub use object::PlainText;
|
|
||||||
pub use object::RadioLink;
|
|
||||||
pub use object::RadioTarget;
|
|
||||||
pub use object::RegularLink;
|
|
||||||
pub use object::StatisticsCookie;
|
|
||||||
pub use object::StrikeThrough;
|
|
||||||
pub use object::Subscript;
|
|
||||||
pub use object::Superscript;
|
|
||||||
pub use object::Target;
|
|
||||||
pub use object::Timestamp;
|
|
||||||
pub use object::Underline;
|
|
||||||
pub use object::Verbatim;
|
|
||||||
pub use source::Source;
|
|
||||||
type Context<'r, 's> = &'r parser_context::ContextTree<'r, 's>;
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ use nom::branch::alt;
|
|||||||
use nom::combinator::map;
|
use nom::combinator::map;
|
||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::parser_with_context::parser_with_context;
|
|
||||||
use super::plain_text::plain_text;
|
use super::plain_text::plain_text;
|
||||||
use super::regular_link::regular_link;
|
use super::regular_link::regular_link;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::angle_link::angle_link;
|
use crate::parser::angle_link::angle_link;
|
||||||
use crate::parser::citation::citation;
|
use crate::parser::citation::citation;
|
||||||
@@ -16,7 +16,6 @@ use crate::parser::inline_babel_call::inline_babel_call;
|
|||||||
use crate::parser::inline_source_block::inline_source_block;
|
use crate::parser::inline_source_block::inline_source_block;
|
||||||
use crate::parser::latex_fragment::latex_fragment;
|
use crate::parser::latex_fragment::latex_fragment;
|
||||||
use crate::parser::line_break::line_break;
|
use crate::parser::line_break::line_break;
|
||||||
use crate::parser::object::Object;
|
|
||||||
use crate::parser::org_macro::org_macro;
|
use crate::parser::org_macro::org_macro;
|
||||||
use crate::parser::plain_link::plain_link;
|
use crate::parser::plain_link::plain_link;
|
||||||
use crate::parser::radio_link::radio_link;
|
use crate::parser::radio_link::radio_link;
|
||||||
@@ -27,10 +26,11 @@ use crate::parser::subscript_and_superscript::superscript;
|
|||||||
use crate::parser::target::target;
|
use crate::parser::target::target;
|
||||||
use crate::parser::text_markup::text_markup;
|
use crate::parser::text_markup::text_markup;
|
||||||
use crate::parser::timestamp::timestamp;
|
use crate::parser::timestamp::timestamp;
|
||||||
|
use crate::types::Object;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn standard_set_object<'r, 's>(
|
pub fn standard_set_object<'b, 'g, 'r, 's>(
|
||||||
context: Context<'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 (remaining, object) = alt((
|
let (remaining, object) = alt((
|
||||||
@@ -87,8 +87,8 @@ pub fn standard_set_object<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn minimal_set_object<'r, 's>(
|
pub fn minimal_set_object<'b, 'g, 'r, 's>(
|
||||||
context: Context<'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 (remaining, object) = alt((
|
let (remaining, object) = alt((
|
||||||
@@ -109,8 +109,8 @@ pub fn minimal_set_object<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn any_object_except_plain_text<'r, 's>(
|
pub fn any_object_except_plain_text<'b, 'g, 'r, 's>(
|
||||||
context: Context<'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 (remaining, object) = alt((
|
let (remaining, object) = alt((
|
||||||
@@ -166,8 +166,8 @@ pub fn any_object_except_plain_text<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn regular_link_description_object_set<'r, 's>(
|
pub fn regular_link_description_object_set<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Object<'s>> {
|
) -> Res<OrgSource<'s>, Object<'s>> {
|
||||||
// TODO: It can also contain another link, but only when it is a plain or angle link. It can contain square brackets, but not ]]
|
// TODO: It can also contain another link, but only when it is a plain or angle link. It can contain square brackets, but not ]]
|
||||||
@@ -195,8 +195,8 @@ pub fn regular_link_description_object_set<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn table_cell_set_object<'r, 's>(
|
pub fn table_cell_set_object<'b, 'g, 'r, 's>(
|
||||||
context: Context<'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 (remaining, object) = alt((
|
let (remaining, object) = alt((
|
||||||
|
|||||||
@@ -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,23 +8,26 @@ 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::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::RefContext;
|
||||||
|
use crate::error::CustomError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::object::OrgMacro;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::types::OrgMacro;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn org_macro<'r, 's>(
|
pub fn org_macro<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgMacro<'s>> {
|
) -> Res<OrgSource<'s>, OrgMacro<'s>> {
|
||||||
let (remaining, _) = tag("{{{")(input)?;
|
let (remaining, _) = tag("{{{")(input)?;
|
||||||
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((
|
||||||
@@ -43,8 +45,8 @@ pub fn org_macro<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn org_macro_name<'r, 's>(
|
fn org_macro_name<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _) = verify(anychar, |c| c.is_alphabetic())(input)?;
|
let (remaining, _) = verify(anychar, |c| c.is_alphabetic())(input)?;
|
||||||
@@ -56,8 +58,8 @@ fn org_macro_name<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn org_macro_args<'r, 's>(
|
fn org_macro_args<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Vec<OrgSource<'s>>> {
|
) -> Res<OrgSource<'s>, Vec<OrgSource<'s>>> {
|
||||||
let (remaining, _) = tag("(")(input)?;
|
let (remaining, _) = tag("(")(input)?;
|
||||||
@@ -69,8 +71,8 @@ fn org_macro_args<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn org_macro_arg<'r, 's>(
|
fn org_macro_arg<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let mut remaining = input;
|
let mut remaining = input;
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub struct OrgSource<'s> {
|
|||||||
|
|
||||||
impl<'s> std::fmt::Debug for OrgSource<'s> {
|
impl<'s> std::fmt::Debug for OrgSource<'s> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_tuple("OrgSource")
|
f.debug_tuple("Org")
|
||||||
.field(&Into::<&str>::into(self))
|
.field(&Into::<&str>::into(self))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
@@ -318,6 +318,7 @@ impl<'s> From<CustomError<OrgSource<'s>>> for CustomError<&'s str> {
|
|||||||
match value {
|
match value {
|
||||||
CustomError::MyError(err) => CustomError::MyError(err.into()),
|
CustomError::MyError(err) => CustomError::MyError(err.into()),
|
||||||
CustomError::Nom(input, error_kind) => CustomError::Nom(input.into(), error_kind),
|
CustomError::Nom(input, error_kind) => CustomError::Nom(input.into(), error_kind),
|
||||||
|
CustomError::IO(err) => CustomError::IO(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,30 +7,30 @@ use nom::multi::many_till;
|
|||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use super::element_parser::detect_element;
|
use super::element_parser::detect_element;
|
||||||
use super::lesser_element::Paragraph;
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::util::blank_line;
|
use super::util::blank_line;
|
||||||
use super::util::get_consumed;
|
use super::util::get_consumed;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::object_parser::standard_set_object;
|
use crate::parser::object_parser::standard_set_object;
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::util::exit_matcher_parser;
|
use crate::parser::util::exit_matcher_parser;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
|
use crate::types::Paragraph;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn paragraph<'r, 's>(
|
pub fn paragraph<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Paragraph<'s>> {
|
) -> Res<OrgSource<'s>, Paragraph<'s>> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: ¶graph_end,
|
||||||
exit_matcher: ¶graph_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let standard_set_object_matcher = parser_with_context!(standard_set_object)(&parser_context);
|
let standard_set_object_matcher = parser_with_context!(standard_set_object)(&parser_context);
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
|
|
||||||
@@ -53,8 +53,8 @@ pub fn paragraph<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn paragraph_end<'r, 's>(
|
fn paragraph_end<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let non_paragraph_element_matcher = parser_with_context!(detect_element(false))(context);
|
let non_paragraph_element_matcher = parser_with_context!(detect_element(false))(context);
|
||||||
@@ -67,16 +67,21 @@ fn paragraph_end<'r, 's>(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::Context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::GlobalSettings;
|
||||||
|
use crate::context::List;
|
||||||
use crate::parser::element_parser::element;
|
use crate::parser::element_parser::element;
|
||||||
use crate::parser::org_source::OrgSource;
|
use crate::parser::org_source::OrgSource;
|
||||||
use crate::parser::parser_context::ContextTree;
|
use crate::types::Source;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::source::Source;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn two_paragraphs() {
|
fn two_paragraphs() {
|
||||||
let input = OrgSource::new("foo bar baz\n\nlorem ipsum");
|
let input = OrgSource::new("foo bar baz\n\nlorem ipsum");
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let paragraph_matcher = parser_with_context!(element(true))(&initial_context);
|
let paragraph_matcher = parser_with_context!(element(true))(&initial_context);
|
||||||
let (remaining, first_paragraph) = paragraph_matcher(input).expect("Parse first paragraph");
|
let (remaining, first_paragraph) = paragraph_matcher(input).expect("Parse first paragraph");
|
||||||
let (remaining, second_paragraph) =
|
let (remaining, second_paragraph) =
|
||||||
|
|||||||
@@ -1,139 +0,0 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use nom::combinator::eof;
|
|
||||||
use nom::IResult;
|
|
||||||
|
|
||||||
use super::list::List;
|
|
||||||
use super::list::Node;
|
|
||||||
use super::org_source::OrgSource;
|
|
||||||
use super::Context;
|
|
||||||
use super::Object;
|
|
||||||
use crate::error::CustomError;
|
|
||||||
use crate::error::MyError;
|
|
||||||
use crate::error::Res;
|
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
|
|
||||||
type Matcher =
|
|
||||||
dyn for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>>;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ContextTree<'r, 's> {
|
|
||||||
tree: List<ContextElement<'r, 's>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'r, 's> ContextTree<'r, 's> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
ContextTree { tree: List::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn branch_from(trunk: &Rc<Node<ContextElement<'r, 's>>>) -> Self {
|
|
||||||
ContextTree {
|
|
||||||
tree: List::branch_from(trunk),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn ptr_eq<'x, 'y>(&self, other: &ContextTree<'x, 'y>) -> bool {
|
|
||||||
self.tree.ptr_eq(&other.tree)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_additional_node(&self, data: ContextElement<'r, 's>) -> ContextTree<'r, 's> {
|
|
||||||
let new_list = self.tree.push_front(data);
|
|
||||||
ContextTree { tree: new_list }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &Rc<Node<ContextElement<'r, 's>>>> {
|
|
||||||
self.tree.iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
||||||
pub fn check_exit_matcher(
|
|
||||||
&'r self,
|
|
||||||
i: OrgSource<'s>,
|
|
||||||
) -> IResult<OrgSource<'s>, OrgSource<'s>, CustomError<OrgSource<'s>>> {
|
|
||||||
// Special check for EOF. We don't just make this a document-level exit matcher since the IgnoreParent ChainBehavior could cause early exit matchers to not run.
|
|
||||||
let at_end_of_file = eof(i);
|
|
||||||
if at_end_of_file.is_ok() {
|
|
||||||
return at_end_of_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
// let blocked_context =
|
|
||||||
// self.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
|
||||||
// exit_matcher: ChainBehavior::IgnoreParent(Some(&always_fail)),
|
|
||||||
// }));
|
|
||||||
|
|
||||||
let mut current_class_filter = ExitClass::Gamma;
|
|
||||||
for current_node in self.iter() {
|
|
||||||
let context_element = current_node.get_data();
|
|
||||||
match context_element {
|
|
||||||
ContextElement::ExitMatcherNode(exit_matcher) => {
|
|
||||||
if exit_matcher.class as u32 <= current_class_filter as u32 {
|
|
||||||
current_class_filter = exit_matcher.class;
|
|
||||||
let local_context = ContextTree::branch_from(current_node);
|
|
||||||
let local_result = (exit_matcher.exit_matcher)(&local_context, i);
|
|
||||||
if local_result.is_ok() {
|
|
||||||
return local_result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// TODO: Make this a specific error instead of just a generic MyError
|
|
||||||
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
|
||||||
"NoExit".into(),
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicates if elements should consume the whitespace after them.
|
|
||||||
///
|
|
||||||
/// Defaults to true.
|
|
||||||
pub fn should_consume_trailing_whitespace(&self) -> bool {
|
|
||||||
self._should_consume_trailing_whitespace().unwrap_or(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _should_consume_trailing_whitespace(&self) -> Option<bool> {
|
|
||||||
for current_node in self.iter() {
|
|
||||||
let context_element = current_node.get_data();
|
|
||||||
match context_element {
|
|
||||||
ContextElement::ConsumeTrailingWhitespace(should) => {
|
|
||||||
return Some(*should);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ContextElement<'r, 's> {
|
|
||||||
/// Stores a parser that indicates that children should exit upon matching an exit matcher.
|
|
||||||
ExitMatcherNode(ExitMatcherNode<'r>),
|
|
||||||
|
|
||||||
/// Stores the name of the current element to prevent directly nesting elements of the same type.
|
|
||||||
Context(&'r str),
|
|
||||||
|
|
||||||
/// Indicates if elements should consume the whitespace after them.
|
|
||||||
ConsumeTrailingWhitespace(bool),
|
|
||||||
|
|
||||||
/// The contents of a radio target.
|
|
||||||
///
|
|
||||||
/// If any are found, this will force a 2nd parse through the
|
|
||||||
/// org-mode document since text needs to be re-parsed to look for
|
|
||||||
/// radio links matching the contents of radio targets.
|
|
||||||
RadioTarget(Vec<&'r Vec<Object<'s>>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ExitMatcherNode<'r> {
|
|
||||||
pub exit_matcher: &'r Matcher,
|
|
||||||
pub class: ExitClass,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'r> std::fmt::Debug for ExitMatcherNode<'r> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let mut formatter = f.debug_struct("ExitMatcherNode");
|
|
||||||
formatter.field("class", &self.class.to_string());
|
|
||||||
formatter.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,18 +11,19 @@ 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::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::object::PlainLink;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::WORD_CONSTITUENT_CHARACTERS;
|
use crate::parser::util::WORD_CONSTITUENT_CHARACTERS;
|
||||||
|
use crate::types::PlainLink;
|
||||||
|
|
||||||
// TODO: Make this a user-provided variable corresponding to elisp's org-link-parameters
|
// TODO: Make this a user-provided variable corresponding to elisp's org-link-parameters
|
||||||
const ORG_LINK_PARAMETERS: [&'static str; 23] = [
|
const ORG_LINK_PARAMETERS: [&'static str; 23] = [
|
||||||
@@ -52,8 +53,8 @@ const ORG_LINK_PARAMETERS: [&'static str; 23] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn plain_link<'r, 's>(
|
pub fn plain_link<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, PlainLink<'s>> {
|
) -> Res<OrgSource<'s>, PlainLink<'s>> {
|
||||||
let (remaining, _) = pre(context, input)?;
|
let (remaining, _) = pre(context, input)?;
|
||||||
@@ -61,6 +62,8 @@ pub fn plain_link<'r, 's>(
|
|||||||
let (remaining, _separator) = tag(":")(remaining)?;
|
let (remaining, _separator) = tag(":")(remaining)?;
|
||||||
let (remaining, path) = path_plain(context, remaining)?;
|
let (remaining, path) = path_plain(context, remaining)?;
|
||||||
peek(parser_with_context!(post)(context))(remaining)?;
|
peek(parser_with_context!(post)(context))(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,
|
||||||
@@ -73,7 +76,10 @@ pub fn plain_link<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn pre<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
fn pre<'b, 'g, 'r, 's>(
|
||||||
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, ()> {
|
||||||
let preceding_character = input.get_preceding_character();
|
let preceding_character = input.get_preceding_character();
|
||||||
match preceding_character {
|
match preceding_character {
|
||||||
// If None, we are at the start of the file which is fine
|
// If None, we are at the start of the file which is fine
|
||||||
@@ -90,14 +96,17 @@ fn pre<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn post<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
fn post<'b, 'g, 'r, 's>(
|
||||||
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, ()> {
|
||||||
let (remaining, _) = alt((eof, recognize(none_of(WORD_CONSTITUENT_CHARACTERS))))(input)?;
|
let (remaining, _) = alt((eof, recognize(none_of(WORD_CONSTITUENT_CHARACTERS))))(input)?;
|
||||||
Ok((remaining, ()))
|
Ok((remaining, ()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn protocol<'r, 's>(
|
pub fn protocol<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
// TODO: This should be defined by org-link-parameters
|
// TODO: This should be defined by org-link-parameters
|
||||||
@@ -117,16 +126,16 @@ pub fn protocol<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn path_plain<'r, 's>(
|
fn path_plain<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
// TODO: "optionally containing parenthesis-wrapped non-whitespace non-bracket substrings up to a depth of two. The string must end with either a non-punctation non-whitespace character, a forwards slash, or a parenthesis-wrapped substring"
|
// TODO: "optionally containing parenthesis-wrapped non-whitespace non-bracket substrings up to a depth of two. The string must end with either a non-punctation non-whitespace character, a forwards slash, or a parenthesis-wrapped substring"
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &path_plain_end,
|
||||||
exit_matcher: &path_plain_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
|
|
||||||
@@ -139,8 +148,8 @@ fn path_plain<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn path_plain_end<'r, 's>(
|
fn path_plain_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(many_till(
|
recognize(many_till(
|
||||||
|
|||||||
@@ -16,32 +16,30 @@ use nom::multi::many1;
|
|||||||
use nom::multi::many_till;
|
use nom::multi::many_till;
|
||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use super::greater_element::PlainList;
|
use super::element_parser::element;
|
||||||
use super::greater_element::PlainListItem;
|
|
||||||
use super::object_parser::standard_set_object;
|
use super::object_parser::standard_set_object;
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::parser_with_context::parser_with_context;
|
|
||||||
use super::util::non_whitespace_character;
|
use super::util::non_whitespace_character;
|
||||||
use super::Context;
|
use crate::context::parser_with_context;
|
||||||
use super::Object;
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::element_parser::element;
|
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
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::maybe_consume_trailing_whitespace_if_not_exiting;
|
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;
|
||||||
|
use crate::types::Object;
|
||||||
|
use crate::types::PlainList;
|
||||||
|
use crate::types::PlainListItem;
|
||||||
|
|
||||||
#[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,
|
||||||
@@ -63,16 +61,22 @@ pub fn detect_plain_list<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn plain_list<'r, 's>(
|
pub fn plain_list<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, PlainList<'s>> {
|
) -> Res<OrgSource<'s>, PlainList<'s>> {
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::Context("plain list"))
|
ContextElement::Context("plain list"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Beta,
|
class: ExitClass::Beta,
|
||||||
exit_matcher: &plain_list_end,
|
exit_matcher: &plain_list_end,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
// children stores tuple of (input string, parsed object) so we can re-parse the final item
|
// children stores tuple of (input string, parsed object) so we can re-parse the final item
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
let mut first_item_indentation: Option<usize> = None;
|
let mut first_item_indentation: Option<usize> = None;
|
||||||
@@ -114,8 +118,8 @@ pub fn plain_list<'r, 's>(
|
|||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let final_item_context =
|
let final_item_context = ContextElement::ConsumeTrailingWhitespace(false);
|
||||||
parser_context.with_additional_node(ContextElement::ConsumeTrailingWhitespace(false));
|
let final_item_context = parser_context.with_additional_node(&final_item_context);
|
||||||
let (remaining, reparsed_final_item) =
|
let (remaining, reparsed_final_item) =
|
||||||
parser_with_context!(plain_list_item)(&final_item_context)(final_child_start)?;
|
parser_with_context!(plain_list_item)(&final_item_context)(final_child_start)?;
|
||||||
children.push((final_child_start, reparsed_final_item));
|
children.push((final_child_start, reparsed_final_item));
|
||||||
@@ -131,8 +135,8 @@ pub fn plain_list<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn plain_list_item<'r, 's>(
|
pub fn plain_list_item<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, PlainListItem<'s>> {
|
) -> Res<OrgSource<'s>, PlainListItem<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
@@ -143,46 +147,62 @@ 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 contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Beta,
|
class: ExitClass::Beta,
|
||||||
exit_matcher: &exit_matcher,
|
exit_matcher: &exit_matcher,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
|
||||||
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 = ContextElement::ConsumeTrailingWhitespace(false);
|
||||||
|
let final_item_context = parser_context.with_additional_node(&final_item_context);
|
||||||
|
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 +216,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((
|
||||||
@@ -217,8 +249,8 @@ fn counter<'s>(i: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn plain_list_end<'r, 's>(
|
fn plain_list_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(tuple((
|
recognize(tuple((
|
||||||
@@ -229,11 +261,9 @@ fn plain_list_end<'r, 's>(
|
|||||||
)))(input)
|
)))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn plain_list_item_end(
|
const fn plain_list_item_end(indent_level: usize) -> impl ContextMatcher {
|
||||||
indent_level: usize,
|
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
let line_indented_lte_matcher = line_indented_lte(indent_level);
|
let line_indented_lte_matcher = line_indented_lte(indent_level);
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
move |context, input: OrgSource<'_>| {
|
||||||
_plain_list_item_end(context, input, &line_indented_lte_matcher)
|
_plain_list_item_end(context, input, &line_indented_lte_matcher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,13 +272,10 @@ const fn plain_list_item_end(
|
|||||||
feature = "tracing",
|
feature = "tracing",
|
||||||
tracing::instrument(ret, level = "debug", skip(line_indented_lte_matcher))
|
tracing::instrument(ret, level = "debug", skip(line_indented_lte_matcher))
|
||||||
)]
|
)]
|
||||||
fn _plain_list_item_end<'r, 's>(
|
fn _plain_list_item_end<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
line_indented_lte_matcher: impl for<'rr, 'ss> Fn(
|
line_indented_lte_matcher: impl ContextMatcher,
|
||||||
Context<'rr, 'ss>,
|
|
||||||
OrgSource<'ss>,
|
|
||||||
) -> Res<OrgSource<'ss>, OrgSource<'ss>>,
|
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
recognize(tuple((
|
recognize(tuple((
|
||||||
@@ -257,15 +284,13 @@ fn _plain_list_item_end<'r, 's>(
|
|||||||
)))(input)
|
)))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn line_indented_lte(
|
const fn line_indented_lte(indent_level: usize) -> impl ContextMatcher {
|
||||||
indent_level: usize,
|
move |context, input: OrgSource<'_>| _line_indented_lte(context, input, indent_level)
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| _line_indented_lte(context, input, indent_level)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _line_indented_lte<'r, 's>(
|
fn _line_indented_lte<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
indent_level: usize,
|
indent_level: usize,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
@@ -279,15 +304,15 @@ fn _line_indented_lte<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn item_tag<'r, 's>(
|
fn item_tag<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &item_tag_end,
|
||||||
exit_matcher: &item_tag_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, (children, _exit_contents)) = verify(
|
let (remaining, (children, _exit_contents)) = verify(
|
||||||
many_till(
|
many_till(
|
||||||
// TODO: Should this be using a different set like the minimal set?
|
// TODO: Should this be using a different set like the minimal set?
|
||||||
@@ -300,8 +325,8 @@ fn item_tag<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn item_tag_end<'r, 's>(
|
fn item_tag_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(alt((
|
recognize(alt((
|
||||||
@@ -312,8 +337,8 @@ fn item_tag_end<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn item_tag_post_gap<'r, 's>(
|
fn item_tag_post_gap<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
verify(
|
verify(
|
||||||
@@ -335,14 +360,17 @@ fn item_tag_post_gap<'r, 's>(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::parser::parser_context::ContextTree;
|
use crate::context::Context;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
use crate::context::GlobalSettings;
|
||||||
use crate::parser::Source;
|
use crate::context::List;
|
||||||
|
use crate::types::Source;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn plain_list_item_empty() {
|
fn plain_list_item_empty() {
|
||||||
let input = OrgSource::new("1.");
|
let input = OrgSource::new("1.");
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let plain_list_item_matcher = parser_with_context!(plain_list_item)(&initial_context);
|
let plain_list_item_matcher = parser_with_context!(plain_list_item)(&initial_context);
|
||||||
let (remaining, result) = plain_list_item_matcher(input).unwrap();
|
let (remaining, result) = plain_list_item_matcher(input).unwrap();
|
||||||
assert_eq!(Into::<&str>::into(remaining), "");
|
assert_eq!(Into::<&str>::into(remaining), "");
|
||||||
@@ -352,7 +380,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn plain_list_item_simple() {
|
fn plain_list_item_simple() {
|
||||||
let input = OrgSource::new("1. foo");
|
let input = OrgSource::new("1. foo");
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let plain_list_item_matcher = parser_with_context!(plain_list_item)(&initial_context);
|
let plain_list_item_matcher = parser_with_context!(plain_list_item)(&initial_context);
|
||||||
let (remaining, result) = plain_list_item_matcher(input).unwrap();
|
let (remaining, result) = plain_list_item_matcher(input).unwrap();
|
||||||
assert_eq!(Into::<&str>::into(remaining), "");
|
assert_eq!(Into::<&str>::into(remaining), "");
|
||||||
@@ -362,7 +392,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn plain_list_empty() {
|
fn plain_list_empty() {
|
||||||
let input = OrgSource::new("1.");
|
let input = OrgSource::new("1.");
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
|
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
|
||||||
let (remaining, result) = plain_list_matcher(input).unwrap();
|
let (remaining, result) = plain_list_matcher(input).unwrap();
|
||||||
assert_eq!(Into::<&str>::into(remaining), "");
|
assert_eq!(Into::<&str>::into(remaining), "");
|
||||||
@@ -372,7 +404,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn plain_list_simple() {
|
fn plain_list_simple() {
|
||||||
let input = OrgSource::new("1. foo");
|
let input = OrgSource::new("1. foo");
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
|
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
|
||||||
let (remaining, result) = plain_list_matcher(input).unwrap();
|
let (remaining, result) = plain_list_matcher(input).unwrap();
|
||||||
assert_eq!(Into::<&str>::into(remaining), "");
|
assert_eq!(Into::<&str>::into(remaining), "");
|
||||||
@@ -383,7 +417,9 @@ mod tests {
|
|||||||
fn plain_list_cant_start_line_with_asterisk() {
|
fn plain_list_cant_start_line_with_asterisk() {
|
||||||
// Plain lists with an asterisk bullet must be indented or else they would be a headline
|
// Plain lists with an asterisk bullet must be indented or else they would be a headline
|
||||||
let input = OrgSource::new("* foo");
|
let input = OrgSource::new("* foo");
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
|
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
|
||||||
let result = plain_list_matcher(input);
|
let result = plain_list_matcher(input);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@@ -393,7 +429,9 @@ mod tests {
|
|||||||
fn indented_can_start_line_with_asterisk() {
|
fn indented_can_start_line_with_asterisk() {
|
||||||
// Plain lists with an asterisk bullet must be indented or else they would be a headline
|
// Plain lists with an asterisk bullet must be indented or else they would be a headline
|
||||||
let input = OrgSource::new(" * foo");
|
let input = OrgSource::new(" * foo");
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
|
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
|
||||||
let result = plain_list_matcher(input);
|
let result = plain_list_matcher(input);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
@@ -411,7 +449,9 @@ mod tests {
|
|||||||
ipsum
|
ipsum
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let plain_list_matcher = parser_with_context!(element(true))(&initial_context);
|
let plain_list_matcher = parser_with_context!(element(true))(&initial_context);
|
||||||
let (remaining, result) =
|
let (remaining, result) =
|
||||||
plain_list_matcher(input).expect("Should parse the plain list successfully.");
|
plain_list_matcher(input).expect("Should parse the plain list successfully.");
|
||||||
@@ -437,7 +477,9 @@ mod tests {
|
|||||||
|
|
||||||
baz"#,
|
baz"#,
|
||||||
);
|
);
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let plain_list_matcher = parser_with_context!(element(true))(&initial_context);
|
let plain_list_matcher = parser_with_context!(element(true))(&initial_context);
|
||||||
let (remaining, result) =
|
let (remaining, result) =
|
||||||
plain_list_matcher(input).expect("Should parse the plain list successfully.");
|
plain_list_matcher(input).expect("Should parse the plain list successfully.");
|
||||||
@@ -468,7 +510,9 @@ baz"#,
|
|||||||
|
|
||||||
dolar"#,
|
dolar"#,
|
||||||
);
|
);
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let plain_list_matcher = parser_with_context!(element(true))(&initial_context);
|
let plain_list_matcher = parser_with_context!(element(true))(&initial_context);
|
||||||
let (remaining, result) =
|
let (remaining, result) =
|
||||||
plain_list_matcher(input).expect("Should parse the plain list successfully.");
|
plain_list_matcher(input).expect("Should parse the plain list successfully.");
|
||||||
@@ -496,24 +540,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 +562,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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,19 +7,19 @@ use nom::combinator::recognize;
|
|||||||
use nom::combinator::verify;
|
use nom::combinator::verify;
|
||||||
use nom::multi::many_till;
|
use nom::multi::many_till;
|
||||||
|
|
||||||
use super::object::PlainText;
|
use super::object_parser::any_object_except_plain_text;
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::radio_link::RematchObject;
|
use super::radio_link::RematchObject;
|
||||||
use super::Context;
|
use super::util::exit_matcher_parser;
|
||||||
use super::Object;
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::object_parser::any_object_except_plain_text;
|
use crate::types::Object;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
use crate::types::PlainText;
|
||||||
use crate::parser::util::exit_matcher_parser;
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn plain_text<'r, 's>(
|
pub fn plain_text<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, PlainText<'s>> {
|
) -> Res<OrgSource<'s>, PlainText<'s>> {
|
||||||
let (remaining, source) = recognize(verify(
|
let (remaining, source) = recognize(verify(
|
||||||
@@ -42,8 +42,8 @@ pub fn plain_text<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn plain_text_end<'r, 's>(
|
fn plain_text_end<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(parser_with_context!(any_object_except_plain_text)(context))(input)
|
recognize(parser_with_context!(any_object_except_plain_text)(context))(input)
|
||||||
@@ -51,9 +51,9 @@ fn plain_text_end<'r, 's>(
|
|||||||
|
|
||||||
impl<'x> RematchObject<'x> for PlainText<'x> {
|
impl<'x> RematchObject<'x> for PlainText<'x> {
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn rematch_object<'r, 's>(
|
fn rematch_object<'b, 'g, 'r, 's>(
|
||||||
&'x self,
|
&'x self,
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Object<'s>> {
|
) -> Res<OrgSource<'s>, Object<'s>> {
|
||||||
map(tag(self.source), |s| {
|
map(tag(self.source), |s| {
|
||||||
@@ -69,14 +69,18 @@ mod tests {
|
|||||||
use nom::combinator::map;
|
use nom::combinator::map;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::parser::parser_context::ContextTree;
|
use crate::context::Context;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
use crate::context::ContextElement;
|
||||||
use crate::parser::source::Source;
|
use crate::context::GlobalSettings;
|
||||||
|
use crate::context::List;
|
||||||
|
use crate::types::Source;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn plain_text_simple() {
|
fn plain_text_simple() {
|
||||||
let input = OrgSource::new("foobarbaz");
|
let input = OrgSource::new("foobarbaz");
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = GlobalSettings::default();
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
let plain_text_matcher = parser_with_context!(plain_text)(&initial_context);
|
let plain_text_matcher = parser_with_context!(plain_text)(&initial_context);
|
||||||
let (remaining, result) = map(plain_text_matcher, Object::PlainText)(input).unwrap();
|
let (remaining, result) = map(plain_text_matcher, Object::PlainText)(input).unwrap();
|
||||||
assert_eq!(Into::<&str>::into(remaining), "");
|
assert_eq!(Into::<&str>::into(remaining), "");
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ use nom::multi::separated_list1;
|
|||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::Context;
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::lesser_element::Planning;
|
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
|
use crate::types::Planning;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn planning<'r, 's>(
|
pub fn planning<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Planning<'s>> {
|
) -> Res<OrgSource<'s>, Planning<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
|
|||||||
@@ -14,25 +14,25 @@ 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::Context;
|
use super::util::exit_matcher_parser;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::greater_element::NodeProperty;
|
|
||||||
use crate::parser::greater_element::PropertyDrawer;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
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::immediate_in_section;
|
||||||
use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting;
|
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;
|
||||||
|
use crate::types::NodeProperty;
|
||||||
|
use crate::types::PropertyDrawer;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn property_drawer<'r, 's>(
|
pub fn property_drawer<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, PropertyDrawer<'s>> {
|
) -> Res<OrgSource<'s>, PropertyDrawer<'s>> {
|
||||||
if immediate_in_section(context, "property-drawer") {
|
if immediate_in_section(context, "property-drawer") {
|
||||||
@@ -51,13 +51,17 @@ pub fn property_drawer<'r, 's>(
|
|||||||
line_ending,
|
line_ending,
|
||||||
))(input)?;
|
))(input)?;
|
||||||
|
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("property-drawer"))
|
ContextElement::Context("property-drawer"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Alpha,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &property_drawer_end,
|
exit_matcher: &property_drawer_end,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
|
|
||||||
let node_property_matcher = parser_with_context!(node_property)(&parser_context);
|
let node_property_matcher = parser_with_context!(node_property)(&parser_context);
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
@@ -79,8 +83,8 @@ pub fn property_drawer<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn property_drawer_end<'r, 's>(
|
fn property_drawer_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(tuple((
|
recognize(tuple((
|
||||||
@@ -93,8 +97,8 @@ fn property_drawer_end<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn node_property<'r, 's>(
|
fn node_property<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, NodeProperty<'s>> {
|
) -> Res<OrgSource<'s>, NodeProperty<'s>> {
|
||||||
let (remaining, (_start_of_line, _leading_whitespace, _open_colon, _name, _close_colon)) =
|
let (remaining, (_start_of_line, _leading_whitespace, _open_colon, _name, _close_colon)) =
|
||||||
@@ -136,15 +140,15 @@ fn node_property<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn node_property_name<'r, 's>(
|
fn node_property_name<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Beta,
|
||||||
class: ExitClass::Beta,
|
exit_matcher: &node_property_name_end,
|
||||||
exit_matcher: &node_property_name_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, name) = recognize(tuple((
|
let (remaining, name) = recognize(tuple((
|
||||||
verify(
|
verify(
|
||||||
@@ -161,8 +165,8 @@ fn node_property_name<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn node_property_name_end<'r, 's>(
|
fn node_property_name_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
alt((tag("+:"), tag(":")))(input)
|
alt((tag("+:"), tag(":")))(input)
|
||||||
|
|||||||
@@ -5,35 +5,29 @@ 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::object_parser::minimal_set_object;
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::Context;
|
use super::util::exit_matcher_parser;
|
||||||
use super::Object;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::object_parser::minimal_set_object;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::util::exit_matcher_parser;
|
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
use crate::parser::RadioLink;
|
use crate::types::Object;
|
||||||
use crate::parser::RadioTarget;
|
use crate::types::RadioLink;
|
||||||
|
use crate::types::RadioTarget;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn radio_link<'r, 's>(
|
pub fn radio_link<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, RadioLink<'s>> {
|
) -> Res<OrgSource<'s>, RadioLink<'s>> {
|
||||||
let radio_targets = context
|
for radio_target in &context.get_global_settings().radio_targets {
|
||||||
.iter()
|
|
||||||
.filter_map(|context_element| match context_element.get_data() {
|
|
||||||
ContextElement::RadioTarget(targets) => Some(targets),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.flatten();
|
|
||||||
for radio_target in radio_targets {
|
|
||||||
let rematched_target = rematch_target(context, radio_target, input);
|
let rematched_target = rematch_target(context, radio_target, input);
|
||||||
if let Ok((remaining, rematched_target)) = rematched_target {
|
if let Ok((remaining, rematched_target)) = rematched_target {
|
||||||
let (remaining, _) = space0(remaining)?;
|
let (remaining, _) = space0(remaining)?;
|
||||||
@@ -53,8 +47,8 @@ pub fn radio_link<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn rematch_target<'x, 'r, 's>(
|
pub fn rematch_target<'x, 'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
target: &'x Vec<Object<'x>>,
|
target: &'x Vec<Object<'x>>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||||
@@ -84,16 +78,16 @@ pub fn rematch_target<'x, 'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn radio_target<'r, 's>(
|
pub fn radio_target<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, RadioTarget<'s>> {
|
) -> Res<OrgSource<'s>, RadioTarget<'s>> {
|
||||||
let (remaining, _opening) = tag("<<<")(input)?;
|
let (remaining, _opening) = tag("<<<")(input)?;
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &radio_target_end,
|
||||||
exit_matcher: &radio_target_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, (children, _exit_contents)) = verify(
|
let (remaining, (children, _exit_contents)) = verify(
|
||||||
many_till(
|
many_till(
|
||||||
@@ -104,7 +98,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,
|
||||||
@@ -116,17 +111,17 @@ pub fn radio_target<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn radio_target_end<'r, 's>(
|
fn radio_target_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
alt((tag("<"), tag(">"), line_ending))(input)
|
alt((tag("<"), tag(">"), line_ending))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RematchObject<'x> {
|
pub trait RematchObject<'x> {
|
||||||
fn rematch_object<'r, 's>(
|
fn rematch_object<'b, 'g, 'r, 's>(
|
||||||
&'x self,
|
&'x self,
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Object<'s>>;
|
) -> Res<OrgSource<'s>, Object<'s>>;
|
||||||
}
|
}
|
||||||
@@ -134,25 +129,30 @@ pub trait RematchObject<'x> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::context::Context;
|
||||||
|
use crate::context::GlobalSettings;
|
||||||
|
use crate::context::List;
|
||||||
use crate::parser::element_parser::element;
|
use crate::parser::element_parser::element;
|
||||||
use crate::parser::parser_context::ContextElement;
|
use crate::types::Bold;
|
||||||
use crate::parser::parser_context::ContextTree;
|
use crate::types::Element;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
use crate::types::PlainText;
|
||||||
use crate::parser::source::Source;
|
use crate::types::Source;
|
||||||
use crate::parser::Bold;
|
|
||||||
use crate::parser::PlainText;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn plain_text_radio_target() {
|
fn plain_text_radio_target() {
|
||||||
let input = OrgSource::new("foo bar baz");
|
let input = OrgSource::new("foo bar baz");
|
||||||
let radio_target_match = vec![Object::PlainText(PlainText { source: "bar" })];
|
let radio_target_match = vec![Object::PlainText(PlainText { source: "bar" })];
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = {
|
||||||
let document_context = initial_context
|
let mut global_settings = GlobalSettings::default();
|
||||||
.with_additional_node(ContextElement::RadioTarget(vec![&radio_target_match]));
|
global_settings.radio_targets = vec![&radio_target_match];
|
||||||
let paragraph_matcher = parser_with_context!(element(true))(&document_context);
|
global_settings
|
||||||
|
};
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
|
let paragraph_matcher = parser_with_context!(element(true))(&initial_context);
|
||||||
let (remaining, first_paragraph) = paragraph_matcher(input).expect("Parse first paragraph");
|
let (remaining, first_paragraph) = paragraph_matcher(input).expect("Parse first paragraph");
|
||||||
let first_paragraph = match first_paragraph {
|
let first_paragraph = match first_paragraph {
|
||||||
crate::parser::Element::Paragraph(paragraph) => paragraph,
|
Element::Paragraph(paragraph) => paragraph,
|
||||||
_ => panic!("Should be a paragraph!"),
|
_ => panic!("Should be a paragraph!"),
|
||||||
};
|
};
|
||||||
assert_eq!(Into::<&str>::into(remaining), "");
|
assert_eq!(Into::<&str>::into(remaining), "");
|
||||||
@@ -177,14 +177,18 @@ mod tests {
|
|||||||
source: "*bar*",
|
source: "*bar*",
|
||||||
children: vec![Object::PlainText(PlainText { source: "bar" })],
|
children: vec![Object::PlainText(PlainText { source: "bar" })],
|
||||||
})];
|
})];
|
||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let global_settings = {
|
||||||
let document_context = initial_context
|
let mut global_settings = GlobalSettings::default();
|
||||||
.with_additional_node(ContextElement::RadioTarget(vec![&radio_target_match]));
|
global_settings.radio_targets = vec![&radio_target_match];
|
||||||
let paragraph_matcher = parser_with_context!(element(true))(&document_context);
|
global_settings
|
||||||
|
};
|
||||||
|
let initial_context = ContextElement::document_context();
|
||||||
|
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||||
|
let paragraph_matcher = parser_with_context!(element(true))(&initial_context);
|
||||||
let (remaining, first_paragraph) =
|
let (remaining, first_paragraph) =
|
||||||
paragraph_matcher(input.into()).expect("Parse first paragraph");
|
paragraph_matcher(input.into()).expect("Parse first paragraph");
|
||||||
let first_paragraph = match first_paragraph {
|
let first_paragraph = match first_paragraph {
|
||||||
crate::parser::Element::Paragraph(paragraph) => paragraph,
|
Element::Paragraph(paragraph) => paragraph,
|
||||||
_ => panic!("Should be a paragraph!"),
|
_ => panic!("Should be a paragraph!"),
|
||||||
};
|
};
|
||||||
assert_eq!(Into::<&str>::into(remaining), "");
|
assert_eq!(Into::<&str>::into(remaining), "");
|
||||||
|
|||||||
@@ -3,26 +3,26 @@ 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::object_parser::regular_link_description_object_set;
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::parser_with_context::parser_with_context;
|
use super::util::exit_matcher_parser;
|
||||||
use super::util::get_consumed;
|
use super::util::get_consumed;
|
||||||
use super::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
use super::Object;
|
use crate::context::parser_with_context;
|
||||||
use super::RegularLink;
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
use crate::types::Object;
|
||||||
use crate::parser::object_parser::regular_link_description_object_set;
|
use crate::types::RegularLink;
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::util::exit_matcher_parser;
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn regular_link<'r, 's>(
|
pub fn regular_link<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, RegularLink<'s>> {
|
) -> Res<OrgSource<'s>, RegularLink<'s>> {
|
||||||
alt((
|
alt((
|
||||||
@@ -32,14 +32,15 @@ pub fn regular_link<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn regular_link_without_description<'r, 's>(
|
pub fn regular_link_without_description<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, RegularLink<'s>> {
|
) -> Res<OrgSource<'s>, RegularLink<'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,
|
||||||
@@ -50,8 +51,8 @@ pub fn regular_link_without_description<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn regular_link_with_description<'r, 's>(
|
pub fn regular_link_with_description<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, RegularLink<'s>> {
|
) -> Res<OrgSource<'s>, RegularLink<'s>> {
|
||||||
let (remaining, _opening_bracket) = tag("[[")(input)?;
|
let (remaining, _opening_bracket) = tag("[[")(input)?;
|
||||||
@@ -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,
|
||||||
@@ -70,8 +72,8 @@ pub fn regular_link_with_description<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn pathreg<'r, 's>(
|
pub fn pathreg<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, path) = escaped(
|
let (remaining, path) = escaped(
|
||||||
@@ -86,15 +88,15 @@ pub fn pathreg<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn description<'r, 's>(
|
pub fn description<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Beta,
|
||||||
class: ExitClass::Beta,
|
exit_matcher: &description_end,
|
||||||
exit_matcher: &description_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, (children, _exit_contents)) = verify(
|
let (remaining, (children, _exit_contents)) = verify(
|
||||||
many_till(
|
many_till(
|
||||||
parser_with_context!(regular_link_description_object_set)(&parser_context),
|
parser_with_context!(regular_link_description_object_set)(&parser_context),
|
||||||
@@ -107,8 +109,8 @@ pub fn description<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn description_end<'r, 's>(
|
fn description_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
tag("]]")(input)
|
tag("]]")(input)
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
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::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
use crate::types::StatisticsCookie;
|
||||||
use crate::parser::StatisticsCookie;
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn statistics_cookie<'r, 's>(
|
pub fn statistics_cookie<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, StatisticsCookie<'s>> {
|
) -> Res<OrgSource<'s>, StatisticsCookie<'s>> {
|
||||||
alt((
|
alt((
|
||||||
@@ -22,13 +22,14 @@ 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<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
context: RefContext<'b, 'g, '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 {
|
||||||
@@ -38,8 +39,8 @@ 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<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
context: RefContext<'b, 'g, '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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -11,33 +10,36 @@ use nom::combinator::recognize;
|
|||||||
use nom::combinator::verify;
|
use nom::combinator::verify;
|
||||||
use nom::multi::many_till;
|
use nom::multi::many_till;
|
||||||
|
|
||||||
|
use super::object_parser::standard_set_object;
|
||||||
use super::org_source::BracketDepth;
|
use super::org_source::BracketDepth;
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::Context;
|
use super::util::exit_matcher_parser;
|
||||||
use super::Object;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::object_parser::standard_set_object;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::util::exit_matcher_parser;
|
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
use crate::parser::Subscript;
|
use crate::types::Object;
|
||||||
use crate::parser::Superscript;
|
use crate::types::Subscript;
|
||||||
|
use crate::types::Superscript;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn subscript<'r, 's>(
|
pub fn subscript<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Subscript<'s>> {
|
) -> Res<OrgSource<'s>, Subscript<'s>> {
|
||||||
// We check for the underscore first before checking the pre-character as a minor optimization to avoid walking up the context tree to find the document root unnecessarily.
|
// We check for the underscore first before checking the pre-character as a minor optimization to avoid walking up the context tree to find the document root unnecessarily.
|
||||||
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,
|
||||||
@@ -48,15 +50,16 @@ pub fn subscript<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn superscript<'r, 's>(
|
pub fn superscript<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Superscript<'s>> {
|
) -> Res<OrgSource<'s>, Superscript<'s>> {
|
||||||
// We check for the circumflex first before checking the pre-character as a minor optimization to avoid walking up the context tree to find the document root unnecessarily.
|
// We check for the circumflex first before checking the pre-character as a minor optimization to avoid walking up the context tree to find the document root unnecessarily.
|
||||||
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,
|
||||||
@@ -67,7 +70,10 @@ pub fn superscript<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn pre<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
fn pre<'b, 'g, 'r, 's>(
|
||||||
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, ()> {
|
||||||
let preceding_character = input.get_preceding_character();
|
let preceding_character = input.get_preceding_character();
|
||||||
match preceding_character {
|
match preceding_character {
|
||||||
Some(c) if !c.is_whitespace() => {}
|
Some(c) if !c.is_whitespace() => {}
|
||||||
@@ -87,8 +93,8 @@ enum ScriptBody<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn script_body<'r, 's>(
|
fn script_body<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, ScriptBody<'s>> {
|
) -> Res<OrgSource<'s>, ScriptBody<'s>> {
|
||||||
alt((
|
alt((
|
||||||
@@ -105,16 +111,16 @@ fn script_body<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn script_asterisk<'r, 's>(
|
fn script_asterisk<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
tag("*")(input)
|
tag("*")(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn script_alphanum<'r, 's>(
|
fn script_alphanum<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _sign) = opt(recognize(one_of("+-")))(input)?;
|
let (remaining, _sign) = opt(recognize(one_of("+-")))(input)?;
|
||||||
@@ -127,8 +133,8 @@ fn script_alphanum<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn script_alphanum_character<'r, 's>(
|
fn script_alphanum_character<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(verify(anychar, |c| {
|
recognize(verify(anychar, |c| {
|
||||||
@@ -137,8 +143,8 @@ fn script_alphanum_character<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn end_script_alphanum_character<'r, 's>(
|
fn end_script_alphanum_character<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, final_char) = recognize(verify(anychar, |c| c.is_alphanumeric()))(input)?;
|
let (remaining, final_char) = recognize(verify(anychar, |c| c.is_alphanumeric()))(input)?;
|
||||||
@@ -149,17 +155,17 @@ fn end_script_alphanum_character<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn script_with_braces<'r, 's>(
|
fn script_with_braces<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||||
let (remaining, _) = tag("{")(input)?;
|
let (remaining, _) = tag("{")(input)?;
|
||||||
let exit_with_depth = script_with_braces_end(remaining.get_brace_depth());
|
let exit_with_depth = script_with_braces_end(remaining.get_brace_depth());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &exit_with_depth,
|
||||||
exit_matcher: &exit_with_depth,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, (children, _exit_contents)) = many_till(
|
let (remaining, (children, _exit_contents)) = many_till(
|
||||||
parser_with_context!(standard_set_object)(&parser_context),
|
parser_with_context!(standard_set_object)(&parser_context),
|
||||||
@@ -170,17 +176,15 @@ fn script_with_braces<'r, 's>(
|
|||||||
Ok((remaining, children))
|
Ok((remaining, children))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn script_with_braces_end(
|
fn script_with_braces_end(starting_brace_depth: BracketDepth) -> impl ContextMatcher {
|
||||||
starting_brace_depth: BracketDepth,
|
move |context, input: OrgSource<'_>| {
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
|
||||||
_script_with_braces_end(context, input, starting_brace_depth)
|
_script_with_braces_end(context, input, starting_brace_depth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _script_with_braces_end<'r, 's>(
|
fn _script_with_braces_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
starting_brace_depth: BracketDepth,
|
starting_brace_depth: BracketDepth,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
|
|||||||
@@ -14,37 +14,41 @@ use nom::sequence::tuple;
|
|||||||
|
|
||||||
use super::object_parser::table_cell_set_object;
|
use super::object_parser::table_cell_set_object;
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::Context;
|
use super::util::exit_matcher_parser;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::greater_element::TableRow;
|
|
||||||
use crate::parser::lesser_element::TableCell;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::util::exit_matcher_parser;
|
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
use crate::parser::Table;
|
use crate::types::Table;
|
||||||
|
use crate::types::TableCell;
|
||||||
|
use crate::types::TableRow;
|
||||||
|
|
||||||
/// Parse an org-mode-style table
|
/// Parse an org-mode-style table
|
||||||
///
|
///
|
||||||
/// This is not the table.el style.
|
/// This is not the table.el style.
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn org_mode_table<'r, 's>(
|
pub fn org_mode_table<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Table<'s>> {
|
) -> Res<OrgSource<'s>, Table<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
peek(tuple((space0, tag("|"))))(input)?;
|
peek(tuple((space0, tag("|"))))(input)?;
|
||||||
|
|
||||||
let parser_context = context
|
let contexts = [
|
||||||
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
|
ContextElement::ConsumeTrailingWhitespace(true),
|
||||||
.with_additional_node(ContextElement::Context("table"))
|
ContextElement::Context("table"),
|
||||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
class: ExitClass::Alpha,
|
class: ExitClass::Alpha,
|
||||||
exit_matcher: &table_end,
|
exit_matcher: &table_end,
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
let parser_context = context.with_additional_node(&contexts[0]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||||
|
let parser_context = parser_context.with_additional_node(&contexts[2]);
|
||||||
|
|
||||||
let org_mode_table_row_matcher = parser_with_context!(org_mode_table_row)(&parser_context);
|
let org_mode_table_row_matcher = parser_with_context!(org_mode_table_row)(&parser_context);
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
@@ -65,8 +69,8 @@ pub fn org_mode_table<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn table_end<'r, 's>(
|
fn table_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
@@ -74,8 +78,8 @@ fn table_end<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn org_mode_table_row<'r, 's>(
|
pub fn org_mode_table_row<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, TableRow<'s>> {
|
) -> Res<OrgSource<'s>, TableRow<'s>> {
|
||||||
alt((
|
alt((
|
||||||
@@ -85,8 +89,8 @@ pub fn org_mode_table_row<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn org_mode_table_row_rule<'r, 's>(
|
pub fn org_mode_table_row_rule<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, TableRow<'s>> {
|
) -> Res<OrgSource<'s>, TableRow<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
@@ -102,8 +106,8 @@ pub fn org_mode_table_row_rule<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn org_mode_table_row_regular<'r, 's>(
|
pub fn org_mode_table_row_regular<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, TableRow<'s>> {
|
) -> Res<OrgSource<'s>, TableRow<'s>> {
|
||||||
start_of_line(input)?;
|
start_of_line(input)?;
|
||||||
@@ -122,15 +126,15 @@ pub fn org_mode_table_row_regular<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn org_mode_table_cell<'r, 's>(
|
pub fn org_mode_table_cell<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, TableCell<'s>> {
|
) -> Res<OrgSource<'s>, TableCell<'s>> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Beta,
|
||||||
class: ExitClass::Beta,
|
exit_matcher: &org_mode_table_cell_end,
|
||||||
exit_matcher: &org_mode_table_cell_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let table_cell_set_object_matcher =
|
let table_cell_set_object_matcher =
|
||||||
parser_with_context!(table_cell_set_object)(&parser_context);
|
parser_with_context!(table_cell_set_object)(&parser_context);
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
@@ -155,8 +159,8 @@ pub fn org_mode_table_cell<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn org_mode_table_cell_end<'r, 's>(
|
fn org_mode_table_cell_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(tuple((space0, alt((tag("|"), peek(line_ending))))))(input)
|
recognize(tuple((space0, alt((tag("|"), peek(line_ending))))))(input)
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
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::Context;
|
use super::util::exit_matcher_parser;
|
||||||
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::util::exit_matcher_parser;
|
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
use crate::parser::Target;
|
use crate::types::Target;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn target<'r, 's>(
|
pub fn target<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Target<'s>> {
|
) -> Res<OrgSource<'s>, Target<'s>> {
|
||||||
let (remaining, _) = tag("<<")(input)?;
|
let (remaining, _) = tag("<<")(input)?;
|
||||||
@@ -30,11 +30,11 @@ pub fn target<'r, 's>(
|
|||||||
!c.is_whitespace() && !"<>\n".contains(*c)
|
!c.is_whitespace() && !"<>\n".contains(*c)
|
||||||
}))(remaining)?;
|
}))(remaining)?;
|
||||||
|
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Beta,
|
||||||
class: ExitClass::Beta,
|
exit_matcher: &target_end,
|
||||||
exit_matcher: &target_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
let (remaining, _body) = recognize(many_till(
|
let (remaining, _body) = recognize(many_till(
|
||||||
anychar,
|
anychar,
|
||||||
parser_with_context!(exit_matcher_parser)(&parser_context),
|
parser_with_context!(exit_matcher_parser)(&parser_context),
|
||||||
@@ -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((
|
||||||
@@ -61,8 +62,8 @@ pub fn target<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn target_end<'r, 's>(
|
fn target_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(one_of("<>\n"))(input)
|
recognize(one_of("<>\n"))(input)
|
||||||
|
|||||||
@@ -15,32 +15,34 @@ use nom::sequence::terminated;
|
|||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
use tracing::span;
|
use tracing::span;
|
||||||
|
|
||||||
|
use super::object_parser::standard_set_object;
|
||||||
use super::org_source::OrgSource;
|
use super::org_source::OrgSource;
|
||||||
use super::radio_link::RematchObject;
|
use super::radio_link::RematchObject;
|
||||||
use super::Context;
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ContextMatcher;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::object_parser::standard_set_object;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::radio_link::rematch_target;
|
use crate::parser::radio_link::rematch_target;
|
||||||
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::preceded_by_whitespace;
|
use crate::parser::util::preceded_by_whitespace;
|
||||||
use crate::parser::Bold;
|
use crate::types::Bold;
|
||||||
use crate::parser::Code;
|
use crate::types::Code;
|
||||||
use crate::parser::Italic;
|
use crate::types::Italic;
|
||||||
use crate::parser::Object;
|
use crate::types::Object;
|
||||||
use crate::parser::StrikeThrough;
|
use crate::types::StrikeThrough;
|
||||||
use crate::parser::Underline;
|
use crate::types::Underline;
|
||||||
use crate::parser::Verbatim;
|
use crate::types::Verbatim;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn text_markup<'r, 's>(
|
pub fn text_markup<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Object<'s>> {
|
) -> Res<OrgSource<'s>, Object<'s>> {
|
||||||
alt((
|
alt((
|
||||||
@@ -57,8 +59,8 @@ pub fn text_markup<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn bold<'r, 's>(
|
pub fn bold<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Bold<'s>> {
|
) -> Res<OrgSource<'s>, Bold<'s>> {
|
||||||
let text_markup_object_specialized = text_markup_object("*");
|
let text_markup_object_specialized = text_markup_object("*");
|
||||||
@@ -74,8 +76,8 @@ pub fn bold<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn italic<'r, 's>(
|
pub fn italic<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Italic<'s>> {
|
) -> Res<OrgSource<'s>, Italic<'s>> {
|
||||||
let text_markup_object_specialized = text_markup_object("/");
|
let text_markup_object_specialized = text_markup_object("/");
|
||||||
@@ -91,8 +93,8 @@ pub fn italic<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn underline<'r, 's>(
|
pub fn underline<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Underline<'s>> {
|
) -> Res<OrgSource<'s>, Underline<'s>> {
|
||||||
let text_markup_object_specialized = text_markup_object("_");
|
let text_markup_object_specialized = text_markup_object("_");
|
||||||
@@ -108,8 +110,8 @@ pub fn underline<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn strike_through<'r, 's>(
|
pub fn strike_through<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, StrikeThrough<'s>> {
|
) -> Res<OrgSource<'s>, StrikeThrough<'s>> {
|
||||||
let text_markup_object_specialized = text_markup_object("+");
|
let text_markup_object_specialized = text_markup_object("+");
|
||||||
@@ -125,8 +127,8 @@ pub fn strike_through<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn verbatim<'r, 's>(
|
pub fn verbatim<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Verbatim<'s>> {
|
) -> Res<OrgSource<'s>, Verbatim<'s>> {
|
||||||
let text_markup_string_specialized = text_markup_string("=");
|
let text_markup_string_specialized = text_markup_string("=");
|
||||||
@@ -142,8 +144,8 @@ pub fn verbatim<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn code<'r, 's>(
|
pub fn code<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Code<'s>> {
|
) -> Res<OrgSource<'s>, Code<'s>> {
|
||||||
let text_markup_string_specialized = text_markup_string("~");
|
let text_markup_string_specialized = text_markup_string("~");
|
||||||
@@ -158,30 +160,32 @@ pub fn code<'r, 's>(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_markup_object(
|
fn text_markup_object<'c>(
|
||||||
marker_symbol: &str,
|
marker_symbol: &'c str,
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
) -> impl for<'b, 'g, 'r, 's> Fn(
|
||||||
|
RefContext<'b, 'g, 'r, 's>,
|
||||||
|
OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, Vec<Object<'s>>>
|
||||||
|
+ 'c {
|
||||||
let marker_symbol = marker_symbol.to_owned();
|
let marker_symbol = marker_symbol.to_owned();
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
move |context, input: OrgSource<'_>| _text_markup_object(context, input, marker_symbol.as_str())
|
||||||
_text_markup_object(context, input, marker_symbol.as_str())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _text_markup_object<'r, 's, 'x>(
|
fn _text_markup_object<'b, 'g, 'r, 's, 'c>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
marker_symbol: &'x str,
|
marker_symbol: &'c str,
|
||||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||||
let (remaining, _) = pre(context, input)?;
|
let (remaining, _) = pre(context, input)?;
|
||||||
let (remaining, open) = tag(marker_symbol)(remaining)?;
|
let (remaining, open) = tag(marker_symbol)(remaining)?;
|
||||||
let (remaining, _peek_not_whitespace) = peek(not(multispace1))(remaining)?;
|
let (remaining, _peek_not_whitespace) = peek(not(multispace1))(remaining)?;
|
||||||
let text_markup_end_specialized = text_markup_end(open.into());
|
let text_markup_end_specialized = text_markup_end(open.into());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &text_markup_end_specialized,
|
||||||
exit_matcher: &text_markup_end_specialized,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, (children, _exit_contents)) = verify(
|
let (remaining, (children, _exit_contents)) = verify(
|
||||||
many_till(
|
many_till(
|
||||||
@@ -204,34 +208,37 @@ 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))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_markup_string(
|
fn text_markup_string<'c>(
|
||||||
marker_symbol: &str,
|
marker_symbol: &'c str,
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> impl for<'b, 'g, 'r, 's> Fn(
|
||||||
let marker_symbol = marker_symbol.to_owned();
|
RefContext<'b, 'g, 'r, 's>,
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
OrgSource<'s>,
|
||||||
_text_markup_string(context, input, marker_symbol.as_str())
|
) -> Res<OrgSource<'s>, OrgSource<'s>>
|
||||||
}
|
+ 'c {
|
||||||
|
move |context, input: OrgSource<'_>| _text_markup_string(context, input, marker_symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _text_markup_string<'r, 's, 'x>(
|
fn _text_markup_string<'b, 'g, 'r, 's, 'c>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
marker_symbol: &'x str,
|
marker_symbol: &'c str,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _) = pre(context, input)?;
|
let (remaining, _) = pre(context, input)?;
|
||||||
let (remaining, open) = tag(marker_symbol)(remaining)?;
|
let (remaining, open) = tag(marker_symbol)(remaining)?;
|
||||||
let (remaining, _peek_not_whitespace) = peek(not(multispace1))(remaining)?;
|
let (remaining, _peek_not_whitespace) =
|
||||||
|
peek(verify(anychar, |c| !c.is_whitespace() && *c != '\u{200B}'))(remaining)?;
|
||||||
let text_markup_end_specialized = text_markup_end(open.into());
|
let text_markup_end_specialized = text_markup_end(open.into());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &text_markup_end_specialized,
|
||||||
exit_matcher: &text_markup_end_specialized,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, contents) = recognize(verify(
|
let (remaining, contents) = recognize(verify(
|
||||||
many_till(
|
many_till(
|
||||||
@@ -254,12 +261,16 @@ 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))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn pre<'r, 's>(_context: Context<'r, 's>, input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
pub fn pre<'b, 'g, 'r, 's>(
|
||||||
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, ()> {
|
||||||
let preceding_character = input.get_preceding_character();
|
let preceding_character = input.get_preceding_character();
|
||||||
match preceding_character {
|
match preceding_character {
|
||||||
// If None, we are at the start of the file which is technically the beginning of a line.
|
// If None, we are at the start of the file which is technically the beginning of a line.
|
||||||
@@ -276,25 +287,23 @@ 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<'b, 'g, 'r, 's>(
|
||||||
let (remaining, _) = alt((recognize(one_of(" \r\n\t-.,;:!?')}[\">")), line_ending))(input)?;
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
input: OrgSource<'s>,
|
||||||
|
) -> Res<OrgSource<'s>, ()> {
|
||||||
|
let (remaining, _) = alt((recognize(one_of(" \r\n\t-.,;:!?')}[\"")), line_ending))(input)?;
|
||||||
Ok((remaining, ()))
|
Ok((remaining, ()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_markup_end(
|
fn text_markup_end<'c>(marker_symbol: &'c str) -> impl ContextMatcher + 'c {
|
||||||
marker_symbol: &str,
|
move |context, input: OrgSource<'_>| _text_markup_end(context, input, marker_symbol)
|
||||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
||||||
let marker_symbol = marker_symbol.to_owned();
|
|
||||||
move |context: Context, input: OrgSource<'_>| {
|
|
||||||
_text_markup_end(context, input, marker_symbol.as_str())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _text_markup_end<'r, 's, 'x>(
|
fn _text_markup_end<'b, 'g, 'r, 's, 'c>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
marker_symbol: &'x str,
|
marker_symbol: &'c str,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
not(preceded_by_whitespace)(input)?;
|
not(preceded_by_whitespace)(input)?;
|
||||||
let (remaining, _marker) = terminated(
|
let (remaining, _marker) = terminated(
|
||||||
@@ -307,9 +316,9 @@ fn _text_markup_end<'r, 's, 'x>(
|
|||||||
|
|
||||||
impl<'x> RematchObject<'x> for Bold<'x> {
|
impl<'x> RematchObject<'x> for Bold<'x> {
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn rematch_object<'r, 's>(
|
fn rematch_object<'b, 'g, 'r, 's>(
|
||||||
&'x self,
|
&'x self,
|
||||||
_context: Context<'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 (remaining, children) =
|
let (remaining, children) =
|
||||||
@@ -326,8 +335,8 @@ impl<'x> RematchObject<'x> for Bold<'x> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn _rematch_text_markup_object<'r, 's, 'x>(
|
fn _rematch_text_markup_object<'b, 'g, 'r, 's, 'x>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
marker_symbol: &'static str,
|
marker_symbol: &'static str,
|
||||||
original_match_children: &'x Vec<Object<'x>>,
|
original_match_children: &'x Vec<Object<'x>>,
|
||||||
@@ -336,11 +345,11 @@ fn _rematch_text_markup_object<'r, 's, 'x>(
|
|||||||
let (remaining, open) = tag(marker_symbol)(remaining)?;
|
let (remaining, open) = tag(marker_symbol)(remaining)?;
|
||||||
let (remaining, _peek_not_whitespace) = peek(not(multispace1))(remaining)?;
|
let (remaining, _peek_not_whitespace) = peek(not(multispace1))(remaining)?;
|
||||||
let text_markup_end_specialized = text_markup_end(open.into());
|
let text_markup_end_specialized = text_markup_end(open.into());
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &text_markup_end_specialized,
|
||||||
exit_matcher: &text_markup_end_specialized,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, children) =
|
let (remaining, children) =
|
||||||
// TODO: This doesn't really check the exit matcher between each object. I think it may be possible to construct an org document that parses incorrectly with the current code.
|
// TODO: This doesn't really check the exit matcher between each object. I think it may be possible to construct an org document that parses incorrectly with the current code.
|
||||||
|
|||||||
@@ -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,20 +11,20 @@ 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::Context;
|
use super::util::exit_matcher_parser;
|
||||||
|
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
|
||||||
|
use crate::context::parser_with_context;
|
||||||
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::ExitClass;
|
||||||
|
use crate::context::ExitMatcherNode;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::exiting::ExitClass;
|
|
||||||
use crate::parser::parser_context::ContextElement;
|
|
||||||
use crate::parser::parser_context::ContextTree;
|
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
use crate::parser::util::exit_matcher_parser;
|
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
use crate::parser::Timestamp;
|
use crate::types::Timestamp;
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn timestamp<'r, 's>(
|
pub fn timestamp<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
||||||
// TODO: This would be more efficient if we didn't throw away the parse result of the first half of an active/inactive date range timestamp if the parse fails (as in, the first thing active_date_range_timestamp parses is a active_timestamp but then we throw that away if it doesn't turn out to be a full active_date_range_timestamp despite the active_timestamp parse being completely valid). I am going with the simplest/cleanest approach for the first implementation.
|
// TODO: This would be more efficient if we didn't throw away the parse result of the first half of an active/inactive date range timestamp if the parse fails (as in, the first thing active_date_range_timestamp parses is a active_timestamp but then we throw that away if it doesn't turn out to be a full active_date_range_timestamp despite the active_timestamp parse being completely valid). I am going with the simplest/cleanest approach for the first implementation.
|
||||||
@@ -42,14 +41,15 @@ pub fn timestamp<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn diary_timestamp<'r, 's>(
|
fn diary_timestamp<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
) -> Res<OrgSource<'s>, Timestamp<'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((
|
||||||
@@ -61,15 +61,15 @@ fn diary_timestamp<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn sexp<'r, 's>(
|
fn sexp<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &sexp_end,
|
||||||
exit_matcher: &sexp_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, body) = recognize(verify(
|
let (remaining, body) = recognize(verify(
|
||||||
many_till(
|
many_till(
|
||||||
@@ -83,25 +83,25 @@ fn sexp<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn sexp_end<'r, 's>(
|
fn sexp_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
alt((tag(")>"), recognize(one_of(">\n"))))(input)
|
alt((tag(")>"), recognize(one_of(">\n"))))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn active_timestamp<'r, 's>(
|
fn active_timestamp<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
||||||
let (remaining, _) = tag("<")(input)?;
|
let (remaining, _) = tag("<")(input)?;
|
||||||
let (remaining, _date) = date(context, remaining)?;
|
let (remaining, _date) = date(context, remaining)?;
|
||||||
let time_context =
|
let time_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &active_time_rest_end,
|
||||||
exit_matcher: &active_time_rest_end,
|
});
|
||||||
}));
|
let time_context = context.with_additional_node(&time_context);
|
||||||
let (remaining, _time) =
|
let (remaining, _time) =
|
||||||
opt(tuple((space1, parser_with_context!(time)(&time_context))))(remaining)?;
|
opt(tuple((space1, parser_with_context!(time)(&time_context))))(remaining)?;
|
||||||
let (remaining, _repeater) =
|
let (remaining, _repeater) =
|
||||||
@@ -112,7 +112,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((
|
||||||
@@ -124,17 +125,17 @@ fn active_timestamp<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn inactive_timestamp<'r, 's>(
|
fn inactive_timestamp<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
||||||
let (remaining, _) = tag("[")(input)?;
|
let (remaining, _) = tag("[")(input)?;
|
||||||
let (remaining, _date) = date(context, remaining)?;
|
let (remaining, _date) = date(context, remaining)?;
|
||||||
let time_context =
|
let time_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &inactive_time_rest_end,
|
||||||
exit_matcher: &inactive_time_rest_end,
|
});
|
||||||
}));
|
let time_context = context.with_additional_node(&time_context);
|
||||||
let (remaining, _time) =
|
let (remaining, _time) =
|
||||||
opt(tuple((space1, parser_with_context!(time)(&time_context))))(remaining)?;
|
opt(tuple((space1, parser_with_context!(time)(&time_context))))(remaining)?;
|
||||||
let (remaining, _repeater) =
|
let (remaining, _repeater) =
|
||||||
@@ -145,7 +146,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((
|
||||||
@@ -157,8 +159,8 @@ fn inactive_timestamp<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn active_date_range_timestamp<'r, 's>(
|
fn active_date_range_timestamp<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
||||||
let (remaining, _first_timestamp) = active_timestamp(context, input)?;
|
let (remaining, _first_timestamp) = active_timestamp(context, input)?;
|
||||||
@@ -166,7 +168,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((
|
||||||
@@ -178,22 +181,22 @@ fn active_date_range_timestamp<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn active_time_range_timestamp<'r, 's>(
|
fn active_time_range_timestamp<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
||||||
let (remaining, _) = tag("<")(input)?;
|
let (remaining, _) = tag("<")(input)?;
|
||||||
let (remaining, _date) = date(context, remaining)?;
|
let (remaining, _date) = date(context, remaining)?;
|
||||||
let time_context =
|
let time_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &active_time_rest_end,
|
||||||
exit_matcher: &active_time_rest_end,
|
});
|
||||||
}));
|
let time_context = context.with_additional_node(&time_context);
|
||||||
let first_time_context =
|
let first_time_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
time_context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &time_range_rest_end,
|
||||||
exit_matcher: &time_range_rest_end,
|
});
|
||||||
}));
|
let first_time_context = time_context.with_additional_node(&first_time_context);
|
||||||
let (remaining, _first_time) =
|
let (remaining, _first_time) =
|
||||||
tuple((space1, parser_with_context!(time)(&first_time_context)))(remaining)?;
|
tuple((space1, parser_with_context!(time)(&first_time_context)))(remaining)?;
|
||||||
let (remaining, _) = tag("-")(remaining)?;
|
let (remaining, _) = tag("-")(remaining)?;
|
||||||
@@ -206,7 +209,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((
|
||||||
@@ -218,8 +222,8 @@ fn active_time_range_timestamp<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn inactive_date_range_timestamp<'r, 's>(
|
fn inactive_date_range_timestamp<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
||||||
let (remaining, _first_timestamp) = inactive_timestamp(context, input)?;
|
let (remaining, _first_timestamp) = inactive_timestamp(context, input)?;
|
||||||
@@ -227,7 +231,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((
|
||||||
@@ -239,22 +244,22 @@ fn inactive_date_range_timestamp<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn inactive_time_range_timestamp<'r, 's>(
|
fn inactive_time_range_timestamp<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
) -> Res<OrgSource<'s>, Timestamp<'s>> {
|
||||||
let (remaining, _) = tag("[")(input)?;
|
let (remaining, _) = tag("[")(input)?;
|
||||||
let (remaining, _date) = date(context, remaining)?;
|
let (remaining, _date) = date(context, remaining)?;
|
||||||
let time_context =
|
let time_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &inactive_time_rest_end,
|
||||||
exit_matcher: &inactive_time_rest_end,
|
});
|
||||||
}));
|
let time_context = context.with_additional_node(&time_context);
|
||||||
let first_time_context =
|
let first_time_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
time_context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &time_range_rest_end,
|
||||||
exit_matcher: &time_range_rest_end,
|
});
|
||||||
}));
|
let first_time_context = time_context.with_additional_node(&first_time_context);
|
||||||
let (remaining, _first_time) =
|
let (remaining, _first_time) =
|
||||||
tuple((space1, parser_with_context!(time)(&first_time_context)))(remaining)?;
|
tuple((space1, parser_with_context!(time)(&first_time_context)))(remaining)?;
|
||||||
let (remaining, _) = tag("-")(remaining)?;
|
let (remaining, _) = tag("-")(remaining)?;
|
||||||
@@ -267,7 +272,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((
|
||||||
@@ -279,8 +285,8 @@ fn inactive_time_range_timestamp<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn date<'r, 's>(
|
fn date<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _year) = verify(digit1, |year: &OrgSource<'_>| year.len() == 4)(input)?;
|
let (remaining, _year) = verify(digit1, |year: &OrgSource<'_>| year.len() == 4)(input)?;
|
||||||
@@ -297,15 +303,15 @@ fn date<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn dayname<'r, 's>(
|
fn dayname<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let parser_context =
|
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
class: ExitClass::Gamma,
|
||||||
class: ExitClass::Gamma,
|
exit_matcher: &dayname_end,
|
||||||
exit_matcher: &dayname_end,
|
});
|
||||||
}));
|
let parser_context = context.with_additional_node(&parser_context);
|
||||||
|
|
||||||
let (remaining, body) = recognize(verify(
|
let (remaining, body) = recognize(verify(
|
||||||
many_till(
|
many_till(
|
||||||
@@ -319,8 +325,8 @@ fn dayname<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn dayname_end<'r, 's>(
|
fn dayname_end<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(verify(anychar, |c| {
|
recognize(verify(anychar, |c| {
|
||||||
@@ -329,8 +335,8 @@ fn dayname_end<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn time<'r, 's>(
|
fn time<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, _hour) = verify(digit1, |hour: &OrgSource<'_>| {
|
let (remaining, _hour) = verify(digit1, |hour: &OrgSource<'_>| {
|
||||||
@@ -345,8 +351,8 @@ fn time<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn time_rest<'r, 's>(
|
fn time_rest<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
let (remaining, body) = recognize(verify(
|
let (remaining, body) = recognize(verify(
|
||||||
@@ -358,8 +364,8 @@ fn time_rest<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn active_time_rest_end<'r, 's>(
|
fn active_time_rest_end<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
alt((
|
alt((
|
||||||
@@ -373,8 +379,8 @@ fn active_time_rest_end<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn inactive_time_rest_end<'r, 's>(
|
fn inactive_time_rest_end<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
alt((
|
alt((
|
||||||
@@ -388,21 +394,20 @@ fn inactive_time_rest_end<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn time_range_rest_end<'r, 's>(
|
fn time_range_rest_end<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
// We pop off the most recent context element to get a context tree with just the active/inactive_time_rest_end exit matcher (removing this function from the exit matcher chain) because the 2nd time in the range does not end when a "-TIME" pattern is found.
|
// We pop off the most recent context element to get a context tree with just the active/inactive_time_rest_end exit matcher (removing this function from the exit matcher chain) because the 2nd time in the range does not end when a "-TIME" pattern is found.
|
||||||
let parent_node = context.iter().next().expect("Two context elements are added to the tree when adding this exit matcher, so it should be impossible for this to return None.");
|
let parent_node = context.get_parent().expect("Two context elements are added to the tree when adding this exit matcher, so it should be impossible for this to return None.");
|
||||||
let parent_tree = ContextTree::branch_from(parent_node);
|
|
||||||
let exit_contents =
|
let exit_contents =
|
||||||
recognize(tuple((tag("-"), parser_with_context!(time)(&parent_tree))))(input);
|
recognize(tuple((tag("-"), parser_with_context!(time)(&parent_node))))(input);
|
||||||
exit_contents
|
exit_contents
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn repeater<'r, 's>(
|
fn repeater<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
// + for cumulative type
|
// + for cumulative type
|
||||||
@@ -417,8 +422,8 @@ fn repeater<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn warning_delay<'r, 's>(
|
fn warning_delay<'b, 'g, 'r, 's>(
|
||||||
_context: Context<'r, 's>,
|
_context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
// - for all type
|
// - for all type
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use super::Document;
|
use crate::types::Document;
|
||||||
use super::Element;
|
use crate::types::DocumentElement;
|
||||||
use super::Heading;
|
use crate::types::Element;
|
||||||
use super::Object;
|
use crate::types::Heading;
|
||||||
use super::PlainListItem;
|
use crate::types::Object;
|
||||||
use super::Section;
|
use crate::types::PlainListItem;
|
||||||
use super::TableCell;
|
use crate::types::Section;
|
||||||
use super::TableRow;
|
use crate::types::TableCell;
|
||||||
use crate::parser::DocumentElement;
|
use crate::types::TableRow;
|
||||||
|
|
||||||
pub enum Token<'r, 's> {
|
pub enum Token<'r, 's> {
|
||||||
Document(&'r Document<'s>),
|
Document(&'r Document<'s>),
|
||||||
|
|||||||
@@ -14,21 +14,24 @@ 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::parser_context::ContextElement;
|
use crate::context::parser_with_context;
|
||||||
use super::Context;
|
use crate::context::ContextElement;
|
||||||
|
use crate::context::RefContext;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::error::MyError;
|
use crate::error::MyError;
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
|
||||||
|
|
||||||
pub const WORD_CONSTITUENT_CHARACTERS: &str =
|
pub const WORD_CONSTITUENT_CHARACTERS: &str =
|
||||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
|
|
||||||
/// Check if we are below a section of the given section type regardless of depth
|
/// Check if we are below a section of the given section type regardless of depth
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn in_section<'r, 's, 'x>(context: Context<'r, 's>, section_name: &'x str) -> bool {
|
pub fn in_section<'b, 'g, 'r, 's, 'x>(
|
||||||
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
section_name: &'x str,
|
||||||
|
) -> bool {
|
||||||
for thing in context.iter() {
|
for thing in context.iter() {
|
||||||
match thing.get_data() {
|
match thing {
|
||||||
ContextElement::Context(name) if *name == section_name => return true,
|
ContextElement::Context(name) if *name == section_name => return true,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -37,9 +40,12 @@ pub fn in_section<'r, 's, 'x>(context: Context<'r, 's>, section_name: &'x str) -
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if we are currently an immediate child of the given section type
|
/// Checks if we are currently an immediate child of the given section type
|
||||||
pub fn immediate_in_section<'r, 's, 'x>(context: Context<'r, 's>, section_name: &'x str) -> bool {
|
pub fn immediate_in_section<'b, 'g, 'r, 's, 'x>(
|
||||||
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
|
section_name: &'x str,
|
||||||
|
) -> bool {
|
||||||
for thing in context.iter() {
|
for thing in context.iter() {
|
||||||
match thing.get_data() {
|
match thing {
|
||||||
ContextElement::Context(name) if *name == section_name => return true,
|
ContextElement::Context(name) if *name == section_name => return true,
|
||||||
ContextElement::Context(name) if *name != section_name => return false,
|
ContextElement::Context(name) if *name != section_name => return false,
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -69,8 +75,20 @@ pub fn element_trailing_whitespace<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[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_object_trailing_whitespace_if_not_exiting<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, '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"))]
|
||||||
|
pub fn maybe_consume_trailing_whitespace_if_not_exiting<'b, 'g, 'r, 's>(
|
||||||
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Option<OrgSource<'s>>> {
|
) -> Res<OrgSource<'s>, Option<OrgSource<'s>>> {
|
||||||
if context.should_consume_trailing_whitespace() && exit_matcher_parser(context, input).is_err()
|
if context.should_consume_trailing_whitespace() && exit_matcher_parser(context, input).is_err()
|
||||||
@@ -82,8 +100,8 @@ pub fn maybe_consume_trailing_whitespace_if_not_exiting<'r, 's>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn maybe_consume_trailing_whitespace<'r, 's>(
|
pub fn maybe_consume_trailing_whitespace<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, Option<OrgSource<'s>>> {
|
) -> Res<OrgSource<'s>, Option<OrgSource<'s>>> {
|
||||||
if context.should_consume_trailing_whitespace() {
|
if context.should_consume_trailing_whitespace() {
|
||||||
@@ -109,15 +127,14 @@ pub fn start_of_line<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
|||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn preceded_by_whitespace<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
pub fn preceded_by_whitespace<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
|
||||||
let preceding_character = input.get_preceding_character();
|
let preceding_character = input.get_preceding_character();
|
||||||
match preceding_character {
|
if !preceding_character
|
||||||
Some('\n') | Some('\r') | Some(' ') | Some('\t') => {}
|
.map(|c| c.is_whitespace() || c == '\u{200B}') // 200B = Zero-width space
|
||||||
// If None, we are at the start of the file which is not allowed
|
.unwrap_or(false)
|
||||||
None | Some(_) => {
|
{
|
||||||
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
||||||
"Not preceded by whitespace.".into(),
|
"Not preceded by whitespace.".into(),
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
Ok((input, ()))
|
Ok((input, ()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,16 +148,16 @@ pub fn non_whitespace_character(input: OrgSource<'_>) -> Res<OrgSource<'_>, char
|
|||||||
|
|
||||||
/// Check that we are at the start of a line
|
/// Check that we are at the start of a line
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn exit_matcher_parser<'r, 's>(
|
pub fn exit_matcher_parser<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
peek(|i| context.check_exit_matcher(i))(input)
|
peek(|i| context.check_exit_matcher(i))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn text_until_exit<'r, 's>(
|
pub fn text_until_exit<'b, 'g, 'r, 's>(
|
||||||
context: Context<'r, 's>,
|
context: RefContext<'b, 'g, 'r, 's>,
|
||||||
input: OrgSource<'s>,
|
input: OrgSource<'s>,
|
||||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||||
recognize(verify(
|
recognize(verify(
|
||||||
|
|||||||
66
src/types/document.rs
Normal file
66
src/types/document.rs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
use super::Element;
|
||||||
|
use super::Object;
|
||||||
|
use super::Source;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Document<'s> {
|
||||||
|
pub source: &'s str,
|
||||||
|
pub zeroth_section: Option<Section<'s>>,
|
||||||
|
pub children: Vec<Heading<'s>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Heading<'s> {
|
||||||
|
pub source: &'s str,
|
||||||
|
pub stars: usize,
|
||||||
|
pub todo_keyword: Option<(TodoKeywordType, &'s str)>,
|
||||||
|
// TODO: add todo-type enum
|
||||||
|
pub title: Vec<Object<'s>>,
|
||||||
|
pub tags: Vec<&'s str>,
|
||||||
|
pub children: Vec<DocumentElement<'s>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Section<'s> {
|
||||||
|
pub source: &'s str,
|
||||||
|
pub children: Vec<Element<'s>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DocumentElement<'s> {
|
||||||
|
Heading(Heading<'s>),
|
||||||
|
Section(Section<'s>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TodoKeywordType {
|
||||||
|
Todo,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> Source<'s> for Document<'s> {
|
||||||
|
fn get_source(&'s self) -> &'s str {
|
||||||
|
self.source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> Source<'s> for DocumentElement<'s> {
|
||||||
|
fn get_source(&'s self) -> &'s str {
|
||||||
|
match self {
|
||||||
|
DocumentElement::Heading(obj) => obj.source,
|
||||||
|
DocumentElement::Section(obj) => obj.source,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> Source<'s> for Section<'s> {
|
||||||
|
fn get_source(&'s self) -> &'s str {
|
||||||
|
self.source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> Source<'s> for Heading<'s> {
|
||||||
|
fn get_source(&'s self) -> &'s str {
|
||||||
|
self.source
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,9 +18,9 @@ use super::lesser_element::Paragraph;
|
|||||||
use super::lesser_element::Planning;
|
use super::lesser_element::Planning;
|
||||||
use super::lesser_element::SrcBlock;
|
use super::lesser_element::SrcBlock;
|
||||||
use super::lesser_element::VerseBlock;
|
use super::lesser_element::VerseBlock;
|
||||||
use super::source::SetSource;
|
|
||||||
use super::source::Source;
|
|
||||||
use super::Drawer;
|
use super::Drawer;
|
||||||
|
use super::SetSource;
|
||||||
|
use super::Source;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Element<'s> {
|
pub enum Element<'s> {
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::element::Element;
|
use super::element::Element;
|
||||||
use super::lesser_element::TableCell;
|
use super::lesser_element::TableCell;
|
||||||
use super::source::Source;
|
|
||||||
use super::Object;
|
use super::Object;
|
||||||
|
use super::Source;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PlainList<'s> {
|
pub struct PlainList<'s> {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::object::Object;
|
use super::object::Object;
|
||||||
use super::source::Source;
|
|
||||||
use super::PlainText;
|
use super::PlainText;
|
||||||
|
use super::Source;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Paragraph<'s> {
|
pub struct Paragraph<'s> {
|
||||||
@@ -87,6 +87,8 @@ pub struct HorizontalRule<'s> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Keyword<'s> {
|
pub struct Keyword<'s> {
|
||||||
pub source: &'s str,
|
pub source: &'s str,
|
||||||
|
pub key: &'s str,
|
||||||
|
pub value: &'s str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
67
src/types/mod.rs
Normal file
67
src/types/mod.rs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
mod document;
|
||||||
|
mod element;
|
||||||
|
mod greater_element;
|
||||||
|
mod lesser_element;
|
||||||
|
mod object;
|
||||||
|
mod source;
|
||||||
|
pub use document::Document;
|
||||||
|
pub use document::DocumentElement;
|
||||||
|
pub use document::Heading;
|
||||||
|
pub use document::Section;
|
||||||
|
pub use document::TodoKeywordType;
|
||||||
|
pub use element::Element;
|
||||||
|
pub use greater_element::Drawer;
|
||||||
|
pub use greater_element::DynamicBlock;
|
||||||
|
pub use greater_element::FootnoteDefinition;
|
||||||
|
pub use greater_element::GreaterBlock;
|
||||||
|
pub use greater_element::NodeProperty;
|
||||||
|
pub use greater_element::PlainList;
|
||||||
|
pub use greater_element::PlainListItem;
|
||||||
|
pub use greater_element::PropertyDrawer;
|
||||||
|
pub use greater_element::Table;
|
||||||
|
pub use greater_element::TableRow;
|
||||||
|
pub use lesser_element::Clock;
|
||||||
|
pub use lesser_element::Comment;
|
||||||
|
pub use lesser_element::CommentBlock;
|
||||||
|
pub use lesser_element::DiarySexp;
|
||||||
|
pub use lesser_element::ExampleBlock;
|
||||||
|
pub use lesser_element::ExportBlock;
|
||||||
|
pub use lesser_element::FixedWidthArea;
|
||||||
|
pub use lesser_element::HorizontalRule;
|
||||||
|
pub use lesser_element::Keyword;
|
||||||
|
pub use lesser_element::LatexEnvironment;
|
||||||
|
pub use lesser_element::Paragraph;
|
||||||
|
pub use lesser_element::Planning;
|
||||||
|
pub use lesser_element::SrcBlock;
|
||||||
|
pub use lesser_element::TableCell;
|
||||||
|
pub use lesser_element::VerseBlock;
|
||||||
|
pub use object::AngleLink;
|
||||||
|
pub use object::Bold;
|
||||||
|
pub use object::Citation;
|
||||||
|
pub use object::CitationReference;
|
||||||
|
pub use object::Code;
|
||||||
|
pub use object::Entity;
|
||||||
|
pub use object::ExportSnippet;
|
||||||
|
pub use object::FootnoteReference;
|
||||||
|
pub use object::InlineBabelCall;
|
||||||
|
pub use object::InlineSourceBlock;
|
||||||
|
pub use object::Italic;
|
||||||
|
pub use object::LatexFragment;
|
||||||
|
pub use object::LineBreak;
|
||||||
|
pub use object::Object;
|
||||||
|
pub use object::OrgMacro;
|
||||||
|
pub use object::PlainLink;
|
||||||
|
pub use object::PlainText;
|
||||||
|
pub use object::RadioLink;
|
||||||
|
pub use object::RadioTarget;
|
||||||
|
pub use object::RegularLink;
|
||||||
|
pub use object::StatisticsCookie;
|
||||||
|
pub use object::StrikeThrough;
|
||||||
|
pub use object::Subscript;
|
||||||
|
pub use object::Superscript;
|
||||||
|
pub use object::Target;
|
||||||
|
pub use object::Timestamp;
|
||||||
|
pub use object::Underline;
|
||||||
|
pub use object::Verbatim;
|
||||||
|
pub use source::SetSource;
|
||||||
|
pub use source::Source;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::source::Source;
|
use super::Source;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Object<'s> {
|
pub enum Object<'s> {
|
||||||
@@ -1 +1,2 @@
|
|||||||
|
#[cfg(feature = "compare")]
|
||||||
include!(concat!(env!("OUT_DIR"), "/tests.rs"));
|
include!(concat!(env!("OUT_DIR"), "/tests.rs"));
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ fn {name}() {{
|
|||||||
let todo_org_path = "{path}";
|
let todo_org_path = "{path}";
|
||||||
let org_contents = std::fs::read_to_string(todo_org_path).expect("Read org file.");
|
let org_contents = std::fs::read_to_string(todo_org_path).expect("Read org file.");
|
||||||
println!("{{}}", org_contents);
|
println!("{{}}", org_contents);
|
||||||
let org_sexp = emacs_parse_org_document(org_contents.as_str()).expect("Use emacs to parse org file.");
|
let org_sexp = emacs_parse_anonymous_org_document(org_contents.as_str()).expect("Use emacs to parse org file.");
|
||||||
println!("{{}}", org_sexp);
|
println!("{{}}", org_sexp);
|
||||||
let (_remaining, parsed_sexp) = sexp_with_padding(org_sexp.as_str()).expect("Sexp Parse failure");
|
let (_remaining, parsed_sexp) = sexp_with_padding(org_sexp.as_str()).expect("Sexp Parse failure");
|
||||||
let (remaining, rust_parsed) = document(org_contents.as_str()).expect("Org Parse failure");
|
let rust_parsed = parse(org_contents.as_str()).expect("Org Parse failure");
|
||||||
println!("{{:#?}}", rust_parsed);
|
println!("{{:#?}}", rust_parsed);
|
||||||
let diff_result =
|
let diff_result =
|
||||||
compare_document(&parsed_sexp, &rust_parsed).expect("Compare parsed documents.");
|
compare_document(&parsed_sexp, &rust_parsed).expect("Compare parsed documents.");
|
||||||
@@ -14,5 +14,4 @@ fn {name}() {{
|
|||||||
.print(org_contents.as_str())
|
.print(org_contents.as_str())
|
||||||
.expect("Print document parse tree diff.");
|
.expect("Print document parse tree diff.");
|
||||||
assert!(!diff_result.is_bad());
|
assert!(!diff_result.is_bad());
|
||||||
assert_eq!(remaining, "");
|
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user