fix: TOC navigation and pagination improvements
- Fix recalculate_pages missing heading_top_spacing in page height calculation - Improve build_toc path matching: extract filename first, fall back to substring - Filter out EPUB3 nav.xhtml from content sections - Skip Windows resource compilation when windres is not available - Add unit tests for TOC filename matching and nav filtering
This commit is contained in:
186
Cargo.lock
generated
186
Cargo.lock
generated
@@ -1138,6 +1138,20 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embed-resource"
|
||||||
|
version = "2.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d506610004cfc74a6f5ee7e8c632b355de5eca1f03ee5e5e0ec11b77d4eb3d61"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"memchr",
|
||||||
|
"rustc_version",
|
||||||
|
"toml",
|
||||||
|
"vswhom",
|
||||||
|
"winreg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "endi"
|
name = "endi"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
@@ -1207,6 +1221,7 @@ name = "epub-read"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"eframe",
|
"eframe",
|
||||||
|
"embed-resource",
|
||||||
"epub",
|
"epub",
|
||||||
"image",
|
"image",
|
||||||
"rfd",
|
"rfd",
|
||||||
@@ -2827,7 +2842,7 @@ version = "3.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
|
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"toml_edit",
|
"toml_edit 0.25.11+spec-1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3293,6 +3308,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "0.6.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.10.6"
|
version = "0.10.6"
|
||||||
@@ -3626,6 +3650,27 @@ dependencies = [
|
|||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.8.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime 0.6.11",
|
||||||
|
"toml_edit 0.22.27",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.6.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "1.1.1+spec-1.1.0"
|
version = "1.1.1+spec-1.1.0"
|
||||||
@@ -3635,6 +3680,20 @@ dependencies = [
|
|||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_edit"
|
||||||
|
version = "0.22.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime 0.6.11",
|
||||||
|
"toml_write",
|
||||||
|
"winnow 0.7.15",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.25.11+spec-1.1.0"
|
version = "0.25.11+spec-1.1.0"
|
||||||
@@ -3642,9 +3701,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
|
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"toml_datetime",
|
"toml_datetime 1.1.1+spec-1.1.0",
|
||||||
"toml_parser",
|
"toml_parser",
|
||||||
"winnow",
|
"winnow 1.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3653,9 +3712,15 @@ version = "1.1.2+spec-1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
|
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winnow",
|
"winnow 1.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_write"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.44"
|
version = "0.1.44"
|
||||||
@@ -3797,6 +3862,26 @@ version = "0.9.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vswhom"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"vswhom-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vswhom-sys"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -4301,6 +4386,15 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
@@ -4337,6 +4431,21 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.48.5",
|
||||||
|
"windows_aarch64_msvc 0.48.5",
|
||||||
|
"windows_i686_gnu 0.48.5",
|
||||||
|
"windows_i686_msvc 0.48.5",
|
||||||
|
"windows_x86_64_gnu 0.48.5",
|
||||||
|
"windows_x86_64_gnullvm 0.48.5",
|
||||||
|
"windows_x86_64_msvc 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -4370,6 +4479,12 @@ dependencies = [
|
|||||||
"windows_x86_64_msvc 0.53.1",
|
"windows_x86_64_msvc 0.53.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -4382,6 +4497,12 @@ version = "0.53.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -4394,6 +4515,12 @@ version = "0.53.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -4418,6 +4545,12 @@ version = "0.53.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -4430,6 +4563,12 @@ version = "0.53.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -4442,6 +4581,12 @@ version = "0.53.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -4454,6 +4599,12 @@ version = "0.53.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -4518,6 +4669,15 @@ dependencies = [
|
|||||||
"xkbcommon-dl",
|
"xkbcommon-dl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.7.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@@ -4527,6 +4687,16 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen"
|
name = "wit-bindgen"
|
||||||
version = "0.51.0"
|
version = "0.51.0"
|
||||||
@@ -4796,7 +4966,7 @@ dependencies = [
|
|||||||
"uds_windows",
|
"uds_windows",
|
||||||
"uuid",
|
"uuid",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
"winnow",
|
"winnow 1.0.2",
|
||||||
"zbus_macros 5.15.0",
|
"zbus_macros 5.15.0",
|
||||||
"zbus_names 4.3.2",
|
"zbus_names 4.3.2",
|
||||||
"zvariant 5.11.0",
|
"zvariant 5.11.0",
|
||||||
@@ -4872,7 +5042,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52d"
|
checksum = "7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"winnow",
|
"winnow 1.0.2",
|
||||||
"zvariant 5.11.0",
|
"zvariant 5.11.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5028,7 +5198,7 @@ dependencies = [
|
|||||||
"enumflags2",
|
"enumflags2",
|
||||||
"serde",
|
"serde",
|
||||||
"url",
|
"url",
|
||||||
"winnow",
|
"winnow 1.0.2",
|
||||||
"zvariant_derive 5.11.0",
|
"zvariant_derive 5.11.0",
|
||||||
"zvariant_utils 3.3.1",
|
"zvariant_utils 3.3.1",
|
||||||
]
|
]
|
||||||
@@ -5080,5 +5250,5 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"serde",
|
"serde",
|
||||||
"syn",
|
"syn",
|
||||||
"winnow",
|
"winnow 1.0.2",
|
||||||
]
|
]
|
||||||
|
|||||||
10
build.rs
10
build.rs
@@ -1,6 +1,16 @@
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let windres_available = std::process::Command::new("where")
|
||||||
|
.arg("windres")
|
||||||
|
.output()
|
||||||
|
.map(|o| o.status.success())
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if windres_available {
|
||||||
embed_resource::compile("read.rc", embed_resource::NONE);
|
embed_resource::compile("read.rc", embed_resource::NONE);
|
||||||
|
} else {
|
||||||
|
println!("cargo:warning=windres not found, skipping Windows resource (icon) compilation");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
|||||||
90
src/book.rs
90
src/book.rs
@@ -248,7 +248,19 @@ pub fn load_epub(path: impl AsRef<Path>) -> Result<Book, String> {
|
|||||||
let title = doc.mdata("title").unwrap_or_else(|| "未知标题".to_string());
|
let title = doc.mdata("title").unwrap_or_else(|| "未知标题".to_string());
|
||||||
let author = doc.mdata("creator").unwrap_or_else(|| "未知作者".to_string());
|
let author = doc.mdata("creator").unwrap_or_else(|| "未知作者".to_string());
|
||||||
let cover = doc.get_cover().ok();
|
let cover = doc.get_cover().ok();
|
||||||
let spine = doc.spine.clone();
|
let spine: Vec<String> = doc.spine.iter()
|
||||||
|
.filter(|id| {
|
||||||
|
if id.as_str() == "nav" { return false; }
|
||||||
|
if let Some((path, _)) = doc.resources.get(*id) {
|
||||||
|
let path_str = path.to_string_lossy().to_lowercase();
|
||||||
|
if path_str.ends_with("nav.xhtml") || path_str.ends_with("nav.html") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
let mut sections = Vec::new();
|
let mut sections = Vec::new();
|
||||||
for (i, href) in spine.iter().enumerate() {
|
for (i, href) in spine.iter().enumerate() {
|
||||||
@@ -290,6 +302,11 @@ fn extract_title(html: &str) -> Option<String> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extract_filename(path: &str) -> &str {
|
||||||
|
let path = path.trim_end_matches('/');
|
||||||
|
path.rsplit('/').next().unwrap_or(path)
|
||||||
|
}
|
||||||
|
|
||||||
fn build_toc(
|
fn build_toc(
|
||||||
entries: &[epub::doc::NavPoint],
|
entries: &[epub::doc::NavPoint],
|
||||||
spine: &[String],
|
spine: &[String],
|
||||||
@@ -298,10 +315,15 @@ fn build_toc(
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|e| {
|
.map(|e| {
|
||||||
let content_str = e.content.to_string_lossy();
|
let content_str = e.content.to_string_lossy();
|
||||||
|
let content_file = extract_filename(&content_str);
|
||||||
let section = spine
|
let section = spine
|
||||||
.iter()
|
.iter()
|
||||||
.position(|s| content_str.contains(s.trim_end_matches('/')))
|
.position(|s| {
|
||||||
// unwrap_or(0) is safe: a real TOC entry should always match a spine item
|
let spine_file = extract_filename(s);
|
||||||
|
spine_file == content_file
|
||||||
|
|| content_str.contains(s.as_str())
|
||||||
|
|| s.contains(content_str.as_ref())
|
||||||
|
})
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
TocEntry {
|
TocEntry {
|
||||||
label: e.label.clone(),
|
label: e.label.clone(),
|
||||||
@@ -439,4 +461,66 @@ mod tests {
|
|||||||
let toc = build_toc(&[], &[]);
|
let toc = build_toc(&[], &[]);
|
||||||
assert!(toc.is_empty());
|
assert!(toc.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_sample_epub_nav_filtered() {
|
||||||
|
let book = load_epub("sample-short.epub").expect("Failed to load sample epub");
|
||||||
|
// Nav document is filtered out, leaving only chapter_0 as the single section
|
||||||
|
assert_eq!(book.sections.len(), 1);
|
||||||
|
assert_eq!(book.sections[0].title, "Understanding Digital Formats");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_toc_section_bounds() {
|
||||||
|
let book = load_epub("sample-short.epub").expect("Failed to load sample epub");
|
||||||
|
// All TOC section indices should be within sections range
|
||||||
|
fn check_bounds(entries: &[TocEntry], max: usize) {
|
||||||
|
for e in entries {
|
||||||
|
assert!(e.section < max, "TOC entry '{}' maps to section {} but only {} sections exist", e.label, e.section, max);
|
||||||
|
check_bounds(&e.children, max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check_bounds(&book.toc, book.sections.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_toc_filename_matching() {
|
||||||
|
use epub::doc::NavPoint;
|
||||||
|
let spine = vec![
|
||||||
|
"OEBPS/Text/chapter1.xhtml".to_string(),
|
||||||
|
"OEBPS/Text/chapter2.xhtml".to_string(),
|
||||||
|
];
|
||||||
|
let nav_points = vec![
|
||||||
|
NavPoint {
|
||||||
|
label: "Chapter 2".to_string(),
|
||||||
|
content: std::path::PathBuf::from("Text/chapter2.xhtml"),
|
||||||
|
play_order: 1,
|
||||||
|
children: vec![],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let toc = build_toc(&nav_points, &spine);
|
||||||
|
assert_eq!(toc.len(), 1);
|
||||||
|
assert_eq!(toc[0].section, 1); // maps to spine index 1
|
||||||
|
assert_eq!(toc[0].label, "Chapter 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_toc_exact_path_match() {
|
||||||
|
use epub::doc::NavPoint;
|
||||||
|
let spine = vec![
|
||||||
|
"chapter1.xhtml".to_string(),
|
||||||
|
"chapter2.xhtml".to_string(),
|
||||||
|
];
|
||||||
|
let nav_points = vec![
|
||||||
|
NavPoint {
|
||||||
|
label: "Chapter 1".to_string(),
|
||||||
|
content: std::path::PathBuf::from("chapter1.xhtml"),
|
||||||
|
play_order: 1,
|
||||||
|
children: vec![],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let toc = build_toc(&nav_points, &spine);
|
||||||
|
assert_eq!(toc.len(), 1);
|
||||||
|
assert_eq!(toc[0].section, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,7 +151,11 @@ pub fn recalculate_pages(
|
|||||||
let block_height = measure_block_height(ctx, &display_text, block_font_size, available_width);
|
let block_height = measure_block_height(ctx, &display_text, block_font_size, available_width);
|
||||||
|
|
||||||
let spacing = if i > page_start_block && i > 0 {
|
let spacing = if i > page_start_block && i > 0 {
|
||||||
|
if block.heading_level > 0 {
|
||||||
|
para_spacing + heading_top_spacing(para_spacing, block.heading_level)
|
||||||
|
} else {
|
||||||
para_spacing
|
para_spacing
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user