101 Commits

Author SHA1 Message Date
Tom Alexander
320b5f8568 Publish version 0.1.15.
All checks were successful
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
clippy Build clippy has succeeded
rustfmt Build rustfmt has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
2024-01-28 17:12:45 -05:00
Tom Alexander
99b2af6c99 Fix clippy. 2024-01-28 17:11:18 -05:00
Tom Alexander
6e71acdb7d Update README.
Some checks failed
clippy Build clippy has failed
rustfmt Build rustfmt has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2024-01-28 14:25:57 -05:00
Tom Alexander
8406d37991 Switch to using JSON for wasm.
Some checks failed
rust-build Build rust-build has failed
clippy Build clippy has failed
rustfmt Build rustfmt has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-test Build rust-test has succeeded
serde_wasm_bindgen was silently dropping many attributes (I suspect it is triggered by serde flatten) so this switches to serializing to JSON for passing values from wasm to js.
2024-01-27 16:13:17 -05:00
Tom Alexander
64bb597908 Build bundler wasm target by default. 2024-01-26 21:17:40 -05:00
Tom Alexander
068864ea87 Publish version 0.1.14.
All checks were successful
clippy Build clippy has succeeded
rustfmt Build rustfmt has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2024-01-03 23:59:51 -05:00
Tom Alexander
03a3ddbd63 Merge branch 'wasm'
All checks were successful
clippy Build clippy has succeeded
rustfmt Build rustfmt has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2024-01-03 23:56:35 -05:00
Tom Alexander
122adee23b Hide the wasm module.
All checks were successful
clippy Build clippy has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2024-01-03 23:38:04 -05:00
Tom Alexander
556afecbb8 Hide the util module. 2024-01-03 23:04:47 -05:00
Tom Alexander
e4407cbdd1 Hide the event_count module.
All checks were successful
clippy Build clippy has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
By placing the code for the parse executable inside a module inside the organic library, we only need to expose the entrypoint publicly rather than all functions it calls. This hides the event_count module, but I will be expanding the practice to the rest of the code base shortly. This is important for not inadvertently promising stability w.r.t. semver for essentially internal functions for development tools.

It was the parse binary, not compare.
2024-01-03 21:17:44 -05:00
Tom Alexander
f57d60dab0 Add a doc target to the Makefile. 2024-01-03 19:55:22 -05:00
Tom Alexander
0aa3939a75 Format. 2024-01-01 18:34:10 -05:00
Tom Alexander
52cb81e75e Cleanup.
All checks were successful
clippy Build clippy has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-31 12:02:02 -05:00
Tom Alexander
945121202d Remove wasm_test's dependency on compare module.
All checks were successful
clippy Build clippy has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-31 11:11:25 -05:00
Tom Alexander
f4e0dddd9d Fix clippy.
All checks were successful
clippy Build clippy has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-30 23:14:40 -05:00
Tom Alexander
6b62176fd0 Run cargo fix.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-30 22:22:32 -05:00
Tom Alexander
44483b4d54 Break util up into modules. 2023-12-30 22:19:16 -05:00
Tom Alexander
48d3de77fe Move elisp fact to util. 2023-12-30 21:37:25 -05:00
Tom Alexander
680b176501 Fix src block value.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has succeeded
2023-12-30 21:30:08 -05:00
Tom Alexander
dc0338e978 Handle nil in object tree. 2023-12-30 21:28:25 -05:00
Tom Alexander
ff3e0a50af Implement dynamic block.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has failed
2023-12-30 20:56:35 -05:00
Tom Alexander
03c8c07fe0 Implement quote block. 2023-12-30 20:53:20 -05:00
Tom Alexander
3a6fc5b669 Support noop on all token types. 2023-12-30 20:50:28 -05:00
Tom Alexander
d258cdb839 Support null vs noop comparison. 2023-12-30 20:47:17 -05:00
Tom Alexander
aa5629354e Implement special block. 2023-12-30 20:43:01 -05:00
Tom Alexander
efc4a04829 Implement center block. 2023-12-30 20:38:08 -05:00
Tom Alexander
dd611ea64a Fix plain list item. 2023-12-30 20:35:27 -05:00
Tom Alexander
4bd5f3bec7 Implement node property. 2023-12-30 19:01:07 -05:00
Tom Alexander
c2b3509b6a Implement property drawer. 2023-12-30 18:59:52 -05:00
Tom Alexander
7f3f5fb889 Implement table cell.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has failed
2023-12-30 18:52:52 -05:00
Tom Alexander
e0fbf17226 Implement table row. 2023-12-30 18:52:51 -05:00
Tom Alexander
4e18cbafba Implement table. 2023-12-30 18:52:51 -05:00
Tom Alexander
46c36d7f3e Implement babel call. 2023-12-30 18:15:58 -05:00
Tom Alexander
c46a935cfc Implement clock.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has failed
2023-12-30 18:12:09 -05:00
Tom Alexander
f50415cb32 Implement drawer. 2023-12-30 18:05:46 -05:00
Tom Alexander
4f1a151e97 Implement diary sexp. 2023-12-30 18:03:57 -05:00
Tom Alexander
c8e3fdba51 Implement horizontal rule. 2023-12-30 18:02:38 -05:00
Tom Alexander
4b3fc20c62 Fix order of reading optional pair values from elisp. 2023-12-30 18:00:26 -05:00
Tom Alexander
3131f8ac64 Implement example block and export block. 2023-12-30 17:55:56 -05:00
Tom Alexander
60a4835590 Implement comment block. 2023-12-30 17:44:32 -05:00
Tom Alexander
172d72aa46 Implement src block.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has failed
2023-12-30 17:40:15 -05:00
Tom Alexander
b4fcc6500b Implement verse block. 2023-12-30 16:47:24 -05:00
Tom Alexander
ddb6f31562 Implement angle link. 2023-12-30 16:41:55 -05:00
Tom Alexander
dc080b30fc Implement citation reference. 2023-12-30 16:35:01 -05:00
Tom Alexander
9901e17437 Implement citation. 2023-12-30 16:33:02 -05:00
Tom Alexander
ea000894f0 Implement entity. 2023-12-30 16:24:51 -05:00
Tom Alexander
e7742b529a Implement export snippet.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has failed
2023-12-30 16:18:08 -05:00
Tom Alexander
8eba0c4923 Implement footnote definition. 2023-12-30 16:13:54 -05:00
Tom Alexander
e0c0070a13 Implement footnote reference. 2023-12-30 16:05:41 -05:00
Tom Alexander
65ce116998 Implement inline babel call. 2023-12-30 15:52:48 -05:00
Tom Alexander
e348e7d4e3 Implement inline source block. 2023-12-30 13:13:35 -05:00
Tom Alexander
492090470c Implement latex environment. 2023-12-30 13:07:16 -05:00
Tom Alexander
3ec900c8df Implement latex fragment.
Some checks failed
clippy Build clippy has failed
rust-build Build rust-build has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-test Build rust-test has failed
2023-12-30 13:00:07 -05:00
Tom Alexander
d0a008ed22 Implement org macro. 2023-12-30 13:00:07 -05:00
Tom Alexander
f2292f1c07 Implement target. 2023-12-30 12:22:23 -05:00
Tom Alexander
44392cfcca Implement radio target. 2023-12-30 12:17:04 -05:00
Tom Alexander
110630d230 Implement radio link and regular link. 2023-12-30 12:14:03 -05:00
Tom Alexander
ebe12d96c1 Implement subscript and superscript.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has failed
2023-12-29 23:46:47 -05:00
Tom Alexander
24c8ac8e21 Implement all the text markup.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has failed
2023-12-29 23:41:15 -05:00
Tom Alexander
259ad6e242 Implement line break. 2023-12-29 23:27:37 -05:00
Tom Alexander
dd1f7c7777 Support a no-op for headline pre-blank.
Some checks failed
clippy Build clippy has failed
rust-build Build rust-build has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-test Build rust-test has failed
2023-12-29 23:21:30 -05:00
Tom Alexander
c1b471208d Implement plain list item.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has failed
2023-12-29 23:06:45 -05:00
Tom Alexander
606bab9e6d Fix handling of optval. 2023-12-29 22:58:32 -05:00
Tom Alexander
0edf5620a2 Implement plain list. 2023-12-29 22:04:34 -05:00
Tom Alexander
cdf87641c5 Implement comment. 2023-12-29 21:59:45 -05:00
Tom Alexander
eb2995dd3b Support list with empty string as only element for empty list. 2023-12-29 21:56:31 -05:00
Tom Alexander
cd6a64c015 Implement keyword. 2023-12-29 21:36:52 -05:00
Tom Alexander
a4a83d047d Fix node name getting chopped off.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has failed
2023-12-29 21:33:17 -05:00
Tom Alexander
a4414369ce Remove unnecessary additional properties in the already-implemented types. 2023-12-29 21:04:31 -05:00
Tom Alexander
83e4b72307 Implement timestamp. 2023-12-29 20:55:01 -05:00
Tom Alexander
34b3e4fa7b Implement statistics cookie. 2023-12-29 20:26:12 -05:00
Tom Alexander
c0e879dc1e Implement headline. 2023-12-29 20:26:11 -05:00
Tom Alexander
fa31b001f4 Implement fixed width area. 2023-12-29 19:21:35 -05:00
Tom Alexander
0897061ff6 Add wasm tests to the CI. 2023-12-29 19:07:07 -05:00
Tom Alexander
28a3e1bc7b Implement bold. 2023-12-29 18:56:29 -05:00
Tom Alexander
3fd3d20722 Merge branch 'test_wasm_json' into wasm
Some checks failed
clippy Build clippy has failed
rust-build Build rust-build has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-test Build rust-test has succeeded
2023-12-29 18:54:58 -05:00
Tom Alexander
90735586b5 Add special case for object trees. 2023-12-29 18:54:41 -05:00
Tom Alexander
78befc7665 Remove old code. 2023-12-29 17:31:14 -05:00
Tom Alexander
ef549d3b19 Compare quoted strings. 2023-12-29 17:29:13 -05:00
Tom Alexander
777c756a7f Compare plain text AST nodes. 2023-12-29 17:24:38 -05:00
Tom Alexander
037caf369c Standardize parameter order. 2023-12-29 16:56:02 -05:00
Tom Alexander
54085b5833 Implement compare optional pair. 2023-12-29 16:51:52 -05:00
Tom Alexander
2bfa8e59e7 Add code to compare children. 2023-12-29 16:06:07 -05:00
Tom Alexander
5d31db39a4 Remove some underscores from wasm schema to match elisp. 2023-12-29 15:41:41 -05:00
Tom Alexander
adcd0de7e4 Compare standard properties. 2023-12-29 15:38:18 -05:00
Tom Alexander
c2f9789a64 Placeholder for comparing quoted strings. 2023-12-29 15:09:54 -05:00
Tom Alexander
579cbb5d11 Switch everything over to the new to_wasm macro. 2023-12-29 15:03:36 -05:00
Tom Alexander
cad2be43bf Implement a new to_wasm macro that uses the WasmAstNodeWrapper. 2023-12-29 14:06:10 -05:00
Tom Alexander
a0a4f0eb90 Remove lifetimes from wasm ast nodes. 2023-12-29 12:49:43 -05:00
Tom Alexander
9f4f8e79ce Implement a wrapper type for AST nodes.
This is to make it impossible to have a collision for attribute names that are real attributes vs attributes I've added for structure (like children and ast_node).
2023-12-29 11:58:46 -05:00
Tom Alexander
77e0dbb42e Start working on a version of compare based on json values.
This will be a better test because it will be testing that what we export to json is equivalent to the elisp AST generated from emacs. Because of these tests, we could also confidently use the wasm structure to elisp.
2023-12-29 11:37:30 -05:00
Tom Alexander
eff5cdbf40 Flatten some structures.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-29 10:04:59 -05:00
Tom Alexander
eef3571299 Add compare logic for optional pair.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-27 21:23:06 -05:00
Tom Alexander
f227d8405e Implement compare for list of quoted strings.
Some checks failed
clippy Build clippy has failed
rust-build Build rust-build has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-test Build rust-test has succeeded
2023-12-27 21:00:12 -05:00
Tom Alexander
9520e5814b Add conversion for affiliated keywords to wasm additional properties. 2023-12-27 20:36:35 -05:00
Tom Alexander
28ad4fd046 Add conversion to WasmAstNode for wasm Objects. 2023-12-27 19:53:07 -05:00
Tom Alexander
7626a69fa1 Add default implementations for WasmElispCompare. 2023-12-27 19:42:45 -05:00
Tom Alexander
121c0ce516 Move the logic functions into their own module. 2023-12-27 19:22:43 -05:00
Tom Alexander
5a64db98fe Move wasm diff structs to their own module. 2023-12-27 19:15:39 -05:00
Tom Alexander
abfae9c6c0 Compare section.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded
2023-12-27 19:10:43 -05:00
Tom Alexander
5272e2f1b4 Start adding paragraph. 2023-12-27 18:47:59 -05:00
98 changed files with 3680 additions and 1961 deletions

View File

