aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Letan <contact@thomasletan.fr>2019-08-04 00:32:18 +0200
committerThomas Letan <contact@thomasletan.fr>2019-08-04 00:32:18 +0200
commit5eeebd3c96e291804b0d73a927295b83a6ad4f28 (patch)
tree745df66976172ed919a2a60ff6a48d8840e1c463
parentchore: Add a program skeleton (diff)
feature: Generate an EPUB that mupdf can read
-rw-r--r--.gitignore2
-rw-r--r--Cargo.lock226
-rw-r--r--Cargo.toml8
-rw-r--r--src/epub.rs108
-rw-r--r--src/main.rs50
-rw-r--r--src/project.rs121
-rw-r--r--src/render.rs149
7 files changed, 609 insertions, 55 deletions
diff --git a/.gitignore b/.gitignore
index 53eaa21..5c09e9c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
/target
**/*.rs.bk
+
+/_build \ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 7353bb6..b7f37c2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,9 +1,11 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -11,78 +13,110 @@ name = "atty"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
-version = "1.0.4"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "celtchar"
version = "0.1.0"
dependencies = [
- "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "ogmarkup 0.1.0 (git+https://git.sr.ht/~lthms/ogmarkup/?rev=326b6e7c0d4ad366d7ecb6358aae742d9533fb63)",
- "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ogmarkup 0.1.0 (git+https://git.sr.ht/~lthms/ogmarkup/?rev=feaf8d0cbc7aa34ac521020914df91489ef24595)",
+ "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cfg-if"
-version = "0.1.6"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
-version = "2.32.0"
+version = "2.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "lexical-core"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "stackvector 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "static_assertions 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "libc"
-version = "0.2.43"
+version = "0.2.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
-version = "2.1.1"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
[[package]]
name = "nom"
-version = "4.1.1"
+version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lexical-core 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "numtoa"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "ogmarkup"
version = "0.1.0"
-source = "git+https://git.sr.ht/~lthms/ogmarkup/?rev=326b6e7c0d4ad366d7ecb6358aae742d9533fb63#326b6e7c0d4ad366d7ecb6358aae742d9533fb63"
+source = "git+https://git.sr.ht/~lthms/ogmarkup/?rev=feaf8d0cbc7aa34ac521020914df91489ef24595#feaf8d0cbc7aa34ac521020914df91489ef24595"
+dependencies = [
+ "nom 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "0.4.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "0.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
-version = "0.1.40"
+version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -90,32 +124,93 @@ name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "serde"
-version = "1.0.80"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde_derive"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "stackvector"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "static_assertions"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
-version = "0.7.0"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "syn"
+version = "0.15.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "termion"
-version = "1.5.1"
+version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+ "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
-version = "0.10.0"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -123,10 +218,10 @@ dependencies = [
[[package]]
name = "toml"
-version = "0.4.8"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -135,6 +230,19 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "unicode-xid"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unreachable"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -145,8 +253,13 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "winapi"
-version = "0.3.6"
+version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -166,23 +279,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
-"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
-"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
-"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
-"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
-"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
-"checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a"
-"checksum ogmarkup 0.1.0 (git+https://git.sr.ht/~lthms/ogmarkup/?rev=326b6e7c0d4ad366d7ecb6358aae742d9533fb63)" = "<none>"
-"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
+"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
+"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
+"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
+"checksum lexical-core 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b0f90c979adde96d19eb10eb6431ba0c441e2f9e9bdff868b2f6f5114ff519"
+"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
+"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
+"checksum nom 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9761d859320e381010a4f7f8ed425f2c924de33ad121ace447367c713ad561b"
+"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
+"checksum ogmarkup 0.1.0 (git+https://git.sr.ht/~lthms/ogmarkup/?rev=feaf8d0cbc7aa34ac521020914df91489ef24595)" = "<none>"
+"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
+"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
+"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
-"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef"
-"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
-"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
-"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
-"checksum toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4a2ecc31b0351ea18b3fe11274b8db6e4d82bce861bbb22e6dbed40417902c65"
+"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
+"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be"
+"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e"
+"checksum stackvector 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1c4725650978235083241fab0fdc8e694c3de37821524e7534a1a9061d1068af"
+"checksum static_assertions 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4f8de36da215253eb5f24020bfaa0646613b48bf7ebe36cdfa37c3b3b33b241"
+"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+"checksum syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)" = "641e117d55514d6d918490e47102f7e08d096fdde360247e4a10f7a91a8478d3"
+"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"
+"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
-"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
+"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
index c957747..dc90935 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,9 +4,11 @@ version = "0.1.0"
authors = ["Thomas Letan <contact@thomasletan.fr>"]
[dependencies]
-toml = "0.4"
-clap = "2.32"
+toml = "0.5"
+clap = "2.33"
+serde = "1.0"
+serde_derive = "1.0"
[dependencies.ogmarkup]
git = "https://git.sr.ht/~lthms/ogmarkup/"
-rev = "326b6e7c0d4ad366d7ecb6358aae742d9533fb63" \ No newline at end of file
+rev = "feaf8d0cbc7aa34ac521020914df91489ef24595" \ No newline at end of file
diff --git a/src/epub.rs b/src/epub.rs
new file mode 100644
index 0000000..191f487
--- /dev/null
+++ b/src/epub.rs
@@ -0,0 +1,108 @@
+use crate::project::{Error, Project, Chapter};
+use std::fs::{create_dir, create_dir_all};
+use std::path::PathBuf;
+
+const EPUB_MIMETYPE: &'static str = "application/epub+zip";
+const CONTAINER_XML: &'static str = r#"<?xml version="1.0"?>
+<container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
+ <rootfiles>
+ <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
+ </rootfiles>
+</container>"#;
+
+fn create_mimetype() -> Result<(), Error> {
+ std::fs::write("mimetype", EPUB_MIMETYPE)
+ .map_err(|_| Error(String::from("cannot create mimetype")))?;
+
+ Ok(())
+}
+
+fn create_container() -> Result<(), Error> {
+ create_dir("META-INF")
+ .map_err(|_| Error(String::from("cannot create META-INF")))?;
+
+ std::fs::write("META-INF/container.xml", CONTAINER_XML)
+ .map_err(|_| Error(String::from("cannot create container.xml")))?;
+
+ Ok(())
+}
+
+fn create_chapters(chapters : &Vec<Chapter<String>>) -> Result<Vec<String>, Error> {
+
+ chapters.iter().enumerate()
+ .map(|(idx, c)| {
+ let path : String = format!("{}.xhtml", idx);
+ std::fs::write(
+ PathBuf::from(format!("OEBPS/Text/{}", path)).as_path(),
+ format!(
+ "<html><head></head><body>{}</body></html>",
+ c.content.as_str()
+ )
+ )
+ .map_err(|_| Error(format!("cannot create {:?}", path)))?;
+
+ Ok(path)
+ })
+ .collect::<Result<Vec<String>, Error>>()
+}
+
+pub fn generate(project : &Project<String>) -> Result<(), Error> {
+ create_mimetype()?;
+ create_container()?;
+
+ create_dir_all("OEBPS/Text")
+ .map_err(|_| Error(String::from("cannot create OEBPS")))?;
+
+ let files = create_chapters(&project.chapters)?;
+
+ let mut filesxml = String::from("");
+ for f in files.iter() {
+ filesxml.push_str(
+ format!(
+ r#"<item href="Text/{}" id="{}" media-type="application/xhtml+xml" />"#,
+ f, f
+ ).as_str()
+ );
+ }
+
+ let mut spine = String::from("");
+ for f in files.iter() {
+ spine.push_str(
+ format!(
+ r#"<itemref idref="{}" />"#,
+ f
+ ).as_str()
+ );
+ }
+
+ std::fs::write(
+ "OEBPS/content.opf",
+ format!(
+ r#"<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<package xmlns="http://www.idpf.org/2007/opf" unique-identifier="BookId" version="2.0" xmlns:opf="http://www.idpf.org/2007/opf">
+ <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <dc:title>{}</dc:title>
+ <dc:language>fr</dc:language>
+ <dc:creator opf:role="aut">{}</dc:creator>
+ <dc:type>text</dc:type>
+ <dc:description>Ceci est une description</dc:description>
+ </metadata>
+ <manifest>
+ <item href="toc.ncx" id="ncx" media-type="application/x-dtbncx+xml" />
+ {}
+ </manifest>
+ <spine toc="ncxtoc">
+ {}
+ </spine>
+</package>
+"#,
+ project.title,
+ project.author,
+ filesxml,
+ spine
+ )
+ )
+ .map_err(|_| Error(String::from("cannot create content.opf")))?;
+
+ Ok(())
+}
diff --git a/src/main.rs b/src/main.rs
index 7b9cae8..112efb0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,20 +1,64 @@
extern crate clap;
+extern crate ogmarkup;
+extern crate serde_derive;
+extern crate toml;
use clap::{App, SubCommand};
-fn main() {
+pub mod render;
+pub mod project;
+pub mod epub;
+
+use project::{Project, Error};
+use ogmarkup::typography::FRENCH;
+
+use std::fs::{create_dir, remove_dir_all};
+
+const BUILD_DIR : &'static str = "_build";
+
+fn cd_clean_build_dir() -> Result<(), Error> {
+ remove_dir_all(BUILD_DIR)
+ .map_err(|_| Error(String::from("cannot clean up _build/")))?;
+
+ create_dir(BUILD_DIR)
+ .map_err(|_| Error(String::from("cannot create _build/")))?;
+
+ std::env::set_current_dir(BUILD_DIR)
+ .map_err(|_| Error(String::from("cannot set current directory to _build")))?;
+
+ Ok(())
+}
+
+pub fn build() -> Result<(), Error> {
+ Project::cd_root()?;
+
+ let project = Project::find_project()?
+ .load_and_render(&FRENCH)?;
+
+ cd_clean_build_dir()?;
+
+ epub::generate(&project)?;
+
+ Ok(())
+}
+
+fn main() -> Result<(), Error> {
let matches = App::new("celtchar")
.version("0.1")
.author("Thomas Letan")
.about("A tool to generate novels")
.subcommand(SubCommand::with_name("new")
.about("Create a new celtchar document"))
+ .subcommand(SubCommand::with_name("build")
+ .about("Build a celtchar document"))
.get_matches();
let (subcommand, _args) = matches.subcommand();
match subcommand {
- "new" => println!("Hello, world!"),
- _ => println!("meh"),
+ "build" => build()?,
+ _ => unimplemented!(),
}
+
+ Ok(())
}
diff --git a/src/project.rs b/src/project.rs
new file mode 100644
index 0000000..0bf35a9
--- /dev/null
+++ b/src/project.rs
@@ -0,0 +1,121 @@
+use std::fs;
+use std::path::PathBuf;
+use std::env::current_dir;
+
+use serde_derive::Deserialize;
+
+use ogmarkup::typography::Typography;
+
+use crate::render::Html;
+
+const PROJECT_FILE: &'static str = "Book.toml";
+
+#[derive(Debug)]
+pub struct Error(pub String);
+
+#[derive(Debug, Deserialize)]
+pub struct Chapter<A> {
+ pub title: String,
+ pub content: A,
+}
+
+fn compile_file <'input, T> (
+ path : PathBuf,
+ typo : &T,
+) -> Result<String, Error>
+where
+ T : Typography,
+{
+ let input = fs::read_to_string(path.as_path()).map_err(|_| Error(format!("cannot open {:?}", path)))?;
+
+ ogmarkup::compile(input.as_str(), typo)
+ .map(|x: Html| x.to_string())
+ .map_err(|_| Error(format!("cannot render {:?}", path)))
+}
+
+impl Chapter<Vec<PathBuf>> {
+ pub fn load_and_render <'input, T> (
+ self,
+ typo : &T,
+ ) -> Result<Chapter<String>, Error>
+ where
+ T : Typography
+ {
+
+ self.content.iter()
+ .map(|path| compile_file(path.to_path_buf(), typo))
+ .collect::<Result<Vec<String>, Error>>()
+ .map(|x| Chapter {
+ title: self.title,
+ content: x.join(""),
+ })
+ }
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Project<A> {
+ pub author: String,
+ pub title: String,
+ pub chapters: Vec<Chapter<A>>
+}
+
+impl Project<Vec<PathBuf>> {
+ pub fn cd_root() -> Result<(), Error> {
+ let mut cwd: PathBuf = current_dir()
+ .map_err(|_| Error(String::from("cannot get current directory")))?;
+
+ loop {
+ cwd.push(PROJECT_FILE); // (*)
+
+ if cwd.exists() {
+ cwd.pop();
+
+ std::env::set_current_dir(cwd.as_path())
+ .map_err(|_| Error(format!("cannot set current directory to {:?}", cwd)))?;
+
+ return Ok(());
+ } else {
+ // We `pop` a first time for `Book.toml`, since we have pushed
+ // previously it (see (*))
+ cwd.pop();
+
+ // We `pop` a second time to get the parent directory of cwd. If
+ // `pop` returns false, we are at the root of the current FS, and
+ // there is no project file to find.
+ if !cwd.pop() {
+ return Err(Error(String::from("could not find Book.toml")))
+ }
+ }
+ }
+ }
+
+ /// This function tries to open `./Book.toml`. If it succeeds, it tries to
+ /// read it as a TOML file.
+ pub fn find_project() -> Result<Self, Error> {
+ let input = fs::read_to_string(PROJECT_FILE)
+ .map_err(|_| Error(String::from("found Book.toml, but cannot read it")))?;
+
+ return toml::from_str(input.as_str())
+ .map_err(|e| Error(String::from(format!("toml error: {:?}", e))));
+ }
+
+ pub fn load_and_render<'input, T> (
+ self,
+ typo : &T,
+ ) -> Result<Project<String>, Error>
+ where
+ T : Typography
+ {
+ let author = self.author;
+ let title = self.title;
+
+ self.chapters.into_iter()
+ .map(|chapter| chapter.load_and_render(typo))
+ .collect::<Result<Vec<Chapter<String>>, Error>>()
+ .map(|x| Project {
+ author: author,
+ title: title,
+ chapters: x
+ })
+ }
+}
diff --git a/src/render.rs b/src/render.rs
new file mode 100644
index 0000000..3e737b0
--- /dev/null
+++ b/src/render.rs
@@ -0,0 +1,149 @@
+use ogmarkup::typography::Space;
+use ogmarkup::generator::Output;
+
+pub struct Html(String);
+
+impl Html {
+ fn push_str(&mut self, s: &str) -> () {
+ self.0.push_str(s);
+ }
+
+ pub fn to_string(self) -> String {
+ self.0
+ }
+}
+
+impl Output for Html {
+ fn empty(input_size: usize) -> Html {
+ Html(String::with_capacity((15 * input_size) / 10))
+ }
+
+ fn render_space(&mut self, space: Space) -> () {
+ self.push_str(match space {
+ Space::Normal => " ",
+ Space::Nbsp => "&nbsp;",
+ Space::None => "",
+ })
+ }
+
+ fn render_word(&mut self, word: & str) -> () {
+ self.push_str(word)
+ }
+
+ fn render_mark(&mut self, mark: &str) -> () {
+ self.push_str(mark)
+ }
+
+ fn render_illformed(&mut self, err: &str) -> () {
+ self.push_str(err)
+ }
+
+ fn emph_template<F>(&mut self, format: F) -> ()
+ where
+ F : FnOnce(&mut Html) -> ()
+ {
+ self.push_str("<em>");
+ format(self);
+ self.push_str("</em>");
+ }
+
+ fn strong_emph_template<F>(&mut self, format: F) -> ()
+ where
+ F : FnOnce(&mut Html) -> ()
+ {
+ self.push_str("<strong>");
+ format(self);
+ self.push_str("</strong>");
+ }
+
+ fn reply_template<F>(&mut self, reply: F, _author: &Option<&str>) -> ()
+ where
+ F : FnOnce(&mut Html) -> ()
+ {
+ self.push_str("<span class=\"reply\">");
+ reply(self);
+ self.push_str("</span>");
+ }
+
+ fn thought_template<F>(&mut self, reply: F, author: &Option<&str>) -> ()
+ where
+ F : FnOnce(&mut Html) -> ()
+ {
+ self.push_str("<span class=\"thought");
+ author.map(|a| {
+ self.push_str(" by-");
+ self.push_str(a);
+ });
+ self.push_str("\">");
+ reply(self);
+ self.push_str("</span>");
+ }
+
+ fn dialogue_template<F>(&mut self, reply: F, author: &Option<&str>) -> ()
+ where
+ F : FnOnce(&mut Html) -> ()
+ {
+ self.push_str("<span class=\"dialogue");
+ author.map(|a| {
+ self.push_str(" by-");
+ self.push_str(a);
+ });
+ self.push_str("\">");
+ reply(self);
+ self.push_str("</span>");
+ }
+
+ fn between_dialogue(&mut self) -> () {
+ self.push_str("</p><p>");
+ }
+
+ fn illformed_inline_template<F>(&mut self, err: F) -> ()
+ where
+ F: FnOnce(&mut Html) -> ()
+ {
+ self.push_str("<span class=\"illformed_inline\">");
+ err(self);
+ self.push_str("</span>");
+ }
+
+ fn paragraph_template<F>(&mut self, para: F) -> ()
+ where
+ F : FnOnce(&mut Html) -> ()
+ {
+ self.push_str("<p>");
+ para(self);
+ self.push_str("</p>");
+ }
+
+ fn illformed_block_template<F>(&mut self, err: F) -> ()
+ where
+ F : FnOnce(&mut Html) -> ()
+ {
+ self.push_str("<div class=\"illformed_block\">");
+ err(self);
+ self.push_str("</div>");
+ }
+
+ fn story_template<F>(&mut self, story: F) -> ()
+ where
+ F : FnOnce(&mut Html) -> ()
+ {
+ self.push_str("<div class=\"story\">");
+ story(self);
+ self.push_str("</div>");
+ }
+
+ fn aside_template<F>(&mut self, cls: &Option<&str>, aside: F) -> ()
+ where
+ F : FnOnce(&mut Html) -> ()
+ {
+ self.push_str("<div class=\"aside");
+ cls.map(|c| {
+ self.push_str(" ");
+ self.push_str(c);
+ });
+ self.push_str("\">");
+ aside(self);
+ self.push_str("</div>");
+ }
+}