From bd0e61b47c99255ff4cc07ec09c05c2e44e82dbb Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 18 May 2026 18:52:32 +0900 Subject: [PATCH 1/8] introduce office pdf oxide --- Cargo.lock | 613 +++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 4 +- src/app.rs | 6 + src/search.rs | 101 +++++-- tests/search_tests.rs | 1 + 5 files changed, 696 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2febb7e..998004b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,6 +127,17 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aes" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66bd29a732b644c0431c6140f370d097879203d79b80c94a6747ba0872adaef8" +dependencies = [ + "cipher", + "cpubits", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.8.12" @@ -167,6 +178,21 @@ dependencies = [ "equator", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -207,6 +233,56 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + [[package]] name = "anyhow" version = "1.0.102" @@ -417,6 +493,16 @@ dependencies = [ "syn", ] +[[package]] +name = "atoi_simd" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cdb3708a128e559a30fb830e8a77a5022ee6902806925c216658652b452a44" +dependencies = [ + "debug_unsafe", + "rustversion", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -509,6 +595,12 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bit-set" version = "0.9.1" @@ -551,6 +643,24 @@ dependencies = [ "no_std_io2", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "block-padding" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block2" version = "0.5.1" @@ -582,6 +692,27 @@ dependencies = [ "piper", ] +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bstr" version = "1.12.1" @@ -625,6 +756,12 @@ dependencies = [ "syn", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "byteorder-lite" version = "0.1.0" @@ -688,6 +825,15 @@ dependencies = [ "wayland-client", ] +[[package]] +name = "cbc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98db6aeaef0eeef2c1e3ce9a27b739218825dae116076352ac3777076aa22225" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.2.62" @@ -734,6 +880,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "cipher" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clipboard-win" version = "5.4.1" @@ -769,6 +925,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "combine" version = "4.6.7" @@ -788,6 +950,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "core-foundation" version = "0.9.4" @@ -838,6 +1006,21 @@ dependencies = [ "libc", ] +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -878,12 +1061,27 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", +] + [[package]] name = "cursor-icon" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" +[[package]] +name = "debug_unsafe" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eed2c4702fa172d1ce21078faa7c5203e69f5394d48cc436d25928394a867a2" + [[package]] name = "deranged" version = "0.5.8" @@ -893,6 +1091,17 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -1169,6 +1378,29 @@ dependencies = [ "syn", ] +[[package]] +name = "env_filter" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + [[package]] name = "epaint" version = "0.34.2" @@ -1180,13 +1412,13 @@ dependencies = [ "ecolor", "emath", "epaint_default_fonts", - "font-types", + "font-types 0.11.3", "log", "nohash-hasher", "parking_lot", "profiling", "self_cell", - "skrifa", + "skrifa 0.40.0", "smallvec", "vello_cpu", ] @@ -1284,6 +1516,12 @@ dependencies = [ "zune-inflate", ] +[[package]] +name = "fast-float2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8eb564c5c7423d25c886fb561d1e4ee69f72354d16918afa32c08811f6b6a55" + [[package]] name = "fastrand" version = "2.4.1" @@ -1328,6 +1566,7 @@ checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", + "zlib-rs", ] [[package]] @@ -1342,6 +1581,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +[[package]] +name = "font-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a654f404bbcbd48ea58c617c2993ee91d1cb63727a37bf2323a4edeed1b8c5" +dependencies = [ + "bytemuck", +] + [[package]] name = "font-types" version = "0.11.3" @@ -1471,10 +1719,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", "wasip2", "wasip3", + "wasm-bindgen", ] [[package]] @@ -1702,6 +1952,12 @@ dependencies = [ "memmap2", ] +[[package]] +name = "grid" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b40ca9252762c466af32d0b1002e91e4e1bc5398f77455e55474deb466355ff5" + [[package]] name = "half" version = "2.7.1" @@ -1764,6 +2020,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -1965,6 +2230,16 @@ dependencies = [ "serde_core", ] +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "block-padding", + "hybrid-array", +] + [[package]] name = "interpolate_name" version = "0.2.4" @@ -1995,6 +2270,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itertools" version = "0.14.0" @@ -2010,6 +2291,30 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jiff" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "jni" version = "0.22.4" @@ -2078,6 +2383,15 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" +dependencies = [ + "rayon", +] + [[package]] name = "js-sys" version = "0.3.98" @@ -2107,6 +2421,17 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "kurbo" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce9729cc38c18d86123ab736fd2e7151763ba226ac2490ec092d1dd148825e32" +dependencies = [ + "arrayvec", + "euclid", + "smallvec", +] + [[package]] name = "kurbo" version = "0.13.0" @@ -2132,7 +2457,7 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "lexi" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", "chrono", @@ -2143,7 +2468,9 @@ dependencies = [ "ignore", "image", "log", + "office_oxide", "open", + "pdf_oxide", "quoted_printable", "regex", "rfd", @@ -2260,6 +2587,16 @@ dependencies = [ "rayon", ] +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.8.0" @@ -2812,12 +3149,36 @@ dependencies = [ "objc2-foundation 0.2.2", ] +[[package]] +name = "office_oxide" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "866a8fa5e1a756f8cc9f9f614031ad7e33adc7f6972eab74a35b0c799fe08da5" +dependencies = [ + "atoi_simd", + "encoding_rs", + "fast-float2", + "libc", + "log", + "quick-xml 0.40.1", + "serde", + "serde_json", + "thiserror 2.0.18", + "zip", +] + [[package]] name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "open" version = "5.3.5" @@ -2914,6 +3275,52 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +[[package]] +name = "pdf_oxide" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c512f3d7e8feac18e94ee08995d5c12d0fb86375ff4b03f931a11c808276eff4" +dependencies = [ + "aes", + "base64", + "bitflags 2.11.1", + "brotli", + "byteorder", + "bytes", + "cbc", + "chrono", + "encoding_rs", + "env_logger", + "fax", + "flate2", + "getrandom 0.4.2", + "image", + "jpeg-decoder", + "libc", + "log", + "md-5", + "memchr", + "nom", + "office_oxide", + "phf 0.13.1", + "qcms", + "quick-xml 0.39.4", + "regex", + "serde", + "serde_json", + "sha2", + "smallvec", + "stringprep", + "subsetter", + "taffy", + "thiserror 2.0.18", + "ttf-parser", + "unicode-bidi", + "unicode-linebreak", + "uuid", + "weezl", +] + [[package]] name = "peniko" version = "0.6.0" @@ -2922,7 +3329,7 @@ checksum = "9a2b6aadb221872732e87d465213e9be5af2849b0e8cc5300a8ba98fffa2e00a" dependencies = [ "bytemuck", "color", - "kurbo", + "kurbo 0.13.0", "linebender_resource_handle", "smallvec", ] @@ -3200,6 +3607,12 @@ version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" +[[package]] +name = "qcms" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edecfcd5d755a5e5d98e24cf43113e7cdaec5a070edd0f6b250c03a573da30fa" + [[package]] name = "qoi" version = "0.4.1" @@ -3225,6 +3638,16 @@ dependencies = [ "serde", ] +[[package]] +name = "quick-xml" +version = "0.40.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2474bd2e5029e7ccb6abb2ba48cf2383a333851dedf495901544281590c7da7f" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quote" version = "1.0.45" @@ -3390,6 +3813,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "read-fonts" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" +dependencies = [ + "bytemuck", + "font-types 0.10.1", +] + [[package]] name = "read-fonts" version = "0.37.0" @@ -3397,7 +3830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" dependencies = [ "bytemuck", - "font-types", + "font-types 0.11.3", ] [[package]] @@ -3657,6 +4090,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" @@ -3721,6 +4165,16 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" +[[package]] +name = "skrifa" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" +dependencies = [ + "bytemuck", + "read-fonts 0.35.0", +] + [[package]] name = "skrifa" version = "0.40.0" @@ -3728,7 +4182,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" dependencies = [ "bytemuck", - "read-fonts", + "read-fonts 0.37.0", ] [[package]] @@ -3851,6 +4305,29 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "subsetter" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6895a12ac5599bb6057362f00e8a3cf1daab4df33f553a55690a44e4fed8d0" +dependencies = [ + "kurbo 0.12.0", + "rustc-hash 2.1.2", + "skrifa 0.37.0", + "write-fonts", +] + [[package]] name = "syn" version = "2.0.117" @@ -3873,6 +4350,18 @@ dependencies = [ "syn", ] +[[package]] +name = "taffy" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aea22054047c16c3f34d3ac473a2170be1424b1115b2a3adcf28cfb067c88859" +dependencies = [ + "arrayvec", + "grid", + "serde", + "slotmap", +] + [[package]] name = "tempfile" version = "3.27.0" @@ -4017,6 +4506,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "toml" version = "1.1.2+spec-1.1.0" @@ -4115,6 +4619,18 @@ dependencies = [ "rustc-hash 2.1.2", ] +[[package]] +name = "typed-path" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" + +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + [[package]] name = "uds_windows" version = "1.2.1" @@ -4132,12 +4648,39 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + [[package]] name = "unicode-segmentation" version = "1.13.2" @@ -4174,12 +4717,19 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ + "getrandom 0.4.2", "js-sys", "serde_core", "wasm-bindgen", @@ -4207,7 +4757,7 @@ dependencies = [ "hashbrown 0.16.1", "log", "peniko", - "skrifa", + "skrifa 0.40.0", "smallvec", ] @@ -4464,7 +5014,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" dependencies = [ "proc-macro2", - "quick-xml", + "quick-xml 0.39.4", "quote", ] @@ -5149,6 +5699,19 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "write-fonts" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "886614b5ce857341226aa091f3c285e450683894acaaa7887f366c361efef79d" +dependencies = [ + "font-types 0.10.1", + "indexmap", + "kurbo 0.12.0", + "log", + "read-fonts 0.35.0", +] + [[package]] name = "writeable" version = "0.6.3" @@ -5338,7 +5901,7 @@ version = "5.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8067892e940ed1727dea64690378601603b31d62dfde019a5335fbb7c0e0ed9" dependencies = [ - "quick-xml", + "quick-xml 0.39.4", "serde", "zbus_names", "zvariant", @@ -5418,12 +5981,44 @@ dependencies = [ "syn", ] +[[package]] +name = "zip" +version = "8.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" +dependencies = [ + "crc32fast", + "flate2", + "indexmap", + "memchr", + "typed-path", + "zopfli", +] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + [[package]] name = "zune-core" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 444d463..f9cbd18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lexi" -version = "0.1.0" +version = "0.2.0" edition = "2024" [dependencies] @@ -18,6 +18,8 @@ rfd = "0.17" quoted_printable = "0.5" log = "0.4" simplelog = "0.12" +pdf_oxide = "0.3.50" +office_oxide = "0.1.2" [dev-dependencies] tempfile = "3.10" diff --git a/src/app.rs b/src/app.rs index 647742e..90522fb 100644 --- a/src/app.rs +++ b/src/app.rs @@ -491,6 +491,12 @@ impl SearchApp { { input_changed = true; } + if ui + .checkbox(&mut tab.config.search_doc_content, "문서 내부 검색") + .changed() + { + input_changed = true; + } }); ui.add_space(5.0); diff --git a/src/search.rs b/src/search.rs index de917a4..19a5845 100644 --- a/src/search.rs +++ b/src/search.rs @@ -208,6 +208,7 @@ pub struct SearchConfig { pub patterns: String, pub queries: Vec, pub file_name_only: bool, + pub search_doc_content: bool, } impl SearchConfig { @@ -218,6 +219,7 @@ impl SearchConfig { patterns, queries: vec![SearchQuery::new()], file_name_only: false, + search_doc_content: false, } } @@ -228,16 +230,25 @@ impl SearchConfig { /// Parses the pattern string (e.g., "*.rs *.md") into a glob override object. pub fn overrides(&self) -> Override { - if self.patterns.is_empty() { - Override::empty() - } else { - let mut builder = OverrideBuilder::new( - std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")), - ); - for glob in self.patterns.split_whitespace() { + let mut builder = OverrideBuilder::new( + std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")), + ); + let mut final_patterns = self.patterns.clone(); + if self.search_doc_content { + let doc_patterns = "*.docx *.pptx *.xlsx *.pdf *.doc *.ppt *.xls *.eml"; + if final_patterns.is_empty() { + final_patterns = doc_patterns.to_string(); + } else { + final_patterns = format!("{} {}", final_patterns, doc_patterns); + } + } + if !final_patterns.is_empty() { + for glob in final_patterns.split_whitespace() { let _ = builder.add(glob); } builder.build().unwrap_or_else(|_| Override::empty()) + } else { + Override::empty() } } @@ -273,6 +284,7 @@ pub fn spawn_search(config: &SearchConfig) -> Result { // Create variables for the search configuration. let matcher = config.create_matcher()?; let file_name_only = config.file_name_only; + let search_doc_content = config.search_doc_content; let paths = config.paths(); if paths.is_empty() { bail!("No search paths provided"); @@ -339,18 +351,69 @@ pub fn spawn_search(config: &SearchConfig) -> Result { // Second pass: scan file content (unless "File name only" mode is on). if !file_name_only { let mut handled = false; - // Korean .eml files often use Quoted-Printable encoding for the body. - if path.extension().is_some_and(|ext| ext == "eml") - && let Ok(content) = std::fs::read(path) - && let Ok(decoded) = - quoted_printable::decode(&content, quoted_printable::ParseMode::Robust) - { - let mut sink = SearchSink { - results: &mut entries, - matcher: &matcher, - }; - let _ = searcher.search_slice(&*matcher, &decoded, &mut sink); - handled = true; + let extension = path + .extension() + .and_then(|ext| ext.to_str()) + .unwrap_or("") + .to_lowercase(); + + if search_doc_content { + match extension.as_str() { + "docx" | "pptx" | "xlsx" | "doc" | "ppt" | "xls" => { + if let Ok(text) = office_oxide::extract_text(path) { + let mut sink = SearchSink { + results: &mut entries, + matcher: &matcher, + }; + let _ = searcher.search_slice( + &*matcher, + text.as_bytes(), + &mut sink, + ); + handled = true; + } + } + "pdf" => { + if let Ok(doc) = pdf_oxide::PdfDocument::open(path) { + let mut full_pdf_text = String::new(); + let mut page = 0; + while let Ok(page_text) = doc.extract_text(page) { + full_pdf_text.push_str(&page_text); + full_pdf_text.push('\n'); + page += 1; + } + if !full_pdf_text.is_empty() { + let mut sink = SearchSink { + results: &mut entries, + matcher: &matcher, + }; + let _ = searcher.search_slice( + &*matcher, + full_pdf_text.as_bytes(), + &mut sink, + ); + handled = true; + } + } + } + // Korean .eml files often use Quoted-Printable encoding for the body. + "eml" => { + if let Ok(content) = std::fs::read(path) + && let Ok(decoded) = quoted_printable::decode( + &content, + quoted_printable::ParseMode::Robust, + ) + { + let mut sink = SearchSink { + results: &mut entries, + matcher: &matcher, + }; + let _ = searcher.search_slice(&*matcher, &decoded, &mut sink); + handled = true; + } + } + _ => {} + } } if !handled { diff --git a/tests/search_tests.rs b/tests/search_tests.rs index 165aaab..a85de84 100644 --- a/tests/search_tests.rs +++ b/tests/search_tests.rs @@ -155,6 +155,7 @@ fn test_search_korean_qp_eml() { vec![dir.path().to_string_lossy().to_string()], "".to_string(), ); + config.search_doc_content = true; config.queries[0].query = "안녕".to_string(); let pending = spawn_search(&config).unwrap(); From 4ba22af26d2d77116aa736e3b8ea107c548e76ca Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 May 2026 09:02:58 +0900 Subject: [PATCH 2/8] fix checkbox label --- src/app.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app.rs b/src/app.rs index 90522fb..4910e27 100644 --- a/src/app.rs +++ b/src/app.rs @@ -486,13 +486,13 @@ impl SearchApp { input_changed = true; } if ui - .checkbox(&mut tab.config.file_name_only, "파일명만 검색") + .checkbox(&mut tab.config.file_name_only, "파일명만") .changed() { input_changed = true; } if ui - .checkbox(&mut tab.config.search_doc_content, "문서 내부 검색") + .checkbox(&mut tab.config.search_doc_content, "문서내용도") .changed() { input_changed = true; From c1fa742079aaa7ca852ee06091db54fd869036fb Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 May 2026 11:24:16 +0900 Subject: [PATCH 3/8] restore override --- src/app.rs | 2 +- src/search.rs | 23 +++++++---------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/app.rs b/src/app.rs index 4910e27..b598900 100644 --- a/src/app.rs +++ b/src/app.rs @@ -579,7 +579,7 @@ impl SearchApp { .column(Column::remainder().clip(true)) .header(20.0, |mut header| { header.col(|ui| { - ui.label("파일"); + ui.label("파일명"); }); header.col(|ui| { ui.label("라인"); diff --git a/src/search.rs b/src/search.rs index 19a5845..391ec14 100644 --- a/src/search.rs +++ b/src/search.rs @@ -230,25 +230,16 @@ impl SearchConfig { /// Parses the pattern string (e.g., "*.rs *.md") into a glob override object. pub fn overrides(&self) -> Override { - let mut builder = OverrideBuilder::new( - std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")), - ); - let mut final_patterns = self.patterns.clone(); - if self.search_doc_content { - let doc_patterns = "*.docx *.pptx *.xlsx *.pdf *.doc *.ppt *.xls *.eml"; - if final_patterns.is_empty() { - final_patterns = doc_patterns.to_string(); - } else { - final_patterns = format!("{} {}", final_patterns, doc_patterns); - } - } - if !final_patterns.is_empty() { - for glob in final_patterns.split_whitespace() { + if self.patterns.is_empty() { + Override::empty() + } else { + let mut builder = OverrideBuilder::new( + std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")), + ); + for glob in self.patterns.split_whitespace() { let _ = builder.add(glob); } builder.build().unwrap_or_else(|_| Override::empty()) - } else { - Override::empty() } } From e828047c1cfc2b2d4c63505ac61fae0c5fa2b301 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 May 2026 14:54:52 +0900 Subject: [PATCH 4/8] let checkbox disable each other --- src/app.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/app.rs b/src/app.rs index b598900..c2bb218 100644 --- a/src/app.rs +++ b/src/app.rs @@ -490,12 +490,18 @@ impl SearchApp { .changed() { input_changed = true; + if tab.config.file_name_only { + tab.config.search_doc_content = false; + } } if ui .checkbox(&mut tab.config.search_doc_content, "문서내용도") .changed() { input_changed = true; + if tab.config.search_doc_content { + tab.config.file_name_only = false; + } } }); From 6d1ba713a76afda9a99f9ef8fabda1b2eee0f482 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 May 2026 11:58:22 +0900 Subject: [PATCH 5/8] ui --- src/app.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app.rs b/src/app.rs index c2bb218..e8560b1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -487,6 +487,7 @@ impl SearchApp { } if ui .checkbox(&mut tab.config.file_name_only, "파일명만") + .on_hover_text("파일명만 검색합니다.") .changed() { input_changed = true; @@ -495,7 +496,8 @@ impl SearchApp { } } if ui - .checkbox(&mut tab.config.search_doc_content, "문서내용도") + .checkbox(&mut tab.config.search_doc_content, "문서 내용도") + .on_hover_text("pdf, docx, pptx, xlsx 내용도 검색합니다.") .changed() { input_changed = true; From 1062bc85e80ec0e166a9faf1229a715ba0be6df2 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 May 2026 14:38:20 +0900 Subject: [PATCH 6/8] move commemt --- src/search.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.rs b/src/search.rs index 391ec14..1cd3b77 100644 --- a/src/search.rs +++ b/src/search.rs @@ -212,7 +212,7 @@ pub struct SearchConfig { } impl SearchConfig { - // Creates a new search config with the given paths and patterns. + /// Creates a new search config with the given paths and patterns. pub fn new(paths: Vec, patterns: String) -> Self { Self { paths, @@ -387,8 +387,8 @@ pub fn spawn_search(config: &SearchConfig) -> Result { } } } - // Korean .eml files often use Quoted-Printable encoding for the body. "eml" => { + // Korean .eml files often use Quoted-Printable encoding for the body. if let Ok(content) = std::fs::read(path) && let Ok(decoded) = quoted_printable::decode( &content, From e796ee295c1f338d0136e03496f44b18abe57518 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 May 2026 14:40:49 +0900 Subject: [PATCH 7/8] remove space --- src/app.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.rs b/src/app.rs index e8560b1..6cafc57 100644 --- a/src/app.rs +++ b/src/app.rs @@ -496,7 +496,7 @@ impl SearchApp { } } if ui - .checkbox(&mut tab.config.search_doc_content, "문서 내용도") + .checkbox(&mut tab.config.search_doc_content, "문서내용도") .on_hover_text("pdf, docx, pptx, xlsx 내용도 검색합니다.") .changed() { From 675051db4b0c690bc5dac357297b326a40952c97 Mon Sep 17 00:00:00 2001 From: RektPunk Date: Thu, 21 May 2026 14:42:28 +0900 Subject: [PATCH 8/8] Replace image in README.md Updated the image in the README to a new version. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5543712..81a1b56 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # Lexi 윈도우 기본 검색 쓰다가 답답해서 직접 만든 파일 검색기 -image +image