@@ -115,7 +115,7 @@ spec:
[
--no-default-features,
--features,
compare,
"compare,wasm_test",
--no-fail-fast,
--lib,
--test,

View File

@@ -127,7 +127,7 @@ spec:
- name: command
value: ["cargo", "fix"]
- name: args
value: ["--allow-dirty"]
value: ["--all-targets", "--all-features", "--allow-dirty"]
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
- name: commit-changes

View File

@@ -2,7 +2,7 @@
[package]
name = "organic"
version = "0.1.13"
version = "0.1.15"
authors = ["Tom Alexander <tom@fizz.buzz>"]
description = "An org-mode parser."
edition = "2021"
@@ -45,12 +45,14 @@ path = "src/lib.rs"
required-features = ["wasm"]
[[bin]]
# This bin exists for development purposes only. The real target of this crate is the library.
name = "wasm_test"
path = "src/bin_wasm_test.rs"
required-features = ["wasm_test"]
[dependencies]
futures = { version = "0.3.28", optional = true }
gloo-utils = "0.2.0"
nom = "7.1.1"
opentelemetry = { version = "0.20.0", optional = true, default-features = false, features = ["trace", "rt-tokio"] }
opentelemetry-otlp = { version = "0.13.0", optional = true }

View File

@@ -7,6 +7,7 @@ MAKEFLAGS += --no-builtin-rules
TESTJOBS := 4
OS:=$(shell uname -s)
RELEASEFLAGS :=
WASMTARGET := bundler # or web
ifeq ($(OS),Linux)
TESTJOBS:=$(shell nproc)
@@ -32,11 +33,7 @@ release:
.PHONY: wasm
wasm:
> cargo build --target=wasm32-unknown-unknown --profile wasm --bin wasm --features wasm
> wasm-bindgen --target web --out-dir target/wasm32-unknown-unknown/js target/wasm32-unknown-unknown/wasm/wasm.wasm
.PHONY: run_wasm
run_wasm:
> cat /tmp/test.org | cargo run --profile wasm --bin wasm_test --features wasm_test
> wasm-bindgen --target $(WASMTARGET) --out-dir target/wasm32-unknown-unknown/js target/wasm32-unknown-unknown/wasm/wasm.wasm
.PHONY: clean
clean:
@@ -58,11 +55,20 @@ clippy:
test:
> cargo test --no-default-features --features compare --no-fail-fast --lib --test test_loader -- --test-threads $(TESTJOBS)
.PHONY: doc
doc:
> cargo doc --no-deps --open --lib --release --all-features
.PHONY: dockertest
dockertest:
> $(MAKE) -C docker/organic_test
> 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: dockerwasmtest
dockerwasmtest:
> $(MAKE) -C docker/organic_test
> 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,wasm_test --no-fail-fast --lib --test test_loader autogen_wasm_ -- --test-threads $(TESTJOBS)
.PHONY: buildtest
buildtest:
> cargo build --no-default-features
@@ -71,6 +77,8 @@ buildtest:
> cargo build --no-default-features --features compare,tracing
> cargo build --no-default-features --features compare,foreign_document_test
> cargo build --no-default-features --features compare,tracing,foreign_document_test
> cargo build --target wasm32-unknown-unknown --profile wasm --bin wasm --no-default-features --features wasm
> cargo build --bin wasm_test --no-default-features --features wasm_test
.PHONY: foreign_document_test
foreign_document_test:

View File

@@ -10,17 +10,16 @@ Currently, Organic parses most documents the same as the official org-mode parse
### Project Goals
- We aim to provide perfect parity with the emacs org-mode parser. In that regard, any document that parses differently between Emacs and Organic is considered a bug.
- The parser should have minimal dependencies. This should reduce effort w.r.t.: security audits, legal compliance, portability.
- The parser should be usable everywhere. In the interest of getting org-mode used in as many places as possible, this parser should be usable by everyone everywhere. This means:
- The parser should have minimal dependencies.
- The parser should be usable everywhere. In the interest of getting org used in as many places as possible, this parser should be usable by everyone everywhere. This means:
- It must have a permissive license.
- We will investigate compiling to WASM. This is an important goal of the project and will definitely happen, but only after the parser has a more stable API.
- It compiles to both natively and to wasm.
- We will investigate compiling to a C library for native linking to other code. This is more of a maybe-goal for the project.
### Project Non-Goals
- This project will not include an elisp engine since that would drastically increase the complexity of the code. Any features requiring an elisp engine will not be implemented (for example, Emacs supports embedded eval expressions in documents but this parser will never support that).
- This project is exclusively an org-mode **parser**. This limits its scope to roughly the output of `(org-element-parse-buffer)`. It will not render org-mode documents in other formats like HTML or LaTeX.
### Project Maybe-Goals
- table.el support. Currently we support org-mode tables but org-mode also allows table.el tables. So far, their use in org-mode documents seems rather uncommon so this is a low-priority feature.
- Document editing support. I do not anticipate any advanced editing features to make editing ergonomic, but it should be relatively easy to be able to parse an org-mode document and serialize it back into org-mode. This would enable cool features to be built on top of the library like auto-formatters. To accomplish this feature, We'd have to capture all of the various separators and whitespace that we are currently simply throwing away. This would add many additional fields to the parsed structs and it would add more noise to the parsers themselves, so I do not want to approach this feature until the parser is more complete since it would make modifications and refactoring more difficult.
### Supported Versions
This project targets the version of Emacs and Org-mode that are built into the [organic-test docker image](docker/organic_test/Dockerfile). This is newer than the version of Org-mode that shipped with Emacs 29.1. The parser itself does not depend on Emacs or Org-mode though, so this only matters for development purposes when running the automated tests that compare against upstream Org-mode.

View File

@@ -30,7 +30,7 @@ endif
# NOTE: This target will write to folders underneath the git-root
.PHONY: run
run: build
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)
docker run --rm --init -t --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)
.PHONY: shell
shell: build

View File

@@ -1,28 +1,8 @@
use organic::parser::parse_with_settings;
use organic::settings::GlobalSettings;
use organic::wasm::ParseResult;
use organic::wasm::ToWasm;
use organic::wasm::ToWasmContext;
use wasm_bindgen::prelude::wasm_bindgen;
#[wasm_bindgen]
pub fn parse_org(org_contents: &str) -> wasm_bindgen::JsValue {
let rust_parsed = match parse_with_settings(org_contents, &GlobalSettings::default()) {
Ok(document) => document,
Err(err) => {
return serde_wasm_bindgen::to_value(&ParseResult::Error(format!("{:?}", err)))
.unwrap();
}
};
let to_wasm_context = ToWasmContext::new(org_contents);
let wasm_document = match rust_parsed.to_wasm(to_wasm_context) {
Ok(document) => document,
Err(err) => {
return serde_wasm_bindgen::to_value(&ParseResult::Error(format!("{:?}", err)))
.unwrap();
}
};
serde_wasm_bindgen::to_value(&ParseResult::Success(wasm_document)).unwrap()
organic::wasm_cli::parse_org(org_contents)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {

View File

@@ -1,17 +1,16 @@
use std::path::Path;
use crate::compare::diff::compare_document;
use crate::compare::diff::DiffResult;
use crate::compare::sexp::sexp;
use crate::context::GlobalSettings;
use crate::context::LocalFileAccessInterface;
use crate::parser::parse_file_with_settings;
use crate::parser::parse_with_settings;
use crate::util::emacs_parse_anonymous_org_document;
use crate::util::emacs_parse_file_org_document;
use crate::util::foreground_color;
use crate::util::print_versions;
use crate::util::reset_color;
use crate::util::cli::emacs_parse_anonymous_org_document;
use crate::util::cli::emacs_parse_file_org_document;
use crate::util::cli::print_versions;
use crate::util::elisp::sexp;
use crate::util::terminal::foreground_color;
use crate::util::terminal::reset_color;
pub async fn run_anonymous_compare<P: AsRef<str>>(
org_contents: P,

View File

@@ -9,8 +9,6 @@ use super::diff::artificial_owned_diff_scope;
use super::diff::compare_ast_node;
use super::diff::DiffEntry;
use super::diff::DiffStatus;
use super::sexp::unquote;
use super::sexp::Token;
use super::util::get_property;
use super::util::get_property_numeric;
use super::util::get_property_quoted_string;
@@ -20,6 +18,8 @@ use crate::types::CharOffsetInLine;
use crate::types::LineNumber;
use crate::types::RetainLabels;
use crate::types::SwitchNumberLines;
use crate::util::elisp::unquote;
use crate::util::elisp::Token;
#[derive(Debug)]
pub(crate) enum EmacsField<'s> {

View File

@@ -16,10 +16,6 @@ use super::compare_field::compare_property_retain_labels;
use super::compare_field::compare_property_set_of_quoted_string;
use super::compare_field::compare_property_single_ast_node;
use super::compare_field::compare_property_unquoted_atom;
use super::elisp_fact::ElispFact;
use super::elisp_fact::GetElispFact;
use super::sexp::unquote;
use super::sexp::Token;
use super::util::affiliated_keywords_names;
use super::util::assert_no_children;
use super::util::compare_additional_properties;
@@ -109,8 +105,12 @@ use crate::types::Verbatim;
use crate::types::VerseBlock;
use crate::types::WarningDelayType;
use crate::types::Year;
use crate::util::foreground_color;
use crate::util::reset_color;
use crate::util::elisp::unquote;
use crate::util::elisp::Token;
use crate::util::elisp_fact::ElispFact;
use crate::util::elisp_fact::GetElispFact;
use crate::util::terminal::foreground_color;
use crate::util::terminal::reset_color;
#[derive(Debug)]
pub enum DiffEntry<'b, 's> {

View File

@@ -2,9 +2,7 @@
mod compare;
mod compare_field;
mod diff;
mod elisp_fact;
mod macros;
mod sexp;
mod util;
pub use compare::run_anonymous_compare;
pub use compare::run_anonymous_compare_with_settings;
@@ -12,10 +10,3 @@ pub use compare::run_compare_on_file;
pub use compare::run_compare_on_file_with_settings;
pub use compare::silent_anonymous_compare;
pub use compare::silent_compare_on_file;
pub(crate) use compare_field::EmacsField;
pub(crate) use elisp_fact::ElispFact;
pub use sexp::sexp;
pub use sexp::Token;
pub(crate) use util::get_emacs_standard_properties;
pub(crate) use util::get_property_quoted_string;
pub(crate) use util::EmacsStandardProperties;

View File

@@ -8,14 +8,15 @@ use super::compare_field::compare_property_quoted_string;
use super::compare_field::ComparePropertiesResult;
use super::diff::DiffEntry;
use super::diff::DiffStatus;
use super::elisp_fact::GetElispFact;
use super::sexp::Token;
use crate::compare::diff::compare_ast_node;
use crate::compare::sexp::unquote;
use crate::types::AffiliatedKeywordValue;
use crate::types::AstNode;
use crate::types::GetAffiliatedKeywords;
use crate::types::StandardProperties;
use crate::util::elisp::get_emacs_standard_properties;
use crate::util::elisp::unquote;
use crate::util::elisp::Token;
use crate::util::elisp_fact::GetElispFact;
/// Check if the child string slice is a slice of the parent string slice.
fn is_slice_of(parent: &str, child: &str) -> bool {
@@ -145,80 +146,6 @@ fn assert_post_blank<'b, 's, S: StandardProperties<'s> + ?Sized>(
Ok(())
}
pub(crate) struct EmacsStandardProperties {
pub(crate) begin: Option<usize>,
#[allow(dead_code)]
pub(crate) post_affiliated: Option<usize>,
#[allow(dead_code)]
pub(crate) contents_begin: Option<usize>,
#[allow(dead_code)]
pub(crate) contents_end: Option<usize>,
pub(crate) end: Option<usize>,
#[allow(dead_code)]
pub(crate) post_blank: Option<usize>,
}
pub(crate) fn get_emacs_standard_properties(
emacs: &Token<'_>,
) -> Result<EmacsStandardProperties, Box<dyn std::error::Error>> {
let children = emacs.as_list()?;
let attributes_child = children.get(1).ok_or("Should have an attributes child.")?;
let attributes_map = attributes_child.as_map()?;
let standard_properties = attributes_map.get(":standard-properties");
Ok(if standard_properties.is_some() {
let mut std_props = standard_properties
.expect("if statement proves its Some")
.as_vector()?
.iter();
let begin = maybe_token_to_usize(std_props.next())?;
let post_affiliated = maybe_token_to_usize(std_props.next())?;
let contents_begin = maybe_token_to_usize(std_props.next())?;
let contents_end = maybe_token_to_usize(std_props.next())?;
let end = maybe_token_to_usize(std_props.next())?;
let post_blank = maybe_token_to_usize(std_props.next())?;
EmacsStandardProperties {
begin,
post_affiliated,
contents_begin,
contents_end,
end,
post_blank,
}
} else {
let begin = maybe_token_to_usize(attributes_map.get(":begin").copied())?;
let end = maybe_token_to_usize(attributes_map.get(":end").copied())?;
let contents_begin = maybe_token_to_usize(attributes_map.get(":contents-begin").copied())?;
let contents_end = maybe_token_to_usize(attributes_map.get(":contents-end").copied())?;
let post_blank = maybe_token_to_usize(attributes_map.get(":post-blank").copied())?;
let post_affiliated =
maybe_token_to_usize(attributes_map.get(":post-affiliated").copied())?;
EmacsStandardProperties {
begin,
post_affiliated,
contents_begin,
contents_end,
end,
post_blank,
}
})
}
fn maybe_token_to_usize(
token: Option<&Token<'_>>,
) -> Result<Option<usize>, Box<dyn std::error::Error>> {
Ok(token
.map(|token| token.as_atom())
.map_or(Ok(None), |r| r.map(Some))?
.and_then(|val| {
if val == "nil" {
None
} else {
Some(val.parse::<usize>())
}
})
.map_or(Ok(None), |r| r.map(Some))?)
}
/// Get a named property from the emacs token.
///
/// Returns Ok(None) if value is nil or absent.

View File

@@ -24,7 +24,7 @@ pub(crate) fn record_event(event_type: EventType, input: OrgSource<'_>) {
*db.entry(key).or_insert(0) += 1;
}
pub fn report(original_document: &str) {
pub(crate) fn report(original_document: &str) {
let mut db = GLOBAL_DATA.lock().unwrap();
let db = db.get_or_insert_with(HashMap::new);
let mut results: Vec<_> = db.iter().collect();

View File

@@ -2,5 +2,5 @@ mod database;
mod event_type;
pub(crate) use database::record_event;
pub use database::report;
pub(crate) use database::report;
pub(crate) use event_type::EventType;

View File

@@ -3,25 +3,29 @@
#![feature(path_file_prefix)]
#![feature(is_sorted)]
#![feature(test)]
#![feature(iter_intersperse)]
#![feature(exact_size_is_empty)]
// TODO: #![warn(missing_docs)]
#![allow(clippy::bool_assert_comparison)] // Sometimes you want the long form because its easier to see at a glance.
extern crate test;
// TODO: I only include compare to use some shared stuff like sexp and DiffResult. Ideally, this would be moved to a shared module.
#[cfg(any(feature = "compare", feature = "wasm_test"))]
#[cfg(feature = "compare")]
pub mod compare;
#[cfg(any(feature = "compare", feature = "wasm_test"))]
pub mod util;
pub mod parse_cli;
#[cfg(any(feature = "compare", feature = "wasm", feature = "wasm_test"))]
mod util;
#[cfg(any(feature = "wasm", feature = "wasm_test"))]
pub mod wasm;
mod wasm;
#[cfg(any(feature = "wasm", feature = "wasm_test"))]
pub mod wasm_cli;
#[cfg(feature = "wasm_test")]
pub mod wasm_test;
mod context;
mod error;
#[cfg(feature = "event_count")]
pub mod event_count;
mod event_count;
mod iter;
pub mod parser;
pub mod types;

View File

@@ -1,12 +1,4 @@
#![feature(round_char_boundary)]
#![feature(exact_size_is_empty)]
use std::io::Read;
use std::path::Path;
use ::organic::parser::parse;
use organic::parser::parse_with_settings;
use organic::settings::GlobalSettings;
use organic::settings::LocalFileAccessInterface;
use organic::parse_cli::main_body;
#[cfg(feature = "tracing")]
use crate::init_tracing::init_telemetry;
@@ -30,55 +22,3 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
main_body_result
})
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn main_body() -> Result<(), Box<dyn std::error::Error>> {
let args = std::env::args().skip(1);
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>> {
let mut stdin_contents = String::new();
std::io::stdin()
.lock()
.read_to_string(&mut stdin_contents)?;
Ok(stdin_contents)
}
fn run_anonymous_parse<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error::Error>> {
let org_contents = org_contents.as_ref();
let rust_parsed = parse(org_contents)?;
println!("{:#?}", rust_parsed);
#[cfg(feature = "event_count")]
organic::event_count::report(org_contents);
Ok(())
}
fn run_parse_on_file<P: AsRef<Path>>(org_path: P) -> Result<(), Box<dyn std::error::Error>> {
let org_path = org_path.as_ref();
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 = GlobalSettings {
file_access: &file_access_interface,
..Default::default()
};
let rust_parsed = parse_with_settings(org_contents, &global_settings)?;
println!("{:#?}", rust_parsed);
#[cfg(feature = "event_count")]
organic::event_count::report(org_contents);
Ok(())
}

59
src/parse_cli/mod.rs Normal file
View File

@@ -0,0 +1,59 @@
use std::io::Read;
use std::path::Path;
use crate::parser::parse;
use crate::parser::parse_with_settings;
use crate::settings::GlobalSettings;
use crate::settings::LocalFileAccessInterface;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub fn main_body() -> Result<(), Box<dyn std::error::Error>> {
let args = std::env::args().skip(1);
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>> {
let mut stdin_contents = String::new();
std::io::stdin()
.lock()
.read_to_string(&mut stdin_contents)?;
Ok(stdin_contents)
}
fn run_anonymous_parse<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error::Error>> {
let org_contents = org_contents.as_ref();
let rust_parsed = parse(org_contents)?;
println!("{:#?}", rust_parsed);
#[cfg(feature = "event_count")]
crate::event_count::report(org_contents);
Ok(())
}
fn run_parse_on_file<P: AsRef<Path>>(org_path: P) -> Result<(), Box<dyn std::error::Error>> {
let org_path = org_path.as_ref();
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 = GlobalSettings {
file_access: &file_access_interface,
..Default::default()
};
let rust_parsed = parse_with_settings(org_contents, &global_settings)?;
println!("{:#?}", rust_parsed);
#[cfg(feature = "event_count")]
crate::event_count::report(org_contents);
Ok(())
}

View File

@@ -332,19 +332,19 @@ pub type HourInner = u8;
pub type MinuteInner = u8;
#[derive(Debug, Clone)]
pub struct Year(YearInner);
pub struct Year(pub YearInner);
#[derive(Debug, Clone)]
pub struct Month(MonthInner);
pub struct Month(pub MonthInner);
#[derive(Debug, Clone)]
pub struct DayOfMonth(DayOfMonthInner);
pub struct DayOfMonth(pub DayOfMonthInner);
#[derive(Debug, Clone)]
pub struct Hour(HourInner);
pub struct Hour(pub HourInner);
#[derive(Debug, Clone)]
pub struct Minute(MinuteInner);
pub struct Minute(pub MinuteInner);
impl Year {
// TODO: Make a real error type instead of a boxed any error.

191
src/util/cli.rs Normal file
View File

@@ -0,0 +1,191 @@
use std::path::Path;
use tokio::process::Command;
use crate::settings::GlobalSettings;
use crate::settings::HeadlineLevelFilter;
pub async fn print_versions() -> Result<(), Box<dyn std::error::Error>> {
eprintln!("Using emacs version: {}", get_emacs_version().await?.trim());
eprintln!(
"Using org-mode version: {}",
get_org_mode_version().await?.trim()
);
Ok(())
}
pub(crate) async fn get_emacs_version() -> Result<String, Box<dyn std::error::Error>> {
let elisp_script = r#"(progn
(message "%s" (version))
)"#;
let mut cmd = Command::new("emacs");
let cmd = cmd
.arg("-q")
.arg("--no-site-file")
.arg("--no-splash")
.arg("--batch")
.arg("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
out.status.exit_ok()?;
Ok(String::from_utf8(out.stderr)?)
}
pub(crate) async fn get_org_mode_version() -> Result<String, Box<dyn std::error::Error>> {
let elisp_script = r#"(progn
(org-mode)
(message "%s" (org-version nil t nil))
)"#;
let mut cmd = Command::new("emacs");
let cmd = cmd
.arg("-q")
.arg("--no-site-file")
.arg("--no-splash")
.arg("--batch")
.arg("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
out.status.exit_ok()?;
Ok(String::from_utf8(out.stderr)?)
}
pub(crate) async fn emacs_parse_anonymous_org_document<'g, 's, C>(
file_contents: C,
global_settings: &GlobalSettings<'g, 's>,
) -> Result<String, Box<dyn std::error::Error>>
where
C: AsRef<str>,
{
let escaped_file_contents = escape_elisp_string(file_contents);
let elisp_script = format!(
r#"(progn
(erase-buffer)
(require 'org)
(defun org-table-align () t)
(insert "{escaped_file_contents}")
{global_settings}
(org-mode)
(message "%s" (pp-to-string (org-element-parse-buffer)))
)"#,
escaped_file_contents = escaped_file_contents,
global_settings = global_settings_elisp(global_settings)
);
let mut cmd = Command::new("emacs");
let cmd = cmd
.arg("-q")
.arg("--no-site-file")
.arg("--no-splash")
.arg("--batch")
.arg("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
let status = out.status.exit_ok();
if status.is_err() {
eprintln!(
"Emacs errored out: {}\n{}",
String::from_utf8(out.stdout)?,
String::from_utf8(out.stderr)?
);
status?;
unreachable!();
}
let org_sexp = out.stderr;
Ok(String::from_utf8(org_sexp)?)
}
pub(crate) async fn emacs_parse_file_org_document<'g, 's, P>(
file_path: P,
global_settings: &GlobalSettings<'g, 's>,
) -> 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
(require 'org)
(defun org-table-align () t)
(setq vc-handled-backends nil)
{global_settings}
(find-file-read-only "{file_path}")
(org-mode)
(message "%s" (pp-to-string (org-element-parse-buffer)))
)"#,
global_settings = global_settings_elisp(global_settings),
file_path = file_path
.as_os_str()
.to_str()
.expect("File name should be valid utf-8.")
);
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("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
let status = out.status.exit_ok();
if status.is_err() {
eprintln!(
"Emacs errored out: {}\n{}",
String::from_utf8(out.stdout)?,
String::from_utf8(out.stderr)?
);
status?;
unreachable!();
}
let org_sexp = out.stderr;
Ok(String::from_utf8(org_sexp)?)
}
fn escape_elisp_string<C>(file_contents: C) -> String
where
C: AsRef<str>,
{
let source = file_contents.as_ref();
let source_len = source.len();
// We allocate a string 10% larger than the source to account for escape characters. Without this, we would have more allocations during processing.
let mut output = String::with_capacity(source_len + (source_len / 10));
for c in source.chars() {
match c {
'"' | '\\' => {
output.push('\\');
output.push(c);
}
_ => {
output.push(c);
}
}
}
output
}
/// Generate elisp to configure org-mode parsing settings
///
/// Currently only org-list-allow-alphabetical is supported.
fn global_settings_elisp(global_settings: &GlobalSettings) -> String {
// This string concatenation is wildly inefficient but its only called in tests 🤷.
let mut ret = "".to_owned();
if global_settings.list_allow_alphabetical {
ret += "(setq org-list-allow-alphabetical t)\n"
}
if global_settings.tab_width != crate::settings::DEFAULT_TAB_WIDTH {
ret += format!("(setq-default tab-width {})", global_settings.tab_width).as_str();
}
if global_settings.odd_levels_only != HeadlineLevelFilter::default() {
ret += match global_settings.odd_levels_only {
HeadlineLevelFilter::Odd => "(setq org-odd-levels-only t)\n",
HeadlineLevelFilter::OddEven => "(setq org-odd-levels-only nil)\n",
};
}
ret
}

14
src/util/elisp/mod.rs Normal file
View File

@@ -0,0 +1,14 @@
mod sexp;
mod util;
pub use sexp::sexp;
pub(crate) use sexp::unquote;
#[cfg(feature = "wasm_test")]
pub(crate) use sexp::TextWithProperties;
pub use sexp::Token;
#[cfg(feature = "compare")]
pub(crate) use util::get_emacs_standard_properties;
#[cfg(feature = "wasm_test")]
pub(crate) use util::maybe_token_to_usize;
#[cfg(feature = "wasm_test")]
pub(crate) use util::EmacsStandardProperties;

View File

@@ -61,6 +61,7 @@ impl<'s> Token<'s> {
}?)
}
#[cfg(feature = "compare")]
pub(crate) fn as_text<'p>(
&'p self,
) -> Result<&'p TextWithProperties<'s>, Box<dyn std::error::Error>> {

76
src/util/elisp/util.rs Normal file
View File

@@ -0,0 +1,76 @@
use super::Token;
pub(crate) fn maybe_token_to_usize(
token: Option<&Token<'_>>,
) -> Result<Option<usize>, Box<dyn std::error::Error>> {
Ok(token
.map(|token| token.as_atom())
.map_or(Ok(None), |r| r.map(Some))?
.and_then(|val| {
if val == "nil" {
None
} else {
Some(val.parse::<usize>())
}
})
.map_or(Ok(None), |r| r.map(Some))?)
}
pub(crate) struct EmacsStandardProperties {
pub(crate) begin: Option<usize>,
#[allow(dead_code)]
pub(crate) post_affiliated: Option<usize>,
#[allow(dead_code)]
pub(crate) contents_begin: Option<usize>,
#[allow(dead_code)]
pub(crate) contents_end: Option<usize>,
pub(crate) end: Option<usize>,
#[allow(dead_code)]
pub(crate) post_blank: Option<usize>,
}
#[cfg(feature = "compare")]
pub(crate) fn get_emacs_standard_properties(
emacs: &Token<'_>,
) -> Result<EmacsStandardProperties, Box<dyn std::error::Error>> {
let children = emacs.as_list()?;
let attributes_child = children.get(1).ok_or("Should have an attributes child.")?;
let attributes_map = attributes_child.as_map()?;
let standard_properties = attributes_map.get(":standard-properties");
Ok(if standard_properties.is_some() {
let mut std_props = standard_properties
.expect("if statement proves its Some")
.as_vector()?
.iter();
let begin = maybe_token_to_usize(std_props.next())?;
let post_affiliated = maybe_token_to_usize(std_props.next())?;
let contents_begin = maybe_token_to_usize(std_props.next())?;
let contents_end = maybe_token_to_usize(std_props.next())?;
let end = maybe_token_to_usize(std_props.next())?;
let post_blank = maybe_token_to_usize(std_props.next())?;
EmacsStandardProperties {
begin,
post_affiliated,
contents_begin,
contents_end,
end,
post_blank,
}
} else {
let begin = maybe_token_to_usize(attributes_map.get(":begin").copied())?;
let end = maybe_token_to_usize(attributes_map.get(":end").copied())?;
let contents_begin = maybe_token_to_usize(attributes_map.get(":contents-begin").copied())?;
let contents_end = maybe_token_to_usize(attributes_map.get(":contents-end").copied())?;
let post_blank = maybe_token_to_usize(attributes_map.get(":post-blank").copied())?;
let post_affiliated =
maybe_token_to_usize(attributes_map.get(":post-affiliated").copied())?;
EmacsStandardProperties {
begin,
post_affiliated,
contents_begin,
contents_end,
end,
post_blank,
}
})
}

View File

@@ -1,233 +1,8 @@
use std::borrow::Cow;
use std::path::Path;
use tokio::process::Command;
use crate::settings::GlobalSettings;
use crate::settings::HeadlineLevelFilter;
pub async fn print_versions() -> Result<(), Box<dyn std::error::Error>> {
eprintln!("Using emacs version: {}", get_emacs_version().await?.trim());
eprintln!(
"Using org-mode version: {}",
get_org_mode_version().await?.trim()
);
Ok(())
}
pub(crate) async fn get_emacs_version() -> Result<String, Box<dyn std::error::Error>> {
let elisp_script = r#"(progn
(message "%s" (version))
)"#;
let mut cmd = Command::new("emacs");
let cmd = cmd
.arg("-q")
.arg("--no-site-file")
.arg("--no-splash")
.arg("--batch")
.arg("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
out.status.exit_ok()?;
Ok(String::from_utf8(out.stderr)?)
}
pub(crate) async fn get_org_mode_version() -> Result<String, Box<dyn std::error::Error>> {
let elisp_script = r#"(progn
(org-mode)
(message "%s" (org-version nil t nil))
)"#;
let mut cmd = Command::new("emacs");
let cmd = cmd
.arg("-q")
.arg("--no-site-file")
.arg("--no-splash")
.arg("--batch")
.arg("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
out.status.exit_ok()?;
Ok(String::from_utf8(out.stderr)?)
}
pub(crate) async fn emacs_parse_anonymous_org_document<'g, 's, C>(
file_contents: C,
global_settings: &GlobalSettings<'g, 's>,
) -> Result<String, Box<dyn std::error::Error>>
where
C: AsRef<str>,
{
let escaped_file_contents = escape_elisp_string(file_contents);
let elisp_script = format!(
r#"(progn
(erase-buffer)
(require 'org)
(defun org-table-align () t)
(insert "{escaped_file_contents}")
{global_settings}
(org-mode)
(message "%s" (pp-to-string (org-element-parse-buffer)))
)"#,
escaped_file_contents = escaped_file_contents,
global_settings = global_settings_elisp(global_settings)
);
let mut cmd = Command::new("emacs");
let cmd = cmd
.arg("-q")
.arg("--no-site-file")
.arg("--no-splash")
.arg("--batch")
.arg("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
let status = out.status.exit_ok();
if status.is_err() {
eprintln!(
"Emacs errored out: {}\n{}",
String::from_utf8(out.stdout)?,
String::from_utf8(out.stderr)?
);
status?;
unreachable!();
}
let org_sexp = out.stderr;
Ok(String::from_utf8(org_sexp)?)
}
pub(crate) async fn emacs_parse_file_org_document<'g, 's, P>(
file_path: P,
global_settings: &GlobalSettings<'g, 's>,
) -> 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
(require 'org)
(defun org-table-align () t)
(setq vc-handled-backends nil)
{global_settings}
(find-file-read-only "{file_path}")
(org-mode)
(message "%s" (pp-to-string (org-element-parse-buffer)))
)"#,
global_settings = global_settings_elisp(global_settings),
file_path = file_path
.as_os_str()
.to_str()
.expect("File name should be valid utf-8.")
);
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("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
let status = out.status.exit_ok();
if status.is_err() {
eprintln!(
"Emacs errored out: {}\n{}",
String::from_utf8(out.stdout)?,
String::from_utf8(out.stderr)?
);
status?;
unreachable!();
}
let org_sexp = out.stderr;
Ok(String::from_utf8(org_sexp)?)
}
fn escape_elisp_string<C>(file_contents: C) -> String
where
C: AsRef<str>,
{
let source = file_contents.as_ref();
let source_len = source.len();
// We allocate a string 10% larger than the source to account for escape characters. Without this, we would have more allocations during processing.
let mut output = String::with_capacity(source_len + (source_len / 10));
for c in source.chars() {
match c {
'"' | '\\' => {
output.push('\\');
output.push(c);
}
_ => {
output.push(c);
}
}
}
output
}
/// Generate elisp to configure org-mode parsing settings
///
/// Currently only org-list-allow-alphabetical is supported.
fn global_settings_elisp(global_settings: &GlobalSettings) -> String {
// This string concatenation is wildly inefficient but its only called in tests 🤷.
let mut ret = "".to_owned();
if global_settings.list_allow_alphabetical {
ret += "(setq org-list-allow-alphabetical t)\n"
}
if global_settings.tab_width != crate::settings::DEFAULT_TAB_WIDTH {
ret += format!("(setq-default tab-width {})", global_settings.tab_width).as_str();
}
if global_settings.odd_levels_only != HeadlineLevelFilter::default() {
ret += match global_settings.odd_levels_only {
HeadlineLevelFilter::Odd => "(setq org-odd-levels-only t)\n",
HeadlineLevelFilter::OddEven => "(setq org-odd-levels-only nil)\n",
};
}
ret
}
fn should_use_color() -> bool {
!std::env::var("NO_COLOR").is_ok_and(|val| !val.is_empty())
}
pub(crate) fn foreground_color(red: u8, green: u8, blue: u8) -> Cow<'static, str> {
if should_use_color() {
format!(
"\x1b[38;2;{red};{green};{blue}m",
red = red,
green = green,
blue = blue
)
.into()
} else {
Cow::from("")
}
}
#[allow(dead_code)]
pub(crate) fn background_color(red: u8, green: u8, blue: u8) -> Cow<'static, str> {
if should_use_color() {
format!(
"\x1b[48;2;{red};{green};{blue}m",
red = red,
green = green,
blue = blue
)
.into()
} else {
Cow::from("")
}
}
pub(crate) fn reset_color() -> &'static str {
if should_use_color() {
"\x1b[0m"
} else {
""
}
}
#[cfg(any(feature = "compare", feature = "wasm_test"))]
pub mod cli;
#[cfg(any(feature = "compare", feature = "wasm_test"))]
pub mod elisp;
#[cfg(any(feature = "compare", feature = "wasm", feature = "wasm_test"))]
pub mod elisp_fact;
#[cfg(any(feature = "compare", feature = "wasm_test"))]
pub mod terminal;

42
src/util/terminal.rs Normal file
View File

@@ -0,0 +1,42 @@
use std::borrow::Cow;
fn should_use_color() -> bool {
!std::env::var("NO_COLOR").is_ok_and(|val| !val.is_empty())
}
pub(crate) fn foreground_color(red: u8, green: u8, blue: u8) -> Cow<'static, str> {
if should_use_color() {
format!(
"\x1b[38;2;{red};{green};{blue}m",
red = red,
green = green,
blue = blue
)
.into()
} else {
Cow::from("")
}
}
#[allow(dead_code)]
pub(crate) fn background_color(red: u8, green: u8, blue: u8) -> Cow<'static, str> {
if should_use_color() {
format!(
"\x1b[48;2;{red};{green};{blue}m",
red = red,
green = green,
blue = blue
)
.into()
} else {
Cow::from("")
}
}
pub(crate) fn reset_color() -> &'static str {
if should_use_color() {
"\x1b[0m"
} else {
""
}
}

View File

@@ -1,27 +1,95 @@
use std::collections::HashMap;
use serde::Deserialize;
use serde::Serialize;
use super::macros::to_wasm;
use super::to_wasm::ToWasm;
use super::WasmAstNode;
use crate::types::AffiliatedKeywordValue;
use crate::types::AffiliatedKeywords;
#[derive(Debug, Serialize)]
pub enum AdditionalPropertyValue<'s, 'p> {
SingleString(&'s str),
ListOfStrings(Vec<&'s str>),
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum AdditionalPropertyValue {
SingleString(String),
ListOfStrings(Vec<String>),
OptionalPair {
optval: Option<&'s str>,
val: &'s str,
optval: Option<String>,
val: String,
},
ObjectTree {
#[serde(rename = "object-tree")]
object_tree: Vec<(Option<Vec<WasmAstNode>>, Vec<WasmAstNode>)>,
},
ObjectTree(Vec<(Option<Vec<WasmAstNode<'s, 'p>>>, Vec<WasmAstNode<'s, 'p>>)>),
}
#[derive(Debug, Serialize, Default)]
pub struct AdditionalProperties<'s, 'p> {
pub(crate) properties: HashMap<String, AdditionalPropertyValue<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct AdditionalProperties {
#[serde(flatten)]
pub(crate) properties: HashMap<String, AdditionalPropertyValue>,
}
impl<'s, 'p> AdditionalProperties<'s, 'p> {
pub(crate) fn get_elisp_names<'c>(&'c self) -> impl Iterator<Item = String> + 'c {
self.properties.keys().map(move |key| format!(":{}", key))
to_wasm!(
AdditionalProperties,
AffiliatedKeywords<'s>,
original,
wasm_context,
{
let mut additional_properties = AdditionalProperties::default();
for (name, val) in original.keywords.iter() {
let converted_val = match val {
AffiliatedKeywordValue::SingleString(val) => {
AdditionalPropertyValue::SingleString((*val).to_owned())
}
AffiliatedKeywordValue::ListOfStrings(val) => {
AdditionalPropertyValue::ListOfStrings(
val.iter().map(|s| (*s).to_owned()).collect(),
)
}
AffiliatedKeywordValue::OptionalPair { optval, val } => {
AdditionalPropertyValue::OptionalPair {
optval: optval.map(|s| (*s).to_owned()),
val: (*val).to_owned(),
}
}
AffiliatedKeywordValue::ObjectTree(val) => {
let mut ret = Vec::with_capacity(val.len());
for (optval, value) in val {
let converted_optval = if let Some(optval) = optval {
Some(
optval
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?,
)
} else {
None
};
let converted_value = value
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
ret.push((converted_optval, converted_value));
}
AdditionalPropertyValue::ObjectTree { object_tree: ret }
}
};
additional_properties
.properties
.insert(name.clone(), converted_val);
}
Ok(additional_properties)
}
}
);

View File

@@ -1,30 +1,54 @@
use std::borrow::Cow;
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::AngleLink;
use crate::types::LinkType;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmAngleLink<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "format")]
#[serde(rename = "angle")]
pub struct WasmAngleLink {
#[serde(rename = "type")]
pub(crate) link_type: String,
pub(crate) path: String,
#[serde(rename = "raw-link")]
pub(crate) raw_link: String,
pub(crate) application: Option<String>,
#[serde(rename = "search-option")]
pub(crate) search_option: Option<String>,
}
to_wasm!(
WasmAngleLink<'s, 'p>,
WasmAngleLink,
AngleLink<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::AngleLink(original) },
{ "link".into() },
{
Ok(WasmAngleLink {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmAngleLink {
link_type: match &original.link_type {
LinkType::File => "file".to_owned(),
LinkType::Protocol(protocol) => protocol.clone().into_owned(),
LinkType::Id => "id".to_owned(),
LinkType::CustomId => "custom-id".to_owned(),
LinkType::CodeRef => "coderef".to_owned(),
LinkType::Fuzzy => "fuzzy".to_owned(),
},
path: original.get_path().into_owned(),
raw_link: original.raw_link.to_owned(),
application: original.application.map(|c| c.to_owned()),
search_option: original.get_search_option().map(Cow::into_owned),
},
))
}
);

View File

@@ -1,3 +1,4 @@
use serde::Deserialize;
use serde::Serialize;
use super::angle_link::WasmAngleLink;
@@ -58,71 +59,84 @@ use super::timestamp::WasmTimestamp;
use super::underline::WasmUnderline;
use super::verbatim::WasmVerbatim;
use super::verse_block::WasmVerseBlock;
use super::WasmStandardProperties;
#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum WasmAstNode<'s, 'p> {
// Document Nodes
Document(WasmDocument<'s, 'p>),
Headline(WasmHeadline<'s, 'p>),
Section(WasmSection<'s, 'p>),
// Elements
Paragraph(WasmParagraph<'s, 'p>),
PlainList(WasmPlainList<'s, 'p>),
PlainListItem(WasmPlainListItem<'s, 'p>),
CenterBlock(WasmCenterBlock<'s, 'p>),
QuoteBlock(WasmQuoteBlock<'s, 'p>),
SpecialBlock(WasmSpecialBlock<'s, 'p>),
DynamicBlock(WasmDynamicBlock<'s, 'p>),
FootnoteDefinition(WasmFootnoteDefinition<'s, 'p>),
Comment(WasmComment<'s, 'p>),
Drawer(WasmDrawer<'s, 'p>),
PropertyDrawer(WasmPropertyDrawer<'s, 'p>),
NodeProperty(WasmNodeProperty<'s, 'p>),
Table(WasmTable<'s, 'p>),
TableRow(WasmTableRow<'s, 'p>),
VerseBlock(WasmVerseBlock<'s, 'p>),
CommentBlock(WasmCommentBlock<'s, 'p>),
ExampleBlock(WasmExampleBlock<'s, 'p>),
ExportBlock(WasmExportBlock<'s, 'p>),
SrcBlock(WasmSrcBlock<'s, 'p>),
Clock(WasmClock<'s, 'p>),
DiarySexp(WasmDiarySexp<'s, 'p>),
Planning(WasmPlanning<'s, 'p>),
FixedWidthArea(WasmFixedWidthArea<'s, 'p>),
HorizontalRule(WasmHorizontalRule<'s, 'p>),
Keyword(WasmKeyword<'s, 'p>),
BabelCall(WasmBabelCall<'s, 'p>),
LatexEnvironment(WasmLatexEnvironment<'s, 'p>),
// Objects
Bold(WasmBold<'s, 'p>),
Italic(WasmItalic<'s, 'p>),
Underline(WasmUnderline<'s, 'p>),
StrikeThrough(WasmStrikeThrough<'s, 'p>),
Code(WasmCode<'s, 'p>),
Verbatim(WasmVerbatim<'s, 'p>),
PlainText(WasmPlainText<'s, 'p>),
RegularLink(WasmRegularLink<'s, 'p>),
RadioLink(WasmRadioLink<'s, 'p>),
RadioTarget(WasmRadioTarget<'s, 'p>),
PlainLink(WasmPlainLink<'s, 'p>),
AngleLink(WasmAngleLink<'s, 'p>),
OrgMacro(WasmOrgMacro<'s, 'p>),
Entity(WasmEntity<'s, 'p>),
LatexFragment(WasmLatexFragment<'s, 'p>),
ExportSnippet(WasmExportSnippet<'s, 'p>),
FootnoteReference(WasmFootnoteReference<'s, 'p>),
Citation(WasmCitation<'s, 'p>),
CitationReference(WasmCitationReference<'s, 'p>),
InlineBabelCall(WasmInlineBabelCall<'s, 'p>),
InlineSourceBlock(WasmInlineSourceBlock<'s, 'p>),
LineBreak(WasmLineBreak<'s, 'p>),
Target(WasmTarget<'s, 'p>),
StatisticsCookie(WasmStatisticsCookie<'s, 'p>),
Subscript(WasmSubscript<'s, 'p>),
Superscript(WasmSuperscript<'s, 'p>),
TableCell(WasmTableCell<'s, 'p>),
Timestamp(WasmTimestamp<'s, 'p>),
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmAstNodeWrapper<I> {
#[serde(rename = "ast-node")]
pub(crate) ast_node: String,
#[serde(rename = "standard-properties")]
pub(crate) standard_properties: WasmStandardProperties,
#[serde(rename = "children")]
pub(crate) children: Vec<WasmAstNode>,
#[serde(rename = "properties")]
pub(crate) properties: I,
}
impl<'s, 'p> WasmAstNode<'s, 'p> {}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum WasmAstNode {
// Document Nodes
Document(WasmAstNodeWrapper<WasmDocument>),
Headline(WasmAstNodeWrapper<WasmHeadline>),
Section(WasmAstNodeWrapper<WasmSection>),
// Elements
Paragraph(WasmAstNodeWrapper<WasmParagraph>),
PlainList(WasmAstNodeWrapper<WasmPlainList>),
PlainListItem(WasmAstNodeWrapper<WasmPlainListItem>),
CenterBlock(WasmAstNodeWrapper<WasmCenterBlock>),
QuoteBlock(WasmAstNodeWrapper<WasmQuoteBlock>),
SpecialBlock(WasmAstNodeWrapper<WasmSpecialBlock>),
DynamicBlock(WasmAstNodeWrapper<WasmDynamicBlock>),
FootnoteDefinition(WasmAstNodeWrapper<WasmFootnoteDefinition>),
Comment(WasmAstNodeWrapper<WasmComment>),
Drawer(WasmAstNodeWrapper<WasmDrawer>),
PropertyDrawer(WasmAstNodeWrapper<WasmPropertyDrawer>),
NodeProperty(WasmAstNodeWrapper<WasmNodeProperty>),
Table(WasmAstNodeWrapper<WasmTable>),
TableRow(WasmAstNodeWrapper<WasmTableRow>),
VerseBlock(WasmAstNodeWrapper<WasmVerseBlock>),
CommentBlock(WasmAstNodeWrapper<WasmCommentBlock>),
ExampleBlock(WasmAstNodeWrapper<WasmExampleBlock>),
ExportBlock(WasmAstNodeWrapper<WasmExportBlock>),
SrcBlock(WasmAstNodeWrapper<WasmSrcBlock>),
Clock(WasmAstNodeWrapper<WasmClock>),
DiarySexp(WasmAstNodeWrapper<WasmDiarySexp>),
Planning(WasmAstNodeWrapper<WasmPlanning>),
FixedWidthArea(WasmAstNodeWrapper<WasmFixedWidthArea>),
HorizontalRule(WasmAstNodeWrapper<WasmHorizontalRule>),
Keyword(WasmAstNodeWrapper<WasmKeyword>),
BabelCall(WasmAstNodeWrapper<WasmBabelCall>),
LatexEnvironment(WasmAstNodeWrapper<WasmLatexEnvironment>),
// Objects
Bold(WasmAstNodeWrapper<WasmBold>),
Italic(WasmAstNodeWrapper<WasmItalic>),
Underline(WasmAstNodeWrapper<WasmUnderline>),
StrikeThrough(WasmAstNodeWrapper<WasmStrikeThrough>),
Code(WasmAstNodeWrapper<WasmCode>),
Verbatim(WasmAstNodeWrapper<WasmVerbatim>),
PlainText(WasmAstNodeWrapper<WasmPlainText>),
RegularLink(WasmAstNodeWrapper<WasmRegularLink>),
RadioLink(WasmAstNodeWrapper<WasmRadioLink>),
RadioTarget(WasmAstNodeWrapper<WasmRadioTarget>),
PlainLink(WasmAstNodeWrapper<WasmPlainLink>),
AngleLink(WasmAstNodeWrapper<WasmAngleLink>),
OrgMacro(WasmAstNodeWrapper<WasmOrgMacro>),
Entity(WasmAstNodeWrapper<WasmEntity>),
LatexFragment(WasmAstNodeWrapper<WasmLatexFragment>),
ExportSnippet(WasmAstNodeWrapper<WasmExportSnippet>),
FootnoteReference(WasmAstNodeWrapper<WasmFootnoteReference>),
Citation(WasmAstNodeWrapper<WasmCitation>),
CitationReference(WasmAstNodeWrapper<WasmCitationReference>),
InlineBabelCall(WasmAstNodeWrapper<WasmInlineBabelCall>),
InlineSourceBlock(WasmAstNodeWrapper<WasmInlineSourceBlock>),
LineBreak(WasmAstNodeWrapper<WasmLineBreak>),
Target(WasmAstNodeWrapper<WasmTarget>),
StatisticsCookie(WasmAstNodeWrapper<WasmStatisticsCookie>),
Subscript(WasmAstNodeWrapper<WasmSubscript>),
Superscript(WasmAstNodeWrapper<WasmSuperscript>),
TableCell(WasmAstNodeWrapper<WasmTableCell>),
Timestamp(WasmAstNodeWrapper<WasmTimestamp>),
}
impl WasmAstNode {}

View File

@@ -1,30 +1,50 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::BabelCall;
use crate::types::GetAffiliatedKeywords;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmBabelCall<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmBabelCall {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
pub(crate) call: Option<String>,
#[serde(rename = "inside-header")]
pub(crate) inside_header: Option<String>,
pub(crate) arguments: Option<String>,
#[serde(rename = "end-header")]
pub(crate) end_header: Option<String>,
pub(crate) value: String,
}
to_wasm!(
WasmBabelCall<'s, 'p>,
WasmBabelCall,
BabelCall<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::BabelCall(original) },
{ "babel-call".into() },
{
Ok(WasmBabelCall {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
Ok((
Vec::new(),
WasmBabelCall {
additional_properties,
call: original.call.map(|s| s.to_owned()),
inside_header: original.inside_header.map(|s| s.to_owned()),
arguments: original.arguments.map(|s| s.to_owned()),
end_header: original.end_header.map(|s| s.to_owned()),
value: original.value.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,34 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Bold;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmBold<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmBold {}
to_wasm!(
WasmBold<'s, 'p>,
WasmBold,
Bold<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Bold(original) },
{ "bold".into() },
{
Ok(WasmBold {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((children, WasmBold {}))
}
);

View File

@@ -1,30 +1,48 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::CenterBlock;
use crate::types::GetAffiliatedKeywords;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmCenterBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmCenterBlock {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
}
to_wasm!(
WasmCenterBlock<'s, 'p>,
WasmCenterBlock,
CenterBlock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::CenterBlock(original) },
{ "center-block".into() },
{
Ok(WasmCenterBlock {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmCenterBlock {
additional_properties,
},
))
}
);

View File

@@ -1,30 +1,71 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Citation;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmCitation<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmCitation {
pub(crate) style: Option<String>,
pub(crate) prefix: Option<Vec<WasmAstNode>>,
pub(crate) suffix: Option<Vec<WasmAstNode>>,
}
to_wasm!(
WasmCitation<'s, 'p>,
WasmCitation,
Citation<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Citation(original) },
{ "citation".into() },
{
Ok(WasmCitation {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
let prefix = original
.prefix
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
let suffix = original
.suffix
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmCitation {
style: original.style.map(|s| s.to_owned()),
prefix: if prefix.is_empty() {
None
} else {
Some(prefix)
},
suffix: if suffix.is_empty() {
None
} else {
Some(suffix)
},
},
))
}
);

View File

@@ -1,30 +1,62 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::CitationReference;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmCitationReference<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmCitationReference {
pub(crate) key: String,
pub(crate) prefix: Option<Vec<WasmAstNode>>,
pub(crate) suffix: Option<Vec<WasmAstNode>>,
}
to_wasm!(
WasmCitationReference<'s, 'p>,
WasmCitationReference,
CitationReference<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::CitationReference(original) },
{ "citation-reference".into() },
{
Ok(WasmCitationReference {
standard_properties,
children: Vec::new(),
})
let prefix = original
.prefix
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
let suffix = original
.suffix
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
Vec::new(),
WasmCitationReference {
key: original.key.to_owned(),
prefix: if prefix.is_empty() {
None
} else {
Some(prefix)
},
suffix: if suffix.is_empty() {
None
} else {
Some(suffix)
},
},
))
}
);

View File

@@ -1,30 +1,43 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Clock;
use crate::types::ClockStatus;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmClock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmClock {
#[serde(rename = "value")]
pub(crate) timestamp: Box<WasmAstNode>,
pub(crate) duration: Option<String>,
pub(crate) status: String,
}
to_wasm!(
WasmClock<'s, 'p>,
WasmClock,
Clock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Clock(original) },
{ "clock".into() },
{
Ok(WasmClock {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmClock {
timestamp: Box::new(Into::<WasmAstNode>::into(
original.timestamp.to_wasm(wasm_context.clone())?,
)),
duration: original.duration.map(|s| s.to_owned()),
status: match original.status {
ClockStatus::Running => "running",
ClockStatus::Closed => "closed",
}
.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,31 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Code;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmCode<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmCode {
pub(crate) value: String,
}
to_wasm!(
WasmCode<'s, 'p>,
WasmCode,
Code<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Code(original) },
{ "code".into() },
{
Ok(WasmCode {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmCode {
value: original.contents.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,31 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Comment;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmComment<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmComment {
pub(crate) value: String,
}
to_wasm!(
WasmComment<'s, 'p>,
WasmComment,
Comment<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Comment(original) },
{ "comment".into() },
{
Ok(WasmComment {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmComment {
value: original.get_value(),
},
))
}
);

View File

@@ -1,30 +1,40 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::CommentBlock;
use crate::types::GetAffiliatedKeywords;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmCommentBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmCommentBlock {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
pub(crate) value: String,
}
to_wasm!(
WasmCommentBlock<'s, 'p>,
WasmCommentBlock,
CommentBlock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::CommentBlock(original) },
{ "comment-block".into() },
{
Ok(WasmCommentBlock {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
Ok((
Vec::new(),
WasmCommentBlock {
additional_properties,
value: original.contents.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,40 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::DiarySexp;
use crate::types::GetAffiliatedKeywords;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmDiarySexp<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmDiarySexp {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
pub(crate) value: String,
}
to_wasm!(
WasmDiarySexp<'s, 'p>,
WasmDiarySexp,
DiarySexp<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::DiarySexp(original) },
{ "diary-sexp".into() },
{
Ok(WasmDiarySexp {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
Ok((
Vec::new(),
WasmDiarySexp {
additional_properties,
value: original.value.to_owned(),
},
))
}
);

View File

@@ -1,44 +1,42 @@
use std::path::PathBuf;
use serde::Deserialize;
use serde::Serialize;
use super::additional_property::AdditionalProperties;
use super::additional_property::AdditionalPropertyValue;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
#[cfg(feature = "wasm_test")]
use crate::compare::ElispFact;
use crate::types::Document;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmDocument<'s, 'p> {
pub(crate) standard_properties: WasmStandardProperties,
pub(crate) additional_properties: AdditionalProperties<'s, 'p>,
pub(crate) children: Vec<WasmAstNode<'s, 'p>>,
pub(crate) category: Option<&'p str>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmDocument {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
#[serde(rename = "CATEGORY")]
pub(crate) category: Option<String>,
pub(crate) path: Option<PathBuf>,
}
to_wasm!(
WasmDocument<'s, 'p>,
WasmDocument,
Document<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Document(original) },
{ "org-data".into() },
{
let category = original.category.as_ref().map(String::as_str);
let category = original.category.as_deref();
let path = original.path.clone();
let mut additional_properties = AdditionalProperties::default();
for (name, val) in original.get_additional_properties().map(|node_property| {
(
node_property.property_name.to_uppercase(),
AdditionalPropertyValue::SingleString(node_property.value.unwrap_or("")),
AdditionalPropertyValue::SingleString(node_property.value.unwrap_or("").to_owned()),
)
}) {
additional_properties.properties.insert(name, val);
@@ -50,34 +48,22 @@ to_wasm!(
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode<'_, '_>>::into)
.map(Into::<WasmAstNode>::into)
})
.chain(original.children.iter().map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode<'_, '_>>::into)
.map(Into::<WasmAstNode>::into)
}))
.collect::<Result<Vec<_>, _>>()?;
Ok(WasmDocument {
standard_properties,
additional_properties,
Ok((
children,
category,
path,
})
WasmDocument {
additional_properties,
category: category.map(str::to_owned),
path,
},
))
}
);
impl<'s, 'p> Into<WasmAstNode<'s, 'p>> for WasmDocument<'s, 'p> {
fn into(self) -> WasmAstNode<'s, 'p> {
WasmAstNode::Document(self)
}
}
#[cfg(feature = "wasm_test")]
impl<'s, 'p> ElispFact<'s> for WasmDocument<'s, 'p> {
fn get_elisp_name<'b>(&'b self) -> std::borrow::Cow<'s, str> {
"org-data".into()
}
}

View File

@@ -1,30 +1,51 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::Drawer;
use crate::types::GetAffiliatedKeywords;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmDrawer<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmDrawer {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
#[serde(rename = "drawer-name")]
pub(crate) drawer_name: String,
}
to_wasm!(
WasmDrawer<'s, 'p>,
WasmDrawer,
Drawer<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Drawer(original) },
{ "drawer".into() },
{
Ok(WasmDrawer {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmDrawer {
additional_properties,
drawer_name: original.drawer_name.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,53 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::DynamicBlock;
use crate::types::GetAffiliatedKeywords;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmDynamicBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmDynamicBlock {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
#[serde(rename = "block-name")]
pub(crate) block_name: String,
pub(crate) arguments: Option<String>,
}
to_wasm!(
WasmDynamicBlock<'s, 'p>,
WasmDynamicBlock,
DynamicBlock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::DynamicBlock(original) },
{ "dynamic-block".into() },
{
Ok(WasmDynamicBlock {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmDynamicBlock {
additional_properties,
block_name: original.block_name.to_owned(),
arguments: original.parameters.map(|s| s.to_owned()),
},
))
}
);

View File

@@ -1,30 +1,49 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::headline::Noop;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Entity;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmEntity<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmEntity {
pub(crate) name: String,
pub(crate) latex: String,
#[serde(rename = "latex-math-p")]
pub(crate) latex_math_mode: bool,
pub(crate) html: String,
pub(crate) ascii: String,
pub(crate) latin1: Noop,
#[serde(rename = "utf-8")]
pub(crate) utf8: String,
#[serde(rename = "use-brackets-p")]
pub(crate) use_brackets: bool,
}
to_wasm!(
WasmEntity<'s, 'p>,
WasmEntity,
Entity<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Entity(original) },
{ "entity".into() },
{
Ok(WasmEntity {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmEntity {
name: original.name.to_owned(),
latex: original.latex.to_owned(),
latex_math_mode: original.latex_math_mode,
html: original.html.to_owned(),
ascii: original.ascii.to_owned(),
latin1: Noop {},
utf8: original.utf8.to_owned(),
use_brackets: original.use_brackets,
},
))
}
);

View File

@@ -1,30 +1,75 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::src_block::WasmNumberLines;
use super::src_block::WasmNumberLinesWrapper;
use super::src_block::WasmRetainLabels;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::CharOffsetInLine;
use crate::types::ExampleBlock;
use crate::types::GetAffiliatedKeywords;
use crate::types::RetainLabels;
use crate::types::SwitchNumberLines;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmExampleBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmExampleBlock {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
pub(crate) value: String,
pub(crate) switches: Option<String>,
#[serde(rename = "number-lines")]
pub(crate) number_lines: Option<WasmNumberLinesWrapper>,
#[serde(rename = "preserve-indent")]
pub(crate) preserve_indent: Option<CharOffsetInLine>,
#[serde(rename = "retain-labels")]
pub(crate) retain_labels: WasmRetainLabels,
#[serde(rename = "use-labels")]
pub(crate) use_labels: bool,
#[serde(rename = "label-fmt")]
pub(crate) label_format: Option<String>,
}
to_wasm!(
WasmExampleBlock<'s, 'p>,
WasmExampleBlock,
ExampleBlock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::ExampleBlock(original) },
{ "example-block".into() },
{
Ok(WasmExampleBlock {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
Ok((
Vec::new(),
WasmExampleBlock {
additional_properties,
value: original.get_value().into_owned(),
switches: original.switches.map(|s| s.to_owned()),
number_lines: match original.number_lines {
None => None,
Some(SwitchNumberLines::New(n)) => Some(WasmNumberLinesWrapper {
inner: WasmNumberLines::New(n),
}),
Some(SwitchNumberLines::Continued(n)) => Some(WasmNumberLinesWrapper {
inner: WasmNumberLines::Continued(n),
}),
},
preserve_indent: original.preserve_indent,
retain_labels: match original.retain_labels {
RetainLabels::No => WasmRetainLabels::YesNo(false),
RetainLabels::Yes => WasmRetainLabels::YesNo(true),
RetainLabels::Keep(n) => WasmRetainLabels::Keep(n),
},
use_labels: original.use_labels,
label_format: original.label_format.map(|s| s.to_owned()),
},
))
}
);

View File

@@ -1,30 +1,43 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::ExportBlock;
use crate::types::GetAffiliatedKeywords;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmExportBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmExportBlock {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
#[serde(rename = "type")]
pub(crate) export_type: Option<String>,
pub(crate) value: String,
}
to_wasm!(
WasmExportBlock<'s, 'p>,
WasmExportBlock,
ExportBlock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::ExportBlock(original) },
{ "export-block".into() },
{
Ok(WasmExportBlock {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
Ok((
Vec::new(),
WasmExportBlock {
additional_properties,
export_type: original.get_export_type(),
value: original.get_value().into_owned(),
},
))
}
);

View File

@@ -1,30 +1,34 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::ExportSnippet;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmExportSnippet<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmExportSnippet {
#[serde(rename = "back-end")]
pub(crate) backend: String,
pub(crate) value: Option<String>,
}
to_wasm!(
WasmExportSnippet<'s, 'p>,
WasmExportSnippet,
ExportSnippet<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::ExportSnippet(original) },
{ "export-snippet".into() },
{
Ok(WasmExportSnippet {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmExportSnippet {
backend: original.backend.to_owned(),
value: original.contents.map(|s| s.to_owned()),
},
))
}
);

View File

@@ -1,30 +1,42 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::FixedWidthArea;
use crate::types::GetAffiliatedKeywords;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmFixedWidthArea<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmFixedWidthArea {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
pub(crate) value: String,
}
to_wasm!(
WasmFixedWidthArea<'s, 'p>,
WasmFixedWidthArea,
FixedWidthArea<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::FixedWidthArea(original) },
{ "fixed-width".into() },
{
Ok(WasmFixedWidthArea {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let value = original.get_value();
Ok((
Vec::new(),
WasmFixedWidthArea {
additional_properties,
value,
},
))
}
);

View File

@@ -1,30 +1,54 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::headline::Noop;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::FootnoteDefinition;
use crate::types::GetAffiliatedKeywords;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmFootnoteDefinition<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmFootnoteDefinition {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
pub(crate) label: String,
#[serde(rename = "pre-blank")]
pub(crate) pre_blank: Noop,
}
to_wasm!(
WasmFootnoteDefinition<'s, 'p>,
WasmFootnoteDefinition,
FootnoteDefinition<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::FootnoteDefinition(original) },
{ "footnote-definition".into() },
{
Ok(WasmFootnoteDefinition {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmFootnoteDefinition {
additional_properties,
label: original.label.to_owned(),
pre_blank: Noop {},
},
))
}
);

View File

@@ -1,30 +1,49 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::FootnoteReference;
use crate::types::FootnoteReferenceType;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmFootnoteReference<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmFootnoteReference {
pub(crate) label: Option<String>,
#[serde(rename = "type")]
pub(crate) footnote_reference_type: String,
}
to_wasm!(
WasmFootnoteReference<'s, 'p>,
WasmFootnoteReference,
FootnoteReference<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::FootnoteReference(original) },
{ "footnote-reference".into() },
{
Ok(WasmFootnoteReference {
standard_properties,
children: Vec::new(),
})
let children = original
.definition
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmFootnoteReference {
label: original.label.map(|s| s.to_owned()),
footnote_reference_type: match original.get_type() {
FootnoteReferenceType::Standard => "standard",
FootnoteReferenceType::Inline => "inline",
}
.to_owned(),
},
))
}
);

View File

@@ -1,36 +1,140 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use super::AdditionalPropertyValue;
use crate::types::Heading;
use crate::types::HeadlineLevel;
use crate::types::PriorityCookie;
use crate::types::TodoKeywordType;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "headline")]
pub struct WasmHeadline<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmHeadline {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
pub(crate) level: HeadlineLevel,
pub(crate) tags: Vec<String>,
#[serde(rename = "todo-keyword")]
pub(crate) todo_keyword: Option<String>,
#[serde(rename = "todo-type")]
pub(crate) todo_type: Option<String>,
pub(crate) title: Vec<WasmAstNode>,
pub(crate) priority: Option<PriorityCookie>,
#[serde(rename = "archivedp")]
pub(crate) is_archived: bool,
#[serde(rename = "commentedp")]
pub(crate) is_comment: bool,
#[serde(rename = "raw-value")]
pub(crate) raw_value: String,
#[serde(rename = "footnote-section-p")]
pub(crate) is_footnote_section: bool,
pub(crate) scheduled: Option<Box<WasmAstNode>>,
pub(crate) deadline: Option<Box<WasmAstNode>>,
pub(crate) closed: Option<Box<WasmAstNode>>,
#[serde(rename = "pre-blank")]
pub(crate) pre_blank: Noop,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "noop")]
pub struct Noop {}
to_wasm!(
WasmHeadline<'s, 'p>,
WasmHeadline,
Heading<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Headline(original) },
{ "headline".into() },
{
Ok(WasmHeadline {
standard_properties,
children: Vec::new(),
})
let mut additional_properties = AdditionalProperties::default();
for (name, val) in original.get_additional_properties().map(|node_property| {
(
node_property.property_name.to_uppercase(),
AdditionalPropertyValue::SingleString(node_property.value.unwrap_or("").to_owned()),
)
}) {
additional_properties.properties.insert(name, val);
}
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmHeadline {
additional_properties,
level: original.level,
tags: original.tags.iter().map(|tag| (*tag).to_owned()).collect(),
todo_keyword: original
.todo_keyword
.as_ref()
.map(|(_, keyword)| (*keyword).to_owned()),
todo_type: original
.todo_keyword
.as_ref()
.map(|(keyword, _)| match keyword {
TodoKeywordType::Done => "done".to_owned(),
TodoKeywordType::Todo => "todo".to_owned(),
}),
title: original
.title
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?,
priority: original.priority_cookie,
is_archived: original.is_archived,
is_comment: original.is_comment,
raw_value: original.get_raw_value(),
is_footnote_section: original.is_footnote_section,
scheduled: original
.scheduled
.as_ref()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.map_or(Ok(None), |r| r.map(Some))?
.map(Box::new),
deadline: original
.deadline
.as_ref()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.map_or(Ok(None), |r| r.map(Some))?
.map(Box::new),
closed: original
.closed
.as_ref()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.map_or(Ok(None), |r| r.map(Some))?
.map(Box::new),
pre_blank: Noop {},
},
))
}
);
impl<'s, 'p> Into<WasmAstNode<'s, 'p>> for WasmHeadline<'s, 'p> {
fn into(self) -> WasmAstNode<'s, 'p> {
WasmAstNode::Headline(self)
}
}

View File

@@ -1,30 +1,38 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::GetAffiliatedKeywords;
use crate::types::HorizontalRule;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmHorizontalRule<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmHorizontalRule {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
}
to_wasm!(
WasmHorizontalRule<'s, 'p>,
WasmHorizontalRule,
HorizontalRule<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::HorizontalRule(original) },
{ "horizontal-rule".into() },
{
Ok(WasmHorizontalRule {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
Ok((
Vec::new(),
WasmHorizontalRule {
additional_properties,
},
))
}
);

View File

@@ -1,30 +1,41 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::InlineBabelCall;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmInlineBabelCall<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmInlineBabelCall {
pub(crate) call: String,
#[serde(rename = "inside-header")]
pub(crate) inside_header: Option<String>,
pub(crate) arguments: Option<String>,
#[serde(rename = "end-header")]
pub(crate) end_header: Option<String>,
pub(crate) value: String,
}
to_wasm!(
WasmInlineBabelCall<'s, 'p>,
WasmInlineBabelCall,
InlineBabelCall<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::InlineBabelCall(original) },
{ "inline-babel-call".into() },
{
Ok(WasmInlineBabelCall {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmInlineBabelCall {
call: original.call.to_owned(),
inside_header: original.inside_header.map(|s| s.to_owned()),
arguments: original.arguments.map(|s| s.to_owned()),
end_header: original.end_header.map(|s| s.to_owned()),
value: original.value.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,35 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::InlineSourceBlock;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmInlineSourceBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmInlineSourceBlock {
pub(crate) language: String,
pub(crate) value: String,
pub(crate) parameters: Option<String>,
}
to_wasm!(
WasmInlineSourceBlock<'s, 'p>,
WasmInlineSourceBlock,
InlineSourceBlock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::InlineSourceBlock(original) },
{ "inline-src-block".into() },
{
Ok(WasmInlineSourceBlock {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmInlineSourceBlock {
language: original.language.to_owned(),
value: original.value.to_owned(),
parameters: original.parameters.map(str::to_owned),
},
))
}
);

View File

@@ -1,30 +1,34 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Italic;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmItalic<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmItalic {}
to_wasm!(
WasmItalic<'s, 'p>,
WasmItalic,
Italic<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Italic(original) },
{ "italic".into() },
{
Ok(WasmItalic {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((children, WasmItalic {}))
}
);

View File

@@ -1,30 +1,42 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::GetAffiliatedKeywords;
use crate::types::Keyword;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmKeyword<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmKeyword {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
pub(crate) key: String,
pub(crate) value: String,
}
to_wasm!(
WasmKeyword<'s, 'p>,
WasmKeyword,
Keyword<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Keyword(original) },
{ "keyword".into() },
{
Ok(WasmKeyword {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
Ok((
Vec::new(),
WasmKeyword {
additional_properties,
key: original.key.to_uppercase(),
value: original.value.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,40 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::GetAffiliatedKeywords;
use crate::types::LatexEnvironment;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmLatexEnvironment<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmLatexEnvironment {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
pub(crate) value: String,
}
to_wasm!(
WasmLatexEnvironment<'s, 'p>,
WasmLatexEnvironment,
LatexEnvironment<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::LatexEnvironment(original) },
{ "latex-environment".into() },
{
Ok(WasmLatexEnvironment {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
Ok((
Vec::new(),
WasmLatexEnvironment {
additional_properties,
value: original.value.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,31 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::LatexFragment;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmLatexFragment<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmLatexFragment {
pub(crate) value: String,
}
to_wasm!(
WasmLatexFragment<'s, 'p>,
WasmLatexFragment,
LatexFragment<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::LatexFragment(original) },
{ "latex-fragment".into() },
{
Ok(WasmLatexFragment {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmLatexFragment {
value: original.value.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,22 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::LineBreak;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmLineBreak<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmLineBreak {}
to_wasm!(
WasmLineBreak<'s, 'p>,
WasmLineBreak,
LineBreak<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmLineBreak {
standard_properties,
children: Vec::new(),
})
}
{ WasmAstNode::LineBreak(original) },
{ "line-break".into() },
{ Ok((Vec::new(), WasmLineBreak {},)) }
);

View File

@@ -2,21 +2,58 @@
///
/// This exists to make changing the type signature easier.
macro_rules! to_wasm {
($ostruct:ty, $istruct:ty, $original:ident, $wasm_context:ident, $standard_properties:ident, $fnbody:tt) => {
impl<'s, 'p> ToWasm<'p> for $istruct {
($ostruct:ty, $istruct:ty, $original:ident, $wasm_context:ident, $fnbody:tt) => {
impl<'s> ToWasm for $istruct {
type Output = $ostruct;
fn to_wasm(
&'p self,
&self,
$wasm_context: crate::wasm::to_wasm::ToWasmContext<'_>,
) -> Result<Self::Output, crate::error::CustomError> {
let $original = self;
let $standard_properties =
self.to_wasm_standard_properties($wasm_context.clone())?;
#[allow(unused_braces)]
$fnbody
}
}
};
($ostruct:ty, $istruct:ty, $original:ident, $wasm_context:ident, $toastnodebody:tt, $elispnamebody:tt, $fnbody:tt) => {
impl<'s> ToWasm for $istruct {
type Output = crate::wasm::ast_node::WasmAstNodeWrapper<$ostruct>;
fn to_wasm(
&self,
$wasm_context: crate::wasm::to_wasm::ToWasmContext<'_>,
) -> Result<Self::Output, crate::error::CustomError> {
#[allow(unused_variables)]
let $original = self;
let standard_properties =
self.to_wasm_standard_properties($wasm_context.clone())?;
$fnbody.map(
|(children, inner)| crate::wasm::ast_node::WasmAstNodeWrapper {
ast_node: inner.get_elisp_name().into_owned(),
standard_properties,
children,
properties: inner,
},
)
}
}
impl From<crate::wasm::ast_node::WasmAstNodeWrapper<$ostruct>> for WasmAstNode {
fn from($original: crate::wasm::ast_node::WasmAstNodeWrapper<$ostruct>) -> Self {
let ret = $toastnodebody;
ret
}
}
impl<'s> crate::util::elisp_fact::ElispFact<'s> for $ostruct {
fn get_elisp_name<'b>(&'b self) -> std::borrow::Cow<'s, str> {
let ret = $elispnamebody;
ret
}
}
};
}
pub(crate) use to_wasm;

View File

@@ -66,10 +66,11 @@ mod verse_block;
pub use additional_property::AdditionalProperties;
pub use additional_property::AdditionalPropertyValue;
pub use ast_node::WasmAstNode;
#[cfg(feature = "wasm_test")]
pub use ast_node::WasmAstNodeWrapper;
#[cfg(feature = "wasm_test")]
pub use document::WasmDocument;
pub(crate) use headline::WasmHeadline;
pub use parse_result::ParseResult;
pub(crate) use section::WasmSection;
pub(crate) use standard_properties::WasmStandardProperties;
pub use to_wasm::ToWasm;
pub use to_wasm::ToWasmContext;

View File

@@ -1,30 +1,33 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::NodeProperty;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmNodeProperty<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmNodeProperty {
pub(crate) key: String,
pub(crate) value: Option<String>,
}
to_wasm!(
WasmNodeProperty<'s, 'p>,
WasmNodeProperty,
NodeProperty<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::NodeProperty(original) },
{ "node-property".into() },
{
Ok(WasmNodeProperty {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmNodeProperty {
key: original.property_name.to_owned(),
value: original.value.map(|s| s.to_owned()),
},
))
}
);

View File

@@ -1,30 +1,35 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::OrgMacro;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmOrgMacro<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmOrgMacro {
pub(crate) key: String,
pub(crate) value: String,
pub(crate) args: Vec<String>,
}
to_wasm!(
WasmOrgMacro<'s, 'p>,
WasmOrgMacro,
OrgMacro<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::OrgMacro(original) },
{ "macro".into() },
{
Ok(WasmOrgMacro {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmOrgMacro {
key: original.key.to_lowercase(),
value: original.value.to_owned(),
args: original.get_args().map(|s| s.into_owned()).collect(),
},
))
}
);

View File

@@ -1,30 +1,48 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::GetAffiliatedKeywords;
use crate::types::Paragraph;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmParagraph<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmParagraph {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
}
to_wasm!(
WasmParagraph<'s, 'p>,
WasmParagraph,
Paragraph<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Paragraph(original) },
{ "paragraph".into() },
{
Ok(WasmParagraph {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmParagraph {
additional_properties,
},
))
}
);

View File

@@ -1,12 +1,14 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNodeWrapper;
use super::document::WasmDocument;
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "status", content = "content")]
pub enum ParseResult<'s, 'p> {
pub enum ParseResult {
#[serde(rename = "success")]
Success(WasmDocument<'s, 'p>),
Success(WasmAstNodeWrapper<WasmDocument>),
#[serde(rename = "error")]
Error(String),

View File

@@ -1,30 +1,52 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::LinkType;
use crate::types::PlainLink;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPlainLink<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "format")]
#[serde(rename = "plain")]
pub struct WasmPlainLink {
#[serde(rename = "type")]
pub(crate) link_type: String,
pub(crate) path: String,
#[serde(rename = "raw-link")]
pub(crate) raw_link: String,
pub(crate) application: Option<String>,
#[serde(rename = "search-option")]
pub(crate) search_option: Option<String>,
}
to_wasm!(
WasmPlainLink<'s, 'p>,
WasmPlainLink,
PlainLink<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::PlainLink(original) },
{ "link".into() },
{
Ok(WasmPlainLink {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmPlainLink {
link_type: match &original.link_type {
LinkType::File => "file".to_owned(),
LinkType::Protocol(protocol) => protocol.clone().into_owned(),
LinkType::Id => "id".to_owned(),
LinkType::CustomId => "custom-id".to_owned(),
LinkType::CodeRef => "coderef".to_owned(),
LinkType::Fuzzy => "fuzzy".to_owned(),
},
path: original.path.to_owned(),
raw_link: original.raw_link.to_owned(),
application: original.application.map(str::to_owned),
search_option: original.search_option.map(str::to_owned),
},
))
}
);

View File

@@ -1,30 +1,57 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::GetAffiliatedKeywords;
use crate::types::PlainList;
use crate::types::PlainListType;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPlainList<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmPlainList {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
#[serde(rename = "type")]
pub(crate) list_type: String,
}
to_wasm!(
WasmPlainList<'s, 'p>,
WasmPlainList,
PlainList<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::PlainList(original) },
{ "plain-list".into() },
{
Ok(WasmPlainList {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmPlainList {
additional_properties,
list_type: match original.list_type {
PlainListType::Unordered => "unordered",
PlainListType::Ordered => "ordered",
PlainListType::Descriptive => "descriptive",
}
.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,68 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::CheckboxType;
use crate::types::PlainListItem;
use crate::types::PlainListItemCounter;
use crate::types::PlainListItemPreBlank;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPlainListItem<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmPlainListItem {
pub(crate) tag: Vec<WasmAstNode>,
pub(crate) bullet: String,
pub(crate) counter: Option<PlainListItemCounter>,
pub(crate) checkbox: Option<String>,
#[serde(rename = "pre-blank")]
pub(crate) pre_blank: PlainListItemPreBlank,
}
to_wasm!(
WasmPlainListItem<'s, 'p>,
WasmPlainListItem,
PlainListItem<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::PlainListItem(original) },
{ "item".into() },
{
Ok(WasmPlainListItem {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmPlainListItem {
tag: original
.tag
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?,
bullet: original.bullet.to_owned(),
counter: original.counter,
checkbox: original.checkbox.as_ref().map(|(checkbox_type, _)| {
match checkbox_type {
CheckboxType::On => "on",
CheckboxType::Trans => "trans",
CheckboxType::Off => "off",
}
.to_owned()
}),
pre_blank: original.pre_blank,
},
))
}
);

View File

@@ -1,30 +1,22 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::PlainText;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPlainText<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmPlainText {}
to_wasm!(
WasmPlainText<'s, 'p>,
WasmPlainText,
PlainText<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmPlainText {
standard_properties,
children: Vec::new(),
})
}
{ WasmAstNode::PlainText(original) },
{ "plain-text".into() },
{ Ok((Vec::new(), WasmPlainText {},)) }
);

View File

@@ -1,30 +1,62 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Planning;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPlanning<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmPlanning {
pub(crate) scheduled: Option<Box<WasmAstNode>>,
pub(crate) deadline: Option<Box<WasmAstNode>>,
pub(crate) closed: Option<Box<WasmAstNode>>,
}
to_wasm!(
WasmPlanning<'s, 'p>,
WasmPlanning,
Planning<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Planning(original) },
{ "planning".into() },
{
Ok(WasmPlanning {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmPlanning {
scheduled: original
.scheduled
.as_ref()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.map_or(Ok(None), |r| r.map(Some))?
.map(Box::new),
deadline: original
.deadline
.as_ref()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.map_or(Ok(None), |r| r.map(Some))?
.map(Box::new),
closed: original
.closed
.as_ref()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.map_or(Ok(None), |r| r.map(Some))?
.map(Box::new),
},
))
}
);

View File

@@ -1,30 +1,34 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::PropertyDrawer;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPropertyDrawer<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmPropertyDrawer {}
to_wasm!(
WasmPropertyDrawer<'s, 'p>,
WasmPropertyDrawer,
PropertyDrawer<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::PropertyDrawer(original) },
{ "property-drawer".into() },
{
Ok(WasmPropertyDrawer {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((children, WasmPropertyDrawer {}))
}
);

View File

@@ -1,30 +1,48 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::GetAffiliatedKeywords;
use crate::types::QuoteBlock;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmQuoteBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmQuoteBlock {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
}
to_wasm!(
WasmQuoteBlock<'s, 'p>,
WasmQuoteBlock,
QuoteBlock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::QuoteBlock(original) },
{ "quote-block".into() },
{
Ok(WasmQuoteBlock {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmQuoteBlock {
additional_properties,
},
))
}
);

View File

@@ -1,30 +1,54 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::RadioLink;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmRadioLink<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "format")]
#[serde(rename = "plain")]
pub struct WasmRadioLink {
#[serde(rename = "type")]
pub(crate) link_type: String,
pub(crate) path: String,
#[serde(rename = "raw-link")]
pub(crate) raw_link: String,
pub(crate) application: Option<String>, // Always None
#[serde(rename = "search-option")]
pub(crate) search_option: Option<String>, // Always None
}
to_wasm!(
WasmRadioLink<'s, 'p>,
WasmRadioLink,
RadioLink<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::RadioLink(original) },
{ "link".into() },
{
Ok(WasmRadioLink {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmRadioLink {
link_type: "radio".to_owned(),
path: original.path.to_owned(),
raw_link: original.get_raw_link().to_owned(),
application: None,
search_option: None,
},
))
}
);

View File

@@ -1,30 +1,41 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::RadioTarget;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmRadioTarget<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmRadioTarget {
pub(crate) value: String,
}
to_wasm!(
WasmRadioTarget<'s, 'p>,
WasmRadioTarget,
RadioTarget<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::RadioTarget(original) },
{ "radio-target".into() },
{
Ok(WasmRadioTarget {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmRadioTarget {
value: original.value.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,67 @@
use std::borrow::Cow;
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::LinkType;
use crate::types::RegularLink;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmRegularLink<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "format")]
#[serde(rename = "bracket")]
pub struct WasmRegularLink {
#[serde(rename = "type")]
pub(crate) link_type: String,
pub(crate) path: String,
#[serde(rename = "raw-link")]
pub(crate) raw_link: String,
pub(crate) application: Option<String>,
#[serde(rename = "search-option")]
pub(crate) search_option: Option<String>,
}
to_wasm!(
WasmRegularLink<'s, 'p>,
WasmRegularLink,
RegularLink<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::RegularLink(original) },
{ "link".into() },
{
Ok(WasmRegularLink {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmRegularLink {
link_type: match &original.link_type {
LinkType::File => "file".to_owned(),
LinkType::Protocol(protocol) => protocol.clone().into_owned(),
LinkType::Id => "id".to_owned(),
LinkType::CustomId => "custom-id".to_owned(),
LinkType::CodeRef => "coderef".to_owned(),
LinkType::Fuzzy => "fuzzy".to_owned(),
},
path: original.get_path().into_owned(),
raw_link: original.get_raw_link().into_owned(),
application: original
.application
.as_ref()
.map(|c| c.clone().into_owned()),
search_option: original.get_search_option().map(Cow::into_owned),
},
))
}
);

View File

@@ -1,36 +1,34 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Section;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "section")]
pub struct WasmSection<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmSection {}
to_wasm!(
WasmSection<'s, 'p>,
WasmSection,
Section<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Section(original) },
{ "section".into() },
{
Ok(WasmSection {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((children, WasmSection {}))
}
);
impl<'s, 'p> Into<WasmAstNode<'s, 'p>> for WasmSection<'s, 'p> {
fn into(self) -> WasmAstNode<'s, 'p> {
WasmAstNode::Section(self)
}
}

View File

@@ -1,30 +1,56 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::headline::Noop;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::GetAffiliatedKeywords;
use crate::types::SpecialBlock;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmSpecialBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmSpecialBlock {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
#[serde(rename = "type")]
pub(crate) block_type: String,
pub(crate) parameters: Option<String>,
pub(crate) results: Noop,
}
to_wasm!(
WasmSpecialBlock<'s, 'p>,
WasmSpecialBlock,
SpecialBlock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::SpecialBlock(original) },
{ "special-block".into() },
{
Ok(WasmSpecialBlock {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmSpecialBlock {
additional_properties,
block_type: original.block_type.to_owned(),
parameters: original.parameters.map(|s| s.to_owned()),
results: Noop {},
},
))
}
);

View File

@@ -1,30 +1,100 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::CharOffsetInLine;
use crate::types::GetAffiliatedKeywords;
use crate::types::LineNumber;
use crate::types::RetainLabels;
use crate::types::SrcBlock;
use crate::types::SwitchNumberLines;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmSrcBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmSrcBlock {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
pub(crate) language: Option<String>,
pub(crate) value: String,
pub(crate) switches: Option<String>,
pub(crate) parameters: Option<String>,
#[serde(rename = "number-lines")]
pub(crate) number_lines: Option<WasmNumberLinesWrapper>,
#[serde(rename = "preserve-indent")]
pub(crate) preserve_indent: Option<CharOffsetInLine>,
#[serde(rename = "retain-labels")]
pub(crate) retain_labels: WasmRetainLabels,
#[serde(rename = "use-labels")]
pub(crate) use_labels: bool,
#[serde(rename = "label-fmt")]
pub(crate) label_format: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub(crate) enum WasmRetainLabels {
YesNo(bool),
Keep(CharOffsetInLine),
}
#[derive(Debug, Serialize, Deserialize)]
pub(crate) enum WasmNumberLines {
#[serde(rename = "new")]
New(LineNumber),
#[serde(rename = "continued")]
Continued(LineNumber),
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename = "number-lines")]
#[serde(tag = "number-lines")]
pub(crate) struct WasmNumberLinesWrapper {
#[serde(flatten)]
pub(crate) inner: WasmNumberLines,
}
to_wasm!(
WasmSrcBlock<'s, 'p>,
WasmSrcBlock,
SrcBlock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::SrcBlock(original) },
{ "src-block".into() },
{
Ok(WasmSrcBlock {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
Ok((
Vec::new(),
WasmSrcBlock {
additional_properties,
language: original.language.map(|s| s.to_owned()),
value: original.get_value().into_owned(),
switches: original.switches.map(|s| s.to_owned()),
parameters: original.parameters.map(|s| s.to_owned()),
number_lines: match original.number_lines {
None => None,
Some(SwitchNumberLines::New(n)) => Some(WasmNumberLinesWrapper {
inner: WasmNumberLines::New(n),
}),
Some(SwitchNumberLines::Continued(n)) => Some(WasmNumberLinesWrapper {
inner: WasmNumberLines::Continued(n),
}),
},
preserve_indent: original.preserve_indent,
retain_labels: match original.retain_labels {
RetainLabels::No => WasmRetainLabels::YesNo(false),
RetainLabels::Yes => WasmRetainLabels::YesNo(true),
RetainLabels::Keep(n) => WasmRetainLabels::Keep(n),
},
use_labels: original.use_labels,
label_format: original.label_format.map(|s| s.to_owned()),
},
))
}
);

View File

@@ -1,3 +1,4 @@
use serde::Deserialize;
use serde::Serialize;
use super::to_wasm::ToWasmContext;
@@ -5,12 +6,15 @@ use super::to_wasm::ToWasmStandardProperties;
use crate::types::PostBlank;
use crate::types::StandardProperties;
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct WasmStandardProperties {
pub(crate) begin: usize,
pub(crate) end: usize,
#[serde(rename = "contents-begin")]
pub(crate) contents_begin: Option<usize>,
#[serde(rename = "contents-end")]
pub(crate) contents_end: Option<usize>,
#[serde(rename = "post-blank")]
pub(crate) post_blank: PostBlank,
}

View File

@@ -1,30 +1,31 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::StatisticsCookie;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmStatisticsCookie<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmStatisticsCookie {
pub(crate) value: String,
}
to_wasm!(
WasmStatisticsCookie<'s, 'p>,
WasmStatisticsCookie,
StatisticsCookie<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::StatisticsCookie(original) },
{ "statistics-cookie".into() },
{
Ok(WasmStatisticsCookie {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmStatisticsCookie {
value: original.value.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,34 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::StrikeThrough;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmStrikeThrough<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmStrikeThrough {}
to_wasm!(
WasmStrikeThrough<'s, 'p>,
WasmStrikeThrough,
StrikeThrough<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::StrikeThrough(original) },
{ "strike-through".into() },
{
Ok(WasmStrikeThrough {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((children, WasmStrikeThrough {}))
}
);

View File

@@ -1,30 +1,42 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Subscript;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmSubscript<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmSubscript {
#[serde(rename = "use-brackets-p")]
pub(crate) use_brackets: bool,
}
to_wasm!(
WasmSubscript<'s, 'p>,
WasmSubscript,
Subscript<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Subscript(original) },
{ "subscript".into() },
{
Ok(WasmSubscript {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmSubscript {
use_brackets: original.use_brackets,
},
))
}
);

View File

@@ -1,30 +1,42 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Superscript;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmSuperscript<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmSuperscript {
#[serde(rename = "use-brackets-p")]
pub(crate) use_brackets: bool,
}
to_wasm!(
WasmSuperscript<'s, 'p>,
WasmSuperscript,
Superscript<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Superscript(original) },
{ "superscript".into() },
{
Ok(WasmSuperscript {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmSuperscript {
use_brackets: original.use_brackets,
},
))
}
);

View File

@@ -1,30 +1,75 @@
use std::collections::BTreeSet;
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::GetAffiliatedKeywords;
use crate::types::Table;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmTable<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmTable {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
#[serde(rename = "tblfm")]
pub(crate) formulas: Option<WasmStringSet>,
#[serde(rename = "type")]
pub(crate) table_type: String,
pub(crate) value: Option<String>, // Always None
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "string-set")]
#[serde(rename = "string-set")]
pub(crate) struct WasmStringSet {
value: BTreeSet<String>,
}
to_wasm!(
WasmTable<'s, 'p>,
WasmTable,
Table<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Table(original) },
{ "table".into() },
{
Ok(WasmTable {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmTable {
additional_properties,
formulas: if original.formulas.is_empty() {
None
} else {
Some(WasmStringSet {
value: original
.formulas
.iter()
.map(|kw| kw.value.to_owned())
.collect(),
})
},
table_type: "org".to_owned(),
value: None,
},
))
}
);

View File

@@ -1,30 +1,34 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::TableCell;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmTableCell<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmTableCell {}
to_wasm!(
WasmTableCell<'s, 'p>,
WasmTableCell,
TableCell<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::TableCell(original) },
{ "table-cell".into() },
{
Ok(WasmTableCell {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((children, WasmTableCell {}))
}
);

View File

@@ -1,30 +1,47 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::TableRow;
use crate::types::TableRowType;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmTableRow<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmTableRow {
#[serde(rename = "type")]
pub(crate) row_type: String,
}
to_wasm!(
WasmTableRow<'s, 'p>,
WasmTableRow,
TableRow<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::TableRow(original) },
{ "table-row".into() },
{
Ok(WasmTableRow {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmTableRow {
row_type: match original.get_type() {
TableRowType::Standard => "standard",
TableRowType::Rule => "rule",
}
.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,31 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Target;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmTarget<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmTarget {
pub(crate) value: String,
}
to_wasm!(
WasmTarget<'s, 'p>,
WasmTarget,
Target<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Target(original) },
{ "target".into() },
{
Ok(WasmTarget {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmTarget {
value: original.value.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,146 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::DayOfMonthInner;
use crate::types::HourInner;
use crate::types::MinuteInner;
use crate::types::MonthInner;
use crate::types::RepeaterType;
use crate::types::RepeaterWarningDelayValueType;
use crate::types::TimeUnit;
use crate::types::Timestamp;
use crate::types::TimestampRangeType;
use crate::types::TimestampType;
use crate::types::WarningDelayType;
use crate::types::YearInner;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmTimestamp<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmTimestamp {
#[serde(rename = "type")]
pub(crate) timestamp_type: String,
#[serde(rename = "range-type")]
pub(crate) range_type: Option<String>,
#[serde(rename = "raw-value")]
pub(crate) raw_value: String,
#[serde(rename = "year-start")]
pub(crate) year_start: Option<YearInner>,
#[serde(rename = "month-start")]
pub(crate) month_start: Option<MonthInner>,
#[serde(rename = "day-start")]
pub(crate) day_of_month_start: Option<DayOfMonthInner>,
#[serde(rename = "hour-start")]
pub(crate) hour_start: Option<HourInner>,
#[serde(rename = "minute-start")]
pub(crate) minute_start: Option<MinuteInner>,
#[serde(rename = "year-end")]
pub(crate) year_end: Option<YearInner>,
#[serde(rename = "month-end")]
pub(crate) month_end: Option<MonthInner>,
#[serde(rename = "day-end")]
pub(crate) day_of_month_end: Option<DayOfMonthInner>,
#[serde(rename = "hour-end")]
pub(crate) hour_end: Option<HourInner>,
#[serde(rename = "minute-end")]
pub(crate) minute_end: Option<MinuteInner>,
#[serde(rename = "repeater-type")]
pub(crate) repeater_type: Option<String>,
#[serde(rename = "repeater-unit")]
pub(crate) repeater_unit: Option<String>,
#[serde(rename = "repeater-value")]
pub(crate) repeater_value: Option<RepeaterWarningDelayValueType>,
#[serde(rename = "warning-type")]
pub(crate) warning_type: Option<String>,
#[serde(rename = "warning-unit")]
pub(crate) warning_unit: Option<String>,
#[serde(rename = "warning-value")]
pub(crate) warning_value: Option<RepeaterWarningDelayValueType>,
}
to_wasm!(
WasmTimestamp<'s, 'p>,
WasmTimestamp,
Timestamp<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Timestamp(original) },
{ "timestamp".into() },
{
Ok(WasmTimestamp {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmTimestamp {
timestamp_type: match original.timestamp_type {
TimestampType::Diary => "diary",
TimestampType::Active => "active",
TimestampType::Inactive => "inactive",
TimestampType::ActiveRange => "active-range",
TimestampType::InactiveRange => "inactive-range",
}
.to_owned(),
range_type: match original.range_type {
TimestampRangeType::DateRange => Some("daterange".to_owned()),
TimestampRangeType::TimeRange => Some("timerange".to_owned()),
TimestampRangeType::None => None,
},
raw_value: original.get_raw_value().to_owned(),
year_start: original.start.as_ref().map(|date| date.get_year().0),
month_start: original.start.as_ref().map(|date| date.get_month().0),
day_of_month_start: original
.start
.as_ref()
.map(|date| date.get_day_of_month().0),
hour_start: original.start_time.as_ref().map(|time| time.get_hour().0),
minute_start: original.start_time.as_ref().map(|time| time.get_minute().0),
year_end: original.end.as_ref().map(|date| date.get_year().0),
month_end: original.end.as_ref().map(|date| date.get_month().0),
day_of_month_end: original.end.as_ref().map(|date| date.get_day_of_month().0),
hour_end: original.end_time.as_ref().map(|time| time.get_hour().0),
minute_end: original.end_time.as_ref().map(|time| time.get_minute().0),
repeater_type: original
.repeater
.as_ref()
.map(|repeater| match repeater.repeater_type {
RepeaterType::Cumulative => "cumulate",
RepeaterType::CatchUp => "catch-up",
RepeaterType::Restart => "restart",
})
.map(|text| text.to_owned()),
repeater_unit: original
.repeater
.as_ref()
.map(|repeater| match repeater.unit {
TimeUnit::Hour => "hour",
TimeUnit::Day => "day",
TimeUnit::Week => "week",
TimeUnit::Month => "month",
TimeUnit::Year => "year",
})
.map(|text| text.to_owned()),
repeater_value: original.repeater.as_ref().map(|repeater| repeater.value),
warning_type: original
.warning_delay
.as_ref()
.map(|warning| match warning.warning_delay_type {
WarningDelayType::All => "all",
WarningDelayType::First => "first",
})
.map(|text| text.to_owned()),
warning_unit: original
.warning_delay
.as_ref()
.map(|warning| match warning.unit {
TimeUnit::Hour => "hour",
TimeUnit::Day => "day",
TimeUnit::Week => "week",
TimeUnit::Month => "month",
TimeUnit::Year => "year",
})
.map(|text| text.to_owned()),
warning_value: original.warning_delay.as_ref().map(|warning| warning.value),
},
))
}
);

View File

@@ -1,9 +1,14 @@
use super::macros::to_wasm;
use super::WasmAstNode;
use crate::error::CustomError;
use crate::types::DocumentElement;
use crate::types::Element;
use crate::types::Object;
pub trait ToWasm<'p> {
pub trait ToWasm {
type Output;
fn to_wasm(&'p self, full_document: ToWasmContext<'_>) -> Result<Self::Output, CustomError>;
fn to_wasm(&self, full_document: ToWasmContext<'_>) -> Result<Self::Output, CustomError>;
}
pub(crate) trait ToWasmStandardProperties {
@@ -25,3 +30,95 @@ impl<'s> ToWasmContext<'s> {
ToWasmContext { full_document }
}
}
to_wasm!(WasmAstNode, DocumentElement<'s>, original, wasm_context, {
match original {
DocumentElement::Heading(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
DocumentElement::Section(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
}
});
to_wasm!(WasmAstNode, Element<'s>, original, wasm_context, {
match original {
Element::Paragraph(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::PlainList(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::CenterBlock(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::QuoteBlock(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::SpecialBlock(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::DynamicBlock(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::FootnoteDefinition(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
Element::Comment(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::Drawer(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::PropertyDrawer(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
Element::Table(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::VerseBlock(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::CommentBlock(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::ExampleBlock(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::ExportBlock(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::SrcBlock(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::Clock(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::DiarySexp(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::Planning(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::FixedWidthArea(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
Element::HorizontalRule(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
Element::Keyword(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::BabelCall(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Element::LatexEnvironment(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
}
});
to_wasm!(WasmAstNode, Object<'s>, original, wasm_context, {
match original {
Object::Bold(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::Italic(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::Underline(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::StrikeThrough(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::Code(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::Verbatim(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::PlainText(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::RegularLink(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::RadioLink(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::RadioTarget(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::PlainLink(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::AngleLink(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::OrgMacro(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::Entity(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::LatexFragment(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::ExportSnippet(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::FootnoteReference(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
Object::Citation(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::CitationReference(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
Object::InlineBabelCall(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
Object::InlineSourceBlock(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
Object::LineBreak(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::Target(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::StatisticsCookie(inner) => {
inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into)
}
Object::Subscript(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::Superscript(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
Object::Timestamp(inner) => inner.to_wasm(wasm_context).map(Into::<WasmAstNode>::into),
}
});

View File

@@ -1,30 +1,34 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Underline;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmUnderline<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmUnderline {}
to_wasm!(
WasmUnderline<'s, 'p>,
WasmUnderline,
Underline<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Underline(original) },
{ "underline".into() },
{
Ok(WasmUnderline {
standard_properties,
children: Vec::new(),
})
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((children, WasmUnderline {}))
}
);

View File

@@ -1,30 +1,31 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Verbatim;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmVerbatim<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmVerbatim {
pub(crate) value: String,
}
to_wasm!(
WasmVerbatim<'s, 'p>,
WasmVerbatim,
Verbatim<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::Verbatim(original) },
{ "verbatim".into() },
{
Ok(WasmVerbatim {
standard_properties,
children: Vec::new(),
})
Ok((
Vec::new(),
WasmVerbatim {
value: original.contents.to_owned(),
},
))
}
);

View File

@@ -1,30 +1,48 @@
use serde::Deserialize;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use super::AdditionalProperties;
use crate::types::GetAffiliatedKeywords;
use crate::types::VerseBlock;
use crate::util::elisp_fact::ElispFact;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmVerseBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
#[derive(Debug, Serialize, Deserialize)]
pub struct WasmVerseBlock {
#[serde(flatten)]
pub(crate) additional_properties: AdditionalProperties,
}
to_wasm!(
WasmVerseBlock<'s, 'p>,
WasmVerseBlock,
VerseBlock<'s>,
original,
wasm_context,
standard_properties,
{ WasmAstNode::VerseBlock(original) },
{ "verse-block".into() },
{
Ok(WasmVerseBlock {
standard_properties,
children: Vec::new(),
})
let additional_properties = original
.get_affiliated_keywords()
.to_wasm(wasm_context.clone())?;
let children = original
.children
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode>::into)
})
.collect::<Result<Vec<_>, _>>()?;
Ok((
children,
WasmVerseBlock {
additional_properties,
},
))
}
);

25
src/wasm_cli/mod.rs Normal file
View File

@@ -0,0 +1,25 @@
use gloo_utils::format::JsValueSerdeExt;
use wasm_bindgen::JsValue;
use crate::parser::parse_with_settings;
use crate::settings::GlobalSettings;
use crate::wasm::ParseResult;
use crate::wasm::ToWasm;
use crate::wasm::ToWasmContext;
pub fn parse_org(org_contents: &str) -> wasm_bindgen::JsValue {
let rust_parsed = match parse_with_settings(org_contents, &GlobalSettings::default()) {
Ok(document) => document,
Err(err) => {
return JsValue::from_serde(&ParseResult::Error(format!("{:?}", err))).unwrap();
}
};
let to_wasm_context = ToWasmContext::new(org_contents);
let wasm_document = match rust_parsed.to_wasm(to_wasm_context) {
Ok(document) => document,
Err(err) => {
return JsValue::from_serde(&ParseResult::Error(format!("{:?}", err))).unwrap();
}
};
JsValue::from_serde(&ParseResult::Success(wasm_document)).unwrap()
}

File diff suppressed because it is too large Load Diff

109
src/wasm_test/diff.rs Normal file
View File

@@ -0,0 +1,109 @@
use std::borrow::Cow;
use crate::util::terminal::foreground_color;
use crate::util::terminal::reset_color;
#[derive(Debug)]
pub struct WasmDiffResult<'s> {
pub(crate) status: Vec<WasmDiffStatus>,
pub(crate) name: Cow<'s, str>,
pub(crate) children: Vec<WasmDiffResult<'s>>,
}
#[derive(Debug)]
pub(crate) enum WasmDiffStatus {
#[allow(dead_code)]
Good,
Bad(Cow<'static, str>),
}
impl<'s> WasmDiffResult<'s> {
pub(crate) fn extend(
&mut self,
other: WasmDiffResult<'s>,
) -> Result<&mut WasmDiffResult<'s>, Box<dyn std::error::Error>> {
if self.name.is_empty() {
self.name = other.name;
}
self.status.extend(other.status);
self.children.extend(other.children);
Ok(self)
}
pub fn is_bad(&self) -> bool {
self.is_self_bad() || self.has_bad_children()
}
pub fn is_self_bad(&self) -> bool {
self.status
.iter()
.any(|status| matches!(status, WasmDiffStatus::Bad(_)))
}
pub fn has_bad_children(&self) -> bool {
self.children.iter().any(WasmDiffResult::is_bad)
}
pub fn print(&self, original_document: &str) -> Result<(), Box<dyn std::error::Error>> {
self.print_indented(0, original_document)
}
fn print_indented(
&self,
indentation: usize,
_original_document: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let status_text = {
if self.is_self_bad() {
format!(
"{color}BAD{reset}",
color = foreground_color(255, 0, 0),
reset = reset_color(),
)
} else if self.has_bad_children() {
format!(
"{color}BADCHILD{reset}",
color = foreground_color(255, 255, 0),
reset = reset_color(),
)
} else {
format!(
"{color}GOOD{reset}",
color = foreground_color(0, 255, 0),
reset = reset_color(),
)
}
};
let message = self
.status
.iter()
.filter_map(|status| match status {
WasmDiffStatus::Good => None,
WasmDiffStatus::Bad(message) => Some(message),
})
.next();
println!(
"{indentation}{status_text} {name} {message}",
indentation = " ".repeat(indentation),
status_text = status_text,
name = self.name,
message = message.unwrap_or(&Cow::Borrowed(""))
);
for child in self.children.iter() {
child.print_indented(indentation + 1, _original_document)?;
}
Ok(())
}
}
impl<'s> Default for WasmDiffResult<'s> {
fn default() -> Self {
WasmDiffResult {
status: Vec::new(),
name: "".into(),
children: Vec::new(),
}
}
}

View File

@@ -1,10 +0,0 @@
use super::compare::WasmDiffResult;
use crate::compare::Token;
pub trait WasmElispCompare<'s, 'p> {
fn compare_ast_node<'b>(
&self,
source: &'s str,
emacs: &'b Token<'s>,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>>;
}

View File

@@ -1,143 +0,0 @@
macro_rules! wasm_compare {
($source:expr, $emacs:expr, $wasm:expr, $(($emacs_field:expr, $wasm_value_getter:expr, $compare_fn: expr)),*) => {{
let mut result = WasmDiffResult::default();
let emacs_list = $emacs.as_list()?;
let mut emacs_list_iter = emacs_list.iter();
let emacs_name = emacs_list_iter
.next()
.ok_or("Should have an attributes child.")?
.as_atom()?;
result.name = emacs_name.into();
let emacs_attributes_map = emacs_list_iter
.next()
.ok_or("Should have an attributes child.")?
.as_map()?;
let mut emacs_keys: std::collections::BTreeSet<&str> =
emacs_attributes_map.keys().map(|s| *s).collect();
// Mark :standard-properties as seen because it will be handled separately.
if emacs_keys.contains(":standard-properties") {
emacs_keys.remove(":standard-properties");
} else {
result.status.push(WasmDiffStatus::Bad(
"Emacs node lacked :standard-properties field.".into(),
));
}
{
// Compare name.
let wasm_name = $wasm.get_elisp_name();
if emacs_name != wasm_name {
result.status.push(WasmDiffStatus::Bad(
format!(
"AST node name mismatch. Emacs=({emacs}) Wasm=({wasm}).",
emacs = emacs_name,
wasm = wasm_name,
)
.into(),
));
}
}
{
// Compare standard properties.
result.extend(wasm_compare_standard_properties($source, $emacs, &$wasm.standard_properties)?)?;
}
{
// Compare additional properties.
let additional_property_names: Vec<String> = $wasm.additional_properties.get_elisp_names().collect();
for additional_property in additional_property_names.iter().map(String::as_str).map(EmacsField::Required) {
match additional_property {
EmacsField::Required(name) if emacs_keys.contains(name) => {
emacs_keys.remove(name);
}
EmacsField::Optional(name) if emacs_keys.contains(name) => {
emacs_keys.remove(name);
}
EmacsField::Required(name) => {
result.status.push(WasmDiffStatus::Bad(
format!(
"Emacs node lacked required field ({name}).",
name = name,
)
.into(),
));
}
EmacsField::Optional(_name) => {}
}
}
result.extend(wasm_compare_additional_properties($source, $emacs, &$wasm.additional_properties)?)?;
}
{
// Compare children.
result.extend(wasm_compare_list(
$source,
emacs_list_iter,
$wasm.children.iter(),
)?)?;
}
{
// Check for properties that are missing from the elisp node.
$(
match $emacs_field {
EmacsField::Required(name) if emacs_keys.contains(name) => {
emacs_keys.remove(name);
}
EmacsField::Optional(name) if emacs_keys.contains(name) => {
emacs_keys.remove(name);
}
EmacsField::Required(name) => {
result.status.push(WasmDiffStatus::Bad(
format!(
"Emacs node lacked required field ({name}).",
name = name,
)
.into(),
));
}
EmacsField::Optional(_name) => {}
}
)*
}
{
// Check for elisp properties that were not compared.
if !emacs_keys.is_empty() {
let unexpected_keys: Vec<&str> = emacs_keys.into_iter().collect();
let unexpected_keys = unexpected_keys.join(", ");
result.status.push(WasmDiffStatus::Bad(
format!(
"Emacs node had extra field(s): ({field_names}).",
field_names = unexpected_keys,
)
.into(),
));
}
}
{
// Compare properties.
$(
let emacs_name = match $emacs_field {
EmacsField::Required(name) => {
name
},
EmacsField::Optional(name) => {
name
},
};
result.extend($compare_fn($source, $emacs, $wasm, emacs_name, $wasm_value_getter)?)?;
)*
}
result
}};
}
pub(crate) use wasm_compare;

View File

@@ -1,6 +1,5 @@
mod compare;
mod elisp_compare;
mod macros;
mod diff;
mod runner;
pub use runner::wasm_run_anonymous_compare;

View File

@@ -1,16 +1,16 @@
use std::path::Path;
use super::compare::wasm_compare_document;
use crate::compare::sexp;
use crate::context::GlobalSettings;
use crate::parser::parse_file_with_settings;
use crate::parser::parse_with_settings;
use crate::settings::LocalFileAccessInterface;
use crate::util::emacs_parse_anonymous_org_document;
use crate::util::emacs_parse_file_org_document;
use crate::util::foreground_color;
use crate::util::print_versions;
use crate::util::reset_color;
use crate::util::cli::emacs_parse_anonymous_org_document;
use crate::util::cli::emacs_parse_file_org_document;
use crate::util::cli::print_versions;
use crate::util::elisp::sexp;
use crate::util::terminal::foreground_color;
use crate::util::terminal::reset_color;
use crate::wasm::ToWasm;
use crate::wasm::ToWasmContext;
@@ -47,7 +47,7 @@ pub async fn wasm_run_anonymous_compare_with_settings<'g, 's, P: AsRef<str>>(
}
// We do the diffing after printing out both parsed forms in case the diffing panics
let diff_result = wasm_compare_document(org_contents, &parsed_sexp, wasm_parsed)?;
let diff_result = wasm_compare_document(org_contents, &parsed_sexp, &wasm_parsed)?;
if !silent {
diff_result.print(org_contents)?;
}
@@ -112,7 +112,7 @@ pub async fn wasm_run_compare_on_file_with_settings<'g, 's, P: AsRef<Path>>(
}
// We do the diffing after printing out both parsed forms in case the diffing panics
let diff_result = wasm_compare_document(org_contents, &parsed_sexp, wasm_parsed)?;
let diff_result = wasm_compare_document(org_contents, &parsed_sexp, &wasm_parsed)?;
if !silent {
diff_result.print(org_contents)?;
}

View File

@@ -60,3 +60,13 @@ async fn autogen_odd_{name}() -> Result<(), Box<dyn std::error::Error>> {{
assert!(organic::compare::run_anonymous_compare_with_settings(org_contents.as_str(), &global_settings, false).await?);
Ok(())
}}
#[cfg(feature = "wasm_test")]
{expect_fail}
#[tokio::test]
async fn autogen_wasm_{name}() -> Result<(), Box<dyn std::error::Error>> {{
let org_path = "{path}";
let org_contents = std::fs::read_to_string(org_path).expect("Read org file.");
assert!(organic::wasm_test::wasm_run_anonymous_compare(org_contents.as_str()).await?);
Ok(())
}}