diff --git a/.cargo/config.toml b/.cargo/config.toml index d47f983..ed561c7 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -9,3 +9,9 @@ rustflags = [ "-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup", ] + +[target.x86_64-unknown-linux-musl] +rustflags = ["-C", "target-feature=-crt-static"] + +[target.aarch64-unknown-linux-musl] +rustflags = ["-C", "target-feature=-crt-static"] diff --git a/generator/Cargo.lock b/generator/Cargo.lock index 7ad648b..d277eab 100644 --- a/generator/Cargo.lock +++ b/generator/Cargo.lock @@ -1,12 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" @@ -31,15 +31,36 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "arboard" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" +checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" dependencies = [ "clipboard-win", "core-graphics", @@ -56,21 +77,21 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "base64" @@ -108,6 +129,16 @@ dependencies = [ "objc2", ] +[[package]] +name = "bstr" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -116,18 +147,18 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.16.1" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", @@ -149,7 +180,7 @@ dependencies = [ "ahash", "cached_proc_macro", "cached_proc_macro_types", - "hashbrown", + "hashbrown 0.14.5", "once_cell", "thiserror", "web-time", @@ -175,9 +206,12 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cc" -version = "1.1.6" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -191,6 +225,20 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.6", +] + [[package]] name = "clipboard-win" version = "5.4.0" @@ -200,6 +248,30 @@ dependencies = [ "error-code", ] +[[package]] +name = "codesnap" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c21b08e3ff00129f07650e6f607193f2688003035e400ec2417b762cdf9ba8" +dependencies = [ + "anyhow", + "arboard", + "base64", + "cached", + "chrono", + "cosmic-text", + "derive_builder", + "once_cell", + "regex", + "rgb", + "serde", + "serde_json", + "syntect", + "thiserror", + "tiny-skia", + "two-face", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -212,9 +284,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-graphics" @@ -242,16 +314,16 @@ dependencies = [ [[package]] name = "cosmic-text" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70b7eecd441fdfc092d6afcb4d00a521ee6d3dc3ad882575ce13bf38be53fb71" +checksum = "59fd57d82eb4bfe7ffa9b1cec0c05e2fd378155b47f255a67983cb4afe0e80c2" dependencies = [ "bitflags 2.6.0", "fontdb", "log", "rangemap", "rayon", - "rustc-hash", + "rustc-hash 1.1.0", "rustybuzz", "self_cell", "swash", @@ -352,6 +424,37 @@ dependencies = [ "syn", ] +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn", +] + [[package]] name = "dlib" version = "0.5.2" @@ -379,33 +482,43 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erased-serde" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +dependencies = [ + "serde", + "typeid", +] + [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "error-code" -version = "3.2.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fdeflate" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb" dependencies = [ "simd-adler32", ] @@ -418,9 +531,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -434,18 +547,18 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "font-types" -version = "0.5.5" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34fd7136aca682873d859ef34494ab1a7d3f57ecd485ed40eb6437ee8c85aa29" +checksum = "b3971f9a5ca983419cdc386941ba3b9e1feba01a0ab888adf78739feb2798492" dependencies = [ "bytemuck", ] [[package]] name = "fontconfig-parser" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a595cb550439a117696039dfc69830492058211b771a2a165379f2a1a53d84d" +checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" dependencies = [ "roxmltree", ] @@ -495,16 +608,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" name = "generator" version = "0.1.0" dependencies = [ - "arboard", - "cached", - "cosmic-text", - "nvim-oxi", - "regex", + "codesnap", + "mlua", "serde", - "syntect", - "thiserror", - "tiny-skia", - "two-face", ] [[package]] @@ -528,12 +634,32 @@ dependencies = [ ] [[package]] -name = "home" -version = "0.5.9" +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "iana-time-zone" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ - "windows-sys 0.52.0", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", ] [[package]] @@ -544,9 +670,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "image" -version = "0.25.2" +version = "0.25.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" dependencies = [ "bytemuck", "byteorder-lite", @@ -557,19 +683,19 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jpeg-decoder" @@ -579,18 +705,18 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.155" +version = "0.2.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36" [[package]] name = "libloading" @@ -604,9 +730,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "linked-hash-map" @@ -644,9 +770,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] @@ -659,14 +785,54 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", "simd-adler32", ] +[[package]] +name = "mlua" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae9546e4a268c309804e8bbb7526e31cbfdedca7cd60ac1b987d0b212e0d876" +dependencies = [ + "bstr", + "either", + "erased-serde", + "mlua-sys", + "mlua_derive", + "num-traits", + "parking_lot", + "rustc-hash 2.0.0", + "serde", + "serde-value", +] + +[[package]] +name = "mlua-sys" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa6bf1a64f06848749b7e7727417f4ec2121599e2a10ef0a8a3888b0e9a5a0d" +dependencies = [ + "cc", + "cfg-if", + "pkg-config", +] + +[[package]] +name = "mlua_derive" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cfc5faa2e0d044b3f5f0879be2920e0a711c97744c42cf1c295cb183668933e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "nix" version = "0.28.0" @@ -704,76 +870,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "nvim-oxi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13587f8434641462a0674bc575fb1ca88d66827118470df3c2608e769fc8e3ee" -dependencies = [ - "nvim-oxi-api", - "nvim-oxi-libuv", - "nvim-oxi-luajit", - "nvim-oxi-macros", - "nvim-oxi-types", - "thiserror", -] - -[[package]] -name = "nvim-oxi-api" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0926b8fac04e376a743a7519382ef21c9d6e3ef584338d439972b911e5d85554" -dependencies = [ - "nvim-oxi-luajit", - "nvim-oxi-macros", - "nvim-oxi-types", - "serde", - "serde_repr", - "thiserror", -] - -[[package]] -name = "nvim-oxi-libuv" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c92031113da2a83addafb6d50508f96941f017ee2249b1d27b08094355cefd" -dependencies = [ - "nvim-oxi-luajit", - "thiserror", -] - -[[package]] -name = "nvim-oxi-luajit" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d83bb0ca6908c82bad8b22379f7577d0d82aa050601c0dce15d7c691c2131a" -dependencies = [ - "thiserror", -] - -[[package]] -name = "nvim-oxi-macros" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0db91ed44967f43c9ac9f80ce629391f53787aac6212aac79966422940671f9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "nvim-oxi-types" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2545fa96873e7bc0bd12e1e68582a89ca593fad872e996e479a8615ae986424" -dependencies = [ - "libc", - "nvim-oxi-luajit", - "serde", - "thiserror", -] - [[package]] name = "objc-sys" version = "0.3.5" @@ -875,9 +971,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "onig" @@ -901,14 +997,23 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "os_pipe" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d73ba8daf8fac13b0501d1abeddcfe21ba7401ada61a819144b6c2a4f32209" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -946,9 +1051,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plist" @@ -965,9 +1070,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.13" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -984,9 +1089,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1002,18 +1107,18 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.34.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f24d770aeca0eacb81ac29dfbc55ebcc09312fdd1f8bbecdc7e4a84e000e3b4" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1046,9 +1151,9 @@ dependencies = [ [[package]] name = "read-fonts" -version = "0.19.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b8af39d1f23869711ad4cea5e7835a20daa987f80232f7f2a2374d648ca64d" +checksum = "4a04b892cb6f91951f144c33321843790c8574c825aafdb16d815fd7183b5229" dependencies = [ "bytemuck", "font-types", @@ -1056,18 +1161,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -1077,9 +1182,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1088,15 +1193,24 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rgb" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] [[package]] name = "roxmltree" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" [[package]] name = "rustc-hash" @@ -1104,11 +1218,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", @@ -1169,18 +1289,28 @@ checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -1189,9 +1319,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.121" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -1200,15 +1330,10 @@ dependencies = [ ] [[package]] -name = "serde_repr" -version = "0.1.19" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "simd-adler32" @@ -1218,9 +1343,9 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "skrifa" -version = "0.19.3" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab45fb68b53576a43d4fc0e9ec8ea64e29a4d2cc7f44506964cb75f288222e9" +checksum = "8e1c44ad1f6c5bdd4eefed8326711b7dbda9ea45dfd36068c427d332aa382cbe" dependencies = [ "bytemuck", "read-fonts", @@ -1255,9 +1380,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "swash" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d7773d67fe3373048cf840bfcc54ec3207cfc1e95c526b287ef2eb5eff9faf6" +checksum = "cbd59f3f359ddd2c95af4758c18270eddd9c730dde98598023cdabff472c2ca2" dependencies = [ "skrifa", "yazi", @@ -1266,9 +1391,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", @@ -1299,39 +1424,40 @@ dependencies = [ [[package]] name = "sys-locale" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" dependencies = [ "libc", ] [[package]] name = "tempfile" -version = "3.10.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -1423,12 +1549,11 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tree_magic_mini" -version = "3.1.5" +version = "3.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469a727cac55b41448315cc10427c069c618ac59bb6a4480283fcd811749bdc2" +checksum = "aac5e8971f245c3389a5a76e648bfc80803ae066a1243a75db0064d7c1129d63" dependencies = [ "fnv", - "home", "memchr", "nom", "once_cell", @@ -1458,11 +1583,17 @@ dependencies = [ "syntect", ] +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-bidi-mirroring" @@ -1478,9 +1609,9 @@ checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-linebreak" @@ -1490,21 +1621,21 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-script" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d71f5726e5f285a935e9fe8edfd53f0491eb6e9a5774097fdabee7cd8c9cd" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "version_check" @@ -1524,19 +1655,20 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -1549,9 +1681,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1559,9 +1691,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -1572,15 +1704,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wayland-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" dependencies = [ "cc", "downcast-rs", @@ -1592,9 +1724,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.5" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e321577a0a165911bdcfb39cf029302479d7527b517ee58ab0f6ad09edf0943" +checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" dependencies = [ "bitflags 2.6.0", "rustix", @@ -1629,20 +1761,20 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.4" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7b56f89937f1cf2ee1f1259cf2936a17a1f45d8f0aa1019fae6d470d304cfa6" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" dependencies = [ "proc-macro2", - "quick-xml 0.34.0", + "quick-xml 0.36.2", "quote", ] [[package]] name = "wayland-sys" -version = "0.31.4" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" dependencies = [ "dlib", "log", @@ -1667,11 +1799,20 @@ checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -1692,6 +1833,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" diff --git a/generator/Cargo.toml b/generator/Cargo.toml index f36125c..349c0cf 100644 --- a/generator/Cargo.toml +++ b/generator/Cargo.toml @@ -3,17 +3,11 @@ name = "generator" version = "0.1.0" edition = "2021" -[dependencies] -nvim-oxi = { features = ["neovim-0-9", "libuv"], version = "0.5.1" } -tiny-skia = "0.11.4" -syntect = "5.2.0" -cosmic-text = "0.12.0" -serde = "1.0.204" -arboard = { features = ["wayland-data-control"], version = "3.4.0" } -thiserror = "1.0.63" -regex = "1.10.5" -two-face = "0.4.0" -cached = "0.53.1" - [lib] crate-type = ["cdylib"] + +[dependencies] +codesnap = "0.7.2" +mlua = { version = "0.10.0", features = ["module", "luajit", "serialize"] } +serde = { version = "1.0.204", features = ["derive"] } + diff --git a/generator/src/code.rs b/generator/src/code.rs deleted file mode 100644 index e1f7560..0000000 --- a/generator/src/code.rs +++ /dev/null @@ -1,84 +0,0 @@ -use cached::proc_macro::cached; -use regex::Regex; - -const MIN_WIDTH: f32 = 100.; -pub const CHAR_WIDTH: f32 = 9.05; - -fn min_width(width: f32) -> f32 { - if width < MIN_WIDTH { - MIN_WIDTH - } else { - width - } -} - -pub fn calc_max_line_number_length(code_length: usize, start_line_number: usize) -> usize { - let max_line_number = code_length + start_line_number; - - // If code length is 1, the max_line_number will equal to start_line_number - (max_line_number - 1).to_string().len() -} - -pub fn calc_wh(text: &str, char_wdith: f32, line_height: f32) -> (f32, f32) { - let trimmed_text = prepare_code(text); - let lines = trimmed_text.lines(); - let max_length_line = lines.clone().into_iter().fold("", |max_length_line, cur| { - if cur.len() > max_length_line.len() { - cur - } else { - max_length_line - } - }); - let width = max_length_line.len() as f32 * char_wdith; - let height = lines.collect::>().len() as f32 * line_height; - - (width, height) -} - -// Because the code block is input by users, we need to calculate the width and height -// to make sure render the width and height of the "editor" shape correctly -#[cached(key = "String", convert = r#"{ format!("{}", text) }"#)] -pub fn calc_wh_with_min_width(text: &str, char_wdith: f32, line_height: f32) -> (f32, f32) { - let (width, height) = calc_wh(text, char_wdith, line_height); - - (min_width(width), height) -} - -// The tab character is incorrectly render using cosmic, need to replace all tab with space -// before render the code -fn replace_tab_to_space(text: &str) -> String { - let spaces = " ".repeat(2); - - str::replace(text, "\t", &spaces) -} - -// Find min indention of code lines, and remove the same indention from subsequent lines -fn trim_space(text: &str) -> String { - let lines = text.split("\n").collect::>(); - let regex = Regex::new(r"(?:^|\n)(\s*)").unwrap(); - let captures_iter = regex.captures_iter(text); - let space_lengths = captures_iter - .map(|capture| capture.get(1).unwrap().as_str().len()) - .collect::>(); - - if space_lengths.len() < lines.len() { - return text.to_string(); - } - - let need_to_remove_spaces = " ".repeat(space_lengths.into_iter().min().unwrap()); - - lines - .into_iter() - .map(|line| { - Regex::new(format!("^{}", need_to_remove_spaces).as_ref()) - .unwrap() - .replace(line, "") - .to_string() - }) - .collect::>() - .join("\n") -} - -pub fn prepare_code(code: &str) -> String { - trim_space(&replace_tab_to_space(&code)) -} diff --git a/generator/src/color.rs b/generator/src/color.rs deleted file mode 100644 index 59bfda2..0000000 --- a/generator/src/color.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::i64; -use tiny_skia::Color; - -const HEX_COLOR_LENGTH: usize = 7; -const HEX_COLOR_WITH_ALPHA_LENGTH: usize = 9; - -pub struct RgbaColor { - pub color: Color, -} - -pub fn is_valid_hex_color(color: &str) -> bool { - (color.len() == HEX_COLOR_LENGTH || color.len() == HEX_COLOR_WITH_ALPHA_LENGTH) - && color.starts_with("#") -} - -fn parse_color_to_rgba_hex(hex: &str) -> String { - if !is_valid_hex_color(&hex) || hex.len() == HEX_COLOR_WITH_ALPHA_LENGTH { - hex.to_string() - } else { - format!("{}ff", hex) - } -} - -impl Into for String { - fn into(self) -> RgbaColor { - let rgba_hex_color = parse_color_to_rgba_hex(&self); - // Remove the '#' symbol - let hex_color = &rgba_hex_color.to_lowercase()[1..rgba_hex_color.len()]; - let chars = hex_color.chars().collect::>(); - let splits = &chars - .chunks(2) - .map(|chunk| i64::from_str_radix(&chunk.iter().collect::(), 16).unwrap()) - .collect::>(); - - RgbaColor { - color: Color::from_rgba8( - splits[0] as u8, - splits[1] as u8, - splits[2] as u8, - splits[3] as u8, - ), - } - } -} diff --git a/generator/src/components.rs b/generator/src/components.rs deleted file mode 100644 index 6a31557..0000000 --- a/generator/src/components.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub mod background; -pub mod breadcrumbs; -pub mod code_block; -pub mod container; -pub mod editor; -pub mod highlight_code_block; -pub mod interface; -pub mod line_number; -pub mod rect; -pub mod watermark; diff --git a/generator/src/components/background.rs b/generator/src/components/background.rs deleted file mode 100644 index a0b1822..0000000 --- a/generator/src/components/background.rs +++ /dev/null @@ -1,147 +0,0 @@ -use tiny_skia::{ - Color, GradientStop, LinearGradient, Paint, Pixmap, Point, Rect, SpreadMode, Transform, -}; - -use crate::{ - color::{is_valid_hex_color, RgbaColor}, - edges::{edge::Edge, padding::Padding}, -}; - -use super::interface::{ - component::{Component, ComponentContext, RenderParams}, - render_error::{self, RenderError}, - style::{ComponentAlign, ComponentStyle, RawComponentStyle}, -}; - -pub struct Background { - children: Vec>, - padding: Padding, -} - -impl Background { - pub fn new(padding: Padding, children: Vec>) -> Background { - Background { children, padding } - } - - pub fn parse_background_padding( - horizontal_background_padding: f32, - vertical_background_padding: f32, - background_padding: Option, - ) -> Padding { - match background_padding { - Some(padding) => Padding::from_value(padding), - None => Padding { - top: vertical_background_padding, - bottom: vertical_background_padding, - left: horizontal_background_padding, - right: horizontal_background_padding, - }, - } - } - - pub fn has_background(padding: &Padding) -> bool { - return padding.horizontal() != 0. || padding.vertical() != 0.; - } -} - -impl Component for Background { - fn children(&self) -> &Vec> { - &self.children - } - - fn style(&self) -> RawComponentStyle { - RawComponentStyle::default() - .align(ComponentAlign::Column) - .padding(self.padding.clone()) - } - - fn self_render_condition(&self) -> bool { - Self::has_background(&self.padding) - } - - fn draw_self( - &self, - pixmap: &mut Pixmap, - context: &ComponentContext, - _render_params: &RenderParams, - _style: &ComponentStyle, - _parent_style: &ComponentStyle, - ) -> render_error::Result<()> { - let mut paint = Paint::default(); - let w = pixmap.width() as f32; - let h = pixmap.height() as f32; - let params = &context.take_snapshot_params; - - paint.anti_alias = false; - match params.bg_color.as_ref() { - Some(color) => { - if !is_valid_hex_color(color) { - return Err(RenderError::InvalidHexColor(color.to_string())); - } - - let rgba_color: RgbaColor = color.to_string().into(); - - paint.set_color(rgba_color.color); - } - None => { - paint.shader = LinearGradient::new( - Point::from_xy(0., 0.), - Point::from_xy(w, 0.), - Background::get_theme(&context.take_snapshot_params.bg_theme)?, - SpreadMode::Pad, - Transform::identity(), - ) - .unwrap(); - } - }; - - pixmap.fill_rect( - Rect::from_xywh(0., 0., w, h).unwrap(), - &paint, - Transform::identity(), - None, - ); - - Ok(()) - } -} - -impl Background { - fn get_theme(theme: &str) -> render_error::Result> { - let theme = match theme { - "default" => vec![ - GradientStop::new(0.0, Color::from_rgba8(58, 28, 113, 255)), - GradientStop::new(0.5, Color::from_rgba8(215, 109, 119, 255)), - GradientStop::new(0.95, Color::from_rgba8(255, 175, 123, 255)), - ], - "sea" => vec![ - GradientStop::new(0.0, Color::from_rgba8(31, 162, 255, 255)), - GradientStop::new(0.4, Color::from_rgba8(18, 216, 250, 255)), - GradientStop::new(0.95, Color::from_rgba8(166, 255, 203, 255)), - ], - "grape" => vec![ - GradientStop::new(0.28, Color::from_rgba8(103, 90, 247, 255)), - GradientStop::new(0.95, Color::from_rgba8(189, 101, 250, 255)), - ], - "peach" => vec![ - GradientStop::new(0.22, Color::from_rgba8(221, 94, 137, 255)), - GradientStop::new(0.95, Color::from_rgba8(247, 187, 151, 255)), - ], - "summer" => vec![ - GradientStop::new(0.28, Color::from_rgba8(248, 165, 194, 255)), - GradientStop::new(0.95, Color::from_rgba8(116, 185, 255, 255)), - ], - "bamboo" => vec![ - GradientStop::new(0.22, Color::from_rgba8(107, 203, 165, 255)), - GradientStop::new(0.95, Color::from_rgba8(202, 244, 194, 255)), - ], - "dusk" => vec![ - GradientStop::new(0.22, Color::from_rgba8(255, 98, 110, 255)), - GradientStop::new(0.95, Color::from_rgba8(255, 190, 113, 255)), - ], - _ => return Err(RenderError::UnknownBackgroundTheme(theme.to_string())), - }; - - Ok(theme) - } -} diff --git a/generator/src/components/breadcrumbs.rs b/generator/src/components/breadcrumbs.rs deleted file mode 100644 index 94963d3..0000000 --- a/generator/src/components/breadcrumbs.rs +++ /dev/null @@ -1,90 +0,0 @@ -use cosmic_text::{Attrs, Color, Family}; -use regex::Regex; - -use crate::{code::calc_wh_with_min_width, edges::margin::Margin, text::FontRenderer}; - -use super::interface::{ - component::Component, - style::{ComponentStyle, RawComponentStyle, Size}, -}; - -pub struct Breadcrumbs { - children: Vec>, - path: String, - line_height: f32, - has_breadcrumbs: bool, -} - -impl Component for Breadcrumbs { - fn children(&self) -> &Vec> { - &self.children - } - - fn style(&self) -> RawComponentStyle { - let style = RawComponentStyle::default(); - - if self.has_breadcrumbs { - let (w, h) = calc_wh_with_min_width(&self.path, 8., self.line_height); - - style.size(Size::Num(w), Size::Num(h)).margin(Margin { - top: 5., - ..Margin::default() - }) - } else { - style - } - } - - fn draw_self( - &self, - pixmap: &mut tiny_skia::Pixmap, - context: &super::interface::component::ComponentContext, - render_params: &super::interface::component::RenderParams, - style: &super::interface::style::ComponentStyle, - _parent_style: &ComponentStyle, - ) -> super::interface::render_error::Result<()> { - if self.has_breadcrumbs { - let attrs = Attrs::new() - .color(Color::rgb(128, 132, 139)) - .family(Family::Name(&context.take_snapshot_params.code_font_family)); - - FontRenderer::new( - 12., - self.line_height, - context.scale_factor, - &context.take_snapshot_params.fonts_folder, - ) - .draw_text( - render_params.x, - render_params.y, - style.width, - self.line_height, - vec![(&self.path, attrs)], - pixmap, - ); - } - - Ok(()) - } -} - -impl Breadcrumbs { - pub fn from_path( - path: String, - line_height: f32, - separator: String, - has_breadcrumbs: bool, - ) -> Breadcrumbs { - let path = Regex::new("/") - .unwrap() - .replace_all(&path, separator) - .to_string(); - - Breadcrumbs { - children: vec![], - path, - line_height, - has_breadcrumbs, - } - } -} diff --git a/generator/src/components/code_block.rs b/generator/src/components/code_block.rs deleted file mode 100644 index 41d27be..0000000 --- a/generator/src/components/code_block.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::interface::component::Component; - -pub struct CodeBlock { - children: Vec>, -} - -impl Component for CodeBlock { - fn children(&self) -> &Vec> { - &self.children - } -} - -impl CodeBlock { - pub fn from_children(children: Vec>) -> CodeBlock { - CodeBlock { children } - } -} diff --git a/generator/src/components/container.rs b/generator/src/components/container.rs deleted file mode 100644 index afe595d..0000000 --- a/generator/src/components/container.rs +++ /dev/null @@ -1,42 +0,0 @@ -use tiny_skia::Pixmap; - -use super::interface::{ - component::{Component, ComponentContext, ComponentRenderParams}, - render_error::Result, - style::Style, -}; - -pub struct Container { - children: Vec>, -} - -impl Component for Container { - fn children(&self) -> &Vec> { - &self.children - } -} - -impl Container { - pub fn from_children(children: Vec>) -> Container { - Container { children } - } - - pub fn draw_root(&self, context: &ComponentContext) -> Result { - let style = self.parsed_style(); - let mut pixmap = Pixmap::new( - (style.width * context.scale_factor) as u32, - (style.height * context.scale_factor) as u32, - ) - .unwrap(); - - self.draw( - &mut pixmap, - context, - ComponentRenderParams::default(), - Style::default(), - Style::default(), - )?; - - Ok(pixmap) - } -} diff --git a/generator/src/components/editor.rs b/generator/src/components/editor.rs deleted file mode 100644 index 865586a..0000000 --- a/generator/src/components/editor.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod code; -pub mod mac_title_bar; diff --git a/generator/src/components/editor/code.rs b/generator/src/components/editor/code.rs deleted file mode 100644 index dfa62ec..0000000 --- a/generator/src/components/editor/code.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::{ - code::{calc_wh_with_min_width, prepare_code, CHAR_WIDTH}, - components::interface::{ - component::{Component, ComponentContext, RenderParams}, - render_error, - style::{ComponentStyle, RawComponentStyle, Size, Style}, - }, - highlight::Highlight, - text::FontRenderer, -}; - -pub struct Code { - children: Vec>, - line_height: f32, - font_size: f32, - value: String, -} - -impl Component for Code { - fn children(&self) -> &Vec> { - &self.children - } - - fn style(&self) -> RawComponentStyle { - let (w, h) = calc_wh_with_min_width(&self.value, CHAR_WIDTH, self.line_height); - - Style::default().size(Size::Num(w), Size::Num(h)) - } - - fn draw_self( - &self, - pixmap: &mut tiny_skia::Pixmap, - context: &ComponentContext, - render_params: &RenderParams, - style: &ComponentStyle, - _parent_style: &ComponentStyle, - ) -> render_error::Result<()> { - let params = &context.take_snapshot_params; - let highlight = Highlight::new( - self.value.clone(), - params.code_font_family.clone(), - params.code_file_path.clone(), - params.extension.clone(), - ); - let highlight_result = highlight.parse(¶ms.themes_folder, ¶ms.theme)?; - - FontRenderer::new( - self.font_size, - self.line_height, - context.scale_factor, - &context.take_snapshot_params.fonts_folder, - ) - .draw_text( - render_params.x, - render_params.y, - style.width, - style.height, - highlight_result.clone(), - pixmap, - ); - - Ok(()) - } -} - -impl Code { - pub fn new(value: String, line_height: f32, font_size: f32) -> Code { - Code { - value: prepare_code(&value), - line_height, - font_size, - children: vec![], - } - } -} diff --git a/generator/src/components/editor/mac_title_bar.rs b/generator/src/components/editor/mac_title_bar.rs deleted file mode 100644 index eae4557..0000000 --- a/generator/src/components/editor/mac_title_bar.rs +++ /dev/null @@ -1,109 +0,0 @@ -use tiny_skia::{Color, FillRule, Paint, PathBuilder, Transform}; - -use crate::{ - components::interface::{ - component::{Component, ComponentContext, RenderParams}, - render_error, - style::{ComponentStyle, RawComponentStyle, Size, Style}, - }, - edges::margin::Margin, -}; - -pub struct MacTitleBar { - radius: f32, - children: Vec>, - render_condition: bool, -} - -impl Component for MacTitleBar { - fn children(&self) -> &Vec> { - &self.children - } - - fn style(&self) -> RawComponentStyle { - let demeter = self.radius * 2.; - - Style::default() - .size(Size::Num(demeter + 2. * 25.), Size::Num(demeter)) - .margin(Margin { - bottom: 10., - ..Margin::default() - }) - } - - fn render_condition(&self) -> bool { - return self.render_condition; - } - - fn draw_self( - &self, - pixmap: &mut tiny_skia::Pixmap, - context: &ComponentContext, - render_params: &RenderParams, - _style: &ComponentStyle, - _parent_style: &ComponentStyle, - ) -> render_error::Result<()> { - self.draw_control_buttons( - // Control bar construct by draw circles, after drawn, the path will be at the center, - // so the x, y need to offset by radius of the circle, and the next shape will still - // be drwan on the original point - render_params.x + self.radius, - render_params.y + self.radius, - pixmap, - vec![ - Color::from_rgba8(255, 94, 87, 255), - Color::from_rgba8(255, 186, 46, 255), - Color::from_rgba8(43, 200, 65, 255), - ], - 25., - Transform::from_scale(context.scale_factor, context.scale_factor), - ); - - Ok(()) - } -} - -impl MacTitleBar { - pub fn from_radius(radius: f32, render_condition: bool) -> MacTitleBar { - MacTitleBar { - radius, - children: vec![], - render_condition, - } - } - - fn draw_control_buttons( - &self, - x: f32, - y: f32, - pixmap: &mut tiny_skia::Pixmap, - colors: Vec, - gap: f32, - transform: Transform, - ) { - for (index, color) in colors.into_iter().enumerate() { - self.draw_control_button(x, y, pixmap, color, index as f32 * gap, transform); - } - } - - fn draw_control_button( - &self, - x: f32, - y: f32, - pixmap: &mut tiny_skia::Pixmap, - color: Color, - x_offset: f32, - transform: Transform, - ) { - let mut path_builder = PathBuilder::new(); - - path_builder.push_circle(x + x_offset, y, self.radius); - path_builder.close(); - - let path = path_builder.finish().unwrap(); - let mut paint = Paint::default(); - - paint.set_color(color); - pixmap.fill_path(&path, &paint, FillRule::Winding, transform, None); - } -} diff --git a/generator/src/components/highlight_code_block.rs b/generator/src/components/highlight_code_block.rs deleted file mode 100644 index cbefc09..0000000 --- a/generator/src/components/highlight_code_block.rs +++ /dev/null @@ -1,76 +0,0 @@ -use super::{ - interface::{component::Component, style::ComponentStyle}, - rect::EDITOR_PADDING, -}; -use tiny_skia::{Color, Paint, Rect, Transform}; - -#[derive(Default)] -pub struct HighlightCodeBlock { - children: Vec>, - line_height: f32, - start_line_number: usize, - end_line_number: usize, - render_condition: bool, -} - -impl Component for HighlightCodeBlock { - fn children(&self) -> &Vec> { - &self.children - } - - fn render_condition(&self) -> bool { - self.render_condition - } - - fn draw_self( - &self, - pixmap: &mut tiny_skia::Pixmap, - context: &super::interface::component::ComponentContext, - render_params: &super::interface::component::RenderParams, - _style: &super::interface::style::ComponentStyle, - parent_style: &ComponentStyle, - ) -> super::interface::render_error::Result<()> { - let mut paint = Paint::default(); - let start_y_offset = (self.start_line_number - 1) as f32 * self.line_height; - - paint.anti_alias = false; - paint.set_color(Color::from_rgba8(255, 255, 255, 10)); - pixmap.fill_rect( - Rect::from_xywh( - render_params.x - EDITOR_PADDING, - render_params.y + start_y_offset, - parent_style.width + EDITOR_PADDING * 2., - (self.end_line_number - self.start_line_number + 1) as f32 * self.line_height, - ) - .unwrap(), - &paint, - Transform::from_scale(context.scale_factor, context.scale_factor), - None, - ); - - Ok(()) - } -} - -impl HighlightCodeBlock { - pub fn from_line_number( - start_line_number: Option, - end_line_number: Option, - line_height: f32, - ) -> HighlightCodeBlock { - if end_line_number < start_line_number { - panic!("end_line_number should be greater than start_line_number") - } - - match start_line_number { - Some(start_line_number) => HighlightCodeBlock { - render_condition: true, - children: vec![], - line_height, - start_line_number, - end_line_number: end_line_number.unwrap(), - }, - None => HighlightCodeBlock::default(), - } - } -} diff --git a/generator/src/components/interface.rs b/generator/src/components/interface.rs deleted file mode 100644 index 87c3e6d..0000000 --- a/generator/src/components/interface.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod component; -pub mod render_error; -pub mod style; diff --git a/generator/src/components/interface/component.rs b/generator/src/components/interface/component.rs deleted file mode 100644 index 85c1638..0000000 --- a/generator/src/components/interface/component.rs +++ /dev/null @@ -1,204 +0,0 @@ -use super::{ - render_error, - style::{ComponentAlign, ComponentStyle, RawComponentStyle, Size, Style}, -}; -use crate::{config::TakeSnapshotParams, edges::edge::Edge}; -use std::sync::Arc; -use tiny_skia::Pixmap; - -pub struct ComponentContext { - pub scale_factor: f32, - pub take_snapshot_params: Arc, -} - -#[derive(Default, Clone)] -pub struct RenderParams { - pub x: f32, - pub y: f32, -} - -#[derive(Default)] -pub struct ComponentRenderParams { - pub parent_render_params: RenderParams, - pub sibling_render_params: RenderParams, -} - -impl ComponentRenderParams { - fn parse_into_render_params_with_style( - &self, - parent_style: ComponentStyle, - sibling_style: ComponentStyle, - style: ComponentStyle, - ) -> RenderParams { - match parent_style.align { - ComponentAlign::Row => RenderParams { - x: self.sibling_render_params.x - + sibling_style.width - + style.margin.left - + sibling_style.padding.horizontal(), - y: self.sibling_render_params.y + style.margin.top, - }, - ComponentAlign::Column => RenderParams { - x: self.sibling_render_params.x + style.margin.left, - y: self.sibling_render_params.y - + style.margin.top - + sibling_style.height - + sibling_style.padding.vertical(), - }, - } - } -} - -pub trait Component { - fn children(&self) -> &Vec>; - - fn align(&self) -> ComponentAlign { - ComponentAlign::Row - } - - fn initialize(&self, render_params: &RenderParams) -> RenderParams { - render_params.clone() - } - - // The render_condition determines whether the component should be rendered or not - fn render_condition(&self) -> bool { - true - } - - // The difference with render_condition is that self_render_condition still renders childrens - fn self_render_condition(&self) -> bool { - true - } - - fn draw_self( - &self, - _pixmap: &mut Pixmap, - _context: &ComponentContext, - _render_params: &RenderParams, - _style: &ComponentStyle, - _parent_style: &ComponentStyle, - ) -> render_error::Result<()> { - Ok(()) - } - - fn style(&self) -> RawComponentStyle { - RawComponentStyle::default() - } - - fn parse_size(&self, size: Size, dynamic_value: f32) -> f32 { - match size { - Size::Num(num) => num, - Size::Dynamic => dynamic_value, - } - } - - fn parsed_style(&self) -> Style { - // If render_condition return false, the whole component shouldn't rendered, - // includes its children - if !self.render_condition() { - return ComponentStyle::default(); - } - - // If self_render_condition return false, the component shouldn't rendered, - // so the corresponding style should be cleared - let style = if self.self_render_condition() { - self.style() - } else { - RawComponentStyle::default() - }; - let (width, height) = self.get_dynamic_wh(); - let width = self.parse_size(style.width, width) - + style.padding.horizontal() - + style.margin.horizontal(); - - Style { - min_width: style.min_width, - width: if width > style.min_width { - width - } else { - style.min_width - }, - height: self.parse_size(style.height, height) - + style.padding.vertical() - + style.margin.vertical(), - align: style.align, - padding: style.padding, - margin: style.margin, - } - } - - fn draw( - &self, - pixmap: &mut Pixmap, - context: &ComponentContext, - component_render_params: ComponentRenderParams, - parent_style: ComponentStyle, - sibling_style: ComponentStyle, - ) -> render_error::Result { - let style = self.parsed_style(); - let render_params = self.initialize( - &component_render_params.parse_into_render_params_with_style( - parent_style.clone(), - sibling_style.clone(), - style.clone(), - ), - ); - - // Render nothing on paint if render_condition return false - if !self.render_condition() { - return Ok(render_params.clone()); - } - - if self.self_render_condition() { - self.draw_self(pixmap, context, &render_params, &style, &parent_style)?; - } - - let children = self.children(); - let mut sibling_render_params = RenderParams { - x: render_params.x + style.padding.left, - y: render_params.y + style.padding.top, - }; - let mut sibling_style = ComponentStyle::default(); - - for child in children { - sibling_render_params = child.draw( - pixmap, - context, - ComponentRenderParams { - parent_render_params: render_params.clone(), - sibling_render_params, - }, - style.clone(), - sibling_style, - )?; - sibling_style = child.parsed_style(); - } - - Ok(render_params.clone()) - } - - // Dynamic calculate width and height of children, if the children is empty, get_dynamic_wh - // will return (0., 0.) - fn get_dynamic_wh(&self) -> (f32, f32) { - let children = self.children(); - let calc_children_wh = |cb: fn((f32, f32), &Box) -> (f32, f32)| { - children.iter().fold((0., 0.), cb) - }; - let style = self.style(); - - match style.align { - // If align is row, width is sum of children width, height is max of children height - ComponentAlign::Row => calc_children_wh(|(w, h), child| { - let style = child.parsed_style(); - - (w + style.width, h.max(style.height)) - }), - // If align is column, width is max of children width, height is sum of children height - ComponentAlign::Column => calc_children_wh(|(w, h), child| { - let style = child.parsed_style(); - - (w.max(style.width), h + style.height) - }), - } - } -} diff --git a/generator/src/components/interface/render_error.rs b/generator/src/components/interface/render_error.rs deleted file mode 100644 index a2d1be6..0000000 --- a/generator/src/components/interface/render_error.rs +++ /dev/null @@ -1,27 +0,0 @@ -use thiserror::Error; - -pub type Result = std::result::Result; - -#[derive(Debug, Error)] -pub enum RenderError { - #[error("Highlight code failed!")] - HighlightThemeLoadFailed, - - #[error("No such highlight syntax for {0}")] - HighlightCodeFailed(String), - - #[error("Unable to parse unknown background theme {0}")] - UnknownBackgroundTheme(String), - - #[error("Invalid hex color {0}")] - InvalidHexColor(String), - - #[error("No such file {0}")] - NoSuchFile(String), -} - -impl From for nvim_oxi::api::Error { - fn from(err: RenderError) -> Self { - nvim_oxi::api::Error::Other(err.to_string()) - } -} diff --git a/generator/src/components/interface/style.rs b/generator/src/components/interface/style.rs deleted file mode 100644 index 76ff31f..0000000 --- a/generator/src/components/interface/style.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::edges::{margin::Margin, padding::Padding}; - -#[derive(Clone, Debug)] -pub enum ComponentAlign { - Row, - Column, -} - -pub enum Size { - Dynamic, - Num(f32), -} - -#[derive(Clone, Debug)] -pub struct Style { - pub width: T, - pub height: T, - pub min_width: f32, - pub align: ComponentAlign, - pub padding: Padding, - pub margin: Margin, -} - -pub type RawComponentStyle = Style; -pub type ComponentStyle = Style; - -impl Default for RawComponentStyle { - fn default() -> Self { - Style { - min_width: 0., - width: Size::Dynamic, - height: Size::Dynamic, - align: ComponentAlign::Row, - padding: Padding::default(), - margin: Margin::default(), - } - } -} - -impl Default for ComponentStyle { - fn default() -> Self { - Style { - min_width: 0., - width: 0., - height: 0., - align: ComponentAlign::Row, - padding: Padding::default(), - margin: Margin::default(), - } - } -} - -impl RawComponentStyle { - pub fn size(mut self, width: Size, height: Size) -> Self { - self.width = width; - self.height = height; - self - } - - // Only works if the width is calculate dynamically - pub fn min_width(mut self, min_width: f32) -> Self { - self.min_width = min_width; - self - } - - pub fn align(mut self, align: ComponentAlign) -> Self { - self.align = align; - self - } - - pub fn padding(mut self, padding: Padding) -> Self { - self.padding = padding; - self - } - - pub fn margin(mut self, margin: Margin) -> Self { - self.margin = margin; - self - } -} diff --git a/generator/src/components/line_number.rs b/generator/src/components/line_number.rs deleted file mode 100644 index b2a9ca1..0000000 --- a/generator/src/components/line_number.rs +++ /dev/null @@ -1,100 +0,0 @@ -use super::interface::{ - component::{Component, ComponentContext, RenderParams}, - render_error, - style::{ComponentStyle, RawComponentStyle, Size, Style}, -}; -use crate::{code::CHAR_WIDTH, edges::margin::Margin, text::FontRenderer}; -use cosmic_text::{Attrs, Color, Family}; - -const FONT_SIZE: f32 = 14.; - -#[derive(Default)] -pub struct LineNumber { - children: Vec>, - line_height: f32, - render_condition: bool, - line_number_content: Vec, - number_of_digit: usize, -} - -impl Component for LineNumber { - fn render_condition(&self) -> bool { - return self.render_condition; - } - - fn children(&self) -> &Vec> { - &self.children - } - - fn style(&self) -> RawComponentStyle { - Style::default() - .size( - Size::Num(CHAR_WIDTH * self.number_of_digit as f32), - Size::Num(self.line_number_content.len() as f32 * self.line_height), - ) - .margin(Margin { - right: 10., - ..Margin::default() - }) - } - - fn draw_self( - &self, - pixmap: &mut tiny_skia::Pixmap, - context: &ComponentContext, - render_params: &RenderParams, - style: &ComponentStyle, - _parent_style: &ComponentStyle, - ) -> render_error::Result<()> { - FontRenderer::new( - FONT_SIZE, - self.line_height, - context.scale_factor, - &context.take_snapshot_params.fonts_folder, - ) - .draw_text( - render_params.x, - render_params.y, - style.width, - style.height, - vec![( - &self.line_number_content.join("\n"), - Attrs::new() - .color(Color::rgb(73, 81, 98)) - .family(Family::Name(&context.take_snapshot_params.code_font_family)), - )], - pixmap, - ); - - Ok(()) - } -} - -impl LineNumber { - pub fn new(content: &str, start_line_number: Option, line_height: f32) -> LineNumber { - match start_line_number { - None => LineNumber::default(), - Some(start_line_number) => { - let lines = content.split("\n").collect::>(); - let max_line_number = lines.len() + start_line_number; - let number_of_digit = (max_line_number - 1).to_string().len(); - - LineNumber { - line_number_content: (start_line_number..max_line_number) - .map(|line_number| { - format!( - "{:>width$}", - line_number.to_string(), - width = number_of_digit - ) - }) - .collect::>(), - number_of_digit, - children: vec![], - render_condition: true, - line_height, - } - } - } - } -} diff --git a/generator/src/components/rect.rs b/generator/src/components/rect.rs deleted file mode 100644 index dd97b2d..0000000 --- a/generator/src/components/rect.rs +++ /dev/null @@ -1,106 +0,0 @@ -use super::interface::{ - component::{Component, ComponentContext, RenderParams}, - render_error, - style::{ComponentAlign, ComponentStyle, RawComponentStyle, Style}, -}; -use crate::edges::padding::Padding; -use tiny_skia::{FillRule, Paint, PathBuilder, Pixmap, Transform}; - -pub const EDITOR_PADDING: f32 = 20.; - -pub struct Rect { - radius: f32, - min_width: f32, - children: Vec>, -} - -impl Component for Rect { - fn children(&self) -> &Vec> { - &self.children - } - - fn style(&self) -> RawComponentStyle { - Style::default() - .min_width(self.min_width) - .align(ComponentAlign::Column) - .padding(Padding::from_value(EDITOR_PADDING)) - } - - fn draw_self( - &self, - pixmap: &mut Pixmap, - context: &ComponentContext, - render_params: &RenderParams, - style: &ComponentStyle, - _parent_style: &ComponentStyle, - ) -> render_error::Result<()> { - let mut path_builder = PathBuilder::new(); - let x = render_params.x; - let y = render_params.y; - let w = style.width; - let h = style.height; - - let rect_width = w - 2. * self.radius; - let rect_height = h - 2. * self.radius; - - path_builder.move_to(x + self.radius, y); - path_builder.line_to(x + self.radius + rect_width, y); - path_builder.line_to(x + self.radius + rect_width, y + self.radius); - - path_builder.line_to(x + rect_width + self.radius * 2., y + self.radius); - - path_builder.line_to( - x + rect_width + self.radius * 2., - y + rect_height + self.radius, - ); - path_builder.line_to(x + rect_width + self.radius, y + rect_height + self.radius); - path_builder.line_to( - x + rect_width + self.radius, - y + rect_height + self.radius * 2., - ); - - path_builder.line_to(x + self.radius, y + rect_height + self.radius * 2.); - path_builder.line_to(x + self.radius, y + rect_height + self.radius); - - path_builder.line_to(x, y + rect_height + self.radius); - - path_builder.line_to(x, y + self.radius); - path_builder.line_to(x + self.radius, y + self.radius); - path_builder.line_to(x + self.radius, y); - path_builder.line_to(x + self.radius + rect_width, y); - path_builder.push_circle( - x + rect_width + self.radius, - y + rect_height + self.radius, - self.radius, - ); - path_builder.push_circle(x + self.radius + rect_width, y + self.radius, self.radius); - path_builder.push_circle(x + self.radius, y + self.radius, self.radius); - path_builder.push_circle(x + self.radius, y + rect_height + self.radius, self.radius); - - path_builder.close(); - let path = path_builder.finish().unwrap(); - let mut paint = Paint::default(); - paint.set_color_rgba8(40, 44, 52, 237); - - pixmap.fill_path( - &path, - &paint, - FillRule::Winding, - Transform::from_scale(context.scale_factor, context.scale_factor), - // Transform::identity(), - None, - ); - - Ok(()) - } -} - -impl Rect { - pub fn new(radius: f32, min_width: Option, children: Vec>) -> Rect { - Rect { - radius, - children, - min_width: min_width.unwrap_or(0.), - } - } -} diff --git a/generator/src/components/watermark.rs b/generator/src/components/watermark.rs deleted file mode 100644 index 03500ac..0000000 --- a/generator/src/components/watermark.rs +++ /dev/null @@ -1,82 +0,0 @@ -use cosmic_text::{Align, Attrs, Family}; -use tiny_skia::Pixmap; - -use crate::{edges::margin::Margin, text::FontRenderer}; - -use super::interface::{ - component::{Component, ComponentContext, RenderParams}, - render_error, - style::{ComponentStyle, RawComponentStyle}, -}; - -pub struct Watermark { - children: Vec>, - value: String, -} - -impl Component for Watermark { - fn draw_self( - &self, - pixmap: &mut Pixmap, - context: &ComponentContext, - render_params: &RenderParams, - _style: &ComponentStyle, - _parent_style: &ComponentStyle, - ) -> render_error::Result<()> { - let params = &context.take_snapshot_params; - - let attrs = Attrs::new().family(Family::Name( - &context.take_snapshot_params.watermark_font_family, - )); - - FontRenderer::new( - 20., - 20., - context.scale_factor, - &context.take_snapshot_params.fonts_folder, - ) - .draw_line( - 0., - render_params.y, - pixmap.width() as f32, - pixmap.height() as f32, - ¶ms.watermark, - attrs, - Some(Align::Center), - pixmap, - ); - - Ok(()) - } - - fn children(&self) -> &Vec> { - &self.children - } - - fn render_condition(&self) -> bool { - self.value != "" - } - - fn style(&self) -> RawComponentStyle { - let default_style = RawComponentStyle::default(); - - if self.value != "" { - default_style.margin(Margin { - bottom: 22., - top: 15., - ..Margin::default() - }) - } else { - default_style - } - } -} - -impl Watermark { - pub fn new(value: String) -> Watermark { - Watermark { - children: vec![], - value, - } - } -} diff --git a/generator/src/config.rs b/generator/src/config.rs deleted file mode 100644 index 1e347d0..0000000 --- a/generator/src/config.rs +++ /dev/null @@ -1,63 +0,0 @@ -use nvim_oxi::conversion::{Error as ConversionError, FromObject, ToObject}; -use nvim_oxi::serde::{Deserializer, Serializer}; -use nvim_oxi::{lua, Object}; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Clone)] -pub struct TakeSnapshotParams { - // Whether to display the MacOS style title bar - pub mac_window_bar: bool, - // Wartermark of the code snapshot - pub watermark: String, - // Editor title - pub title: Option, - pub code_font_family: String, - pub watermark_font_family: String, - pub code: String, - pub code_file_path: String, - pub extension: Option, - pub save_path: Option, - pub themes_folder: String, - pub fonts_folder: String, - pub theme: String, - pub bg_theme: String, - pub bg_color: Option, - // Breadcrumbs path - pub file_path: String, - pub breadcrumbs_separator: String, - pub has_breadcrumbs: bool, - pub start_line_number: Option, - pub highlight_start_line_number: Option, - pub highlight_end_line_number: Option, - pub min_width: Option, - pub bg_x_padding: f32, - pub bg_y_padding: f32, - pub bg_padding: Option, -} - -impl FromObject for TakeSnapshotParams { - fn from_object(obj: Object) -> Result { - Self::deserialize(Deserializer::new(obj)).map_err(Into::into) - } -} - -impl ToObject for TakeSnapshotParams { - fn to_object(self) -> Result { - self.serialize(Serializer::new()).map_err(Into::into) - } -} - -impl lua::Poppable for TakeSnapshotParams { - unsafe fn pop(lstate: *mut lua::ffi::lua_State) -> Result { - let obj = Object::pop(lstate)?; - Self::from_object(obj).map_err(lua::Error::pop_error_from_err::) - } -} - -impl lua::Pushable for TakeSnapshotParams { - unsafe fn push(self, lstate: *mut lua::ffi::lua_State) -> Result { - self.to_object() - .map_err(lua::Error::push_error_from_err::)? - .push(lstate) - } -} diff --git a/generator/src/copy.rs b/generator/src/copy.rs deleted file mode 100644 index 385db15..0000000 --- a/generator/src/copy.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::{config::TakeSnapshotParams, snapshot::take_snapshot}; -#[cfg(target_os = "linux")] -use arboard::SetExtLinux; -use arboard::{Clipboard, ImageData}; - -use nvim_oxi::api; - -// The function will be called as FFI on Lua side -#[allow(dead_code)] -pub fn copy_into_clipboard(config: TakeSnapshotParams) -> Result<(), api::Error> { - let pixmap = take_snapshot(config.clone())?; - let premultplied_colors = pixmap.pixels(); - let colors = premultplied_colors - .iter() - .map(|premultplied_color| { - vec![ - premultplied_color.red(), - premultplied_color.green(), - premultplied_color.blue(), - premultplied_color.alpha(), - ] - }) - .flatten() - .collect::>(); - - let img_data = ImageData { - width: pixmap.width() as usize, - height: pixmap.height() as usize, - bytes: colors.into(), - }; - - #[cfg(target_os = "linux")] - std::thread::spawn(move || { - Clipboard::new() - .unwrap() - .set() - .wait() - .image(img_data) - .unwrap(); - }); - - #[cfg(not(target_os = "linux"))] - Clipboard::new().unwrap().set_image(img_data).unwrap(); - - Ok(()) -} diff --git a/generator/src/copy_ascii.rs b/generator/src/copy_ascii.rs deleted file mode 100644 index 08d37e0..0000000 --- a/generator/src/copy_ascii.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::{ - code::{calc_max_line_number_length, calc_wh, prepare_code}, - config::TakeSnapshotParams, -}; -use arboard::Clipboard; -#[cfg(target_os = "linux")] -use arboard::SetExtLinux; -use nvim_oxi::api; -use std::cmp::max; - -const SPACE_BOTH_SIDE: usize = 2; - -fn optional(component: String, is_view: bool) -> String { - if is_view { - component - } else { - "".to_string() - } -} - -#[allow(dead_code)] -pub fn copy_ascii(params: TakeSnapshotParams) -> Result<(), api::Error> { - let code = prepare_code(¶ms.code); - let (width, height) = calc_wh(&code, 1., 1.); - let calc_line_number_width = - |start_line_number: usize| calc_max_line_number_length(height as usize, start_line_number); - let frame_width = max(width as usize, params.file_path.len()) + SPACE_BOTH_SIDE; - let frame_width = match params.start_line_number { - Some(start_line_number) => { - frame_width + SPACE_BOTH_SIDE + calc_line_number_width(start_line_number) - } - None => frame_width, - }; - let line = format!("│{}│\n", "─".repeat(frame_width)); - let frame_width_with_content = frame_width - 1; - let top_frame = format!("╭{}╮\n", "─".repeat(frame_width)); - let bottom_frame = format!("╰{}╯", "─".repeat(frame_width)); - let code = code - .lines() - .enumerate() - .map(|(i, line)| { - format!( - "│ {:1$} │\n", - match params.start_line_number { - Some(start_line_number) => format!( - "{:1$} {line}", - start_line_number + i, - calc_line_number_width(start_line_number), - ), - None => line.to_string(), - }, - frame_width_with_content - 1 - ) - }) - .collect::(); - let text_line = |text: &str| format!("│ {:1$}│\n", text, frame_width_with_content); - let breadcrumbs = optional( - format!("{}{line}", text_line(¶ms.file_path)), - params.has_breadcrumbs, - ); - let ascii_snapshot = format!("{top_frame}{breadcrumbs}{code}{bottom_frame}"); - - #[cfg(target_os = "linux")] - std::thread::spawn(move || { - Clipboard::new() - .unwrap() - .set() - .wait() - .text(ascii_snapshot) - .unwrap(); - }); - - #[cfg(not(target_os = "linux"))] - Clipboard::new() - .unwrap() - .set_text(ascii_snapshot) - .map_err(|err| api::Error::Other(err.to_string()))?; - - Ok(()) -} diff --git a/generator/src/edges.rs b/generator/src/edges.rs deleted file mode 100644 index 00932f1..0000000 --- a/generator/src/edges.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod edge; -pub mod margin; -pub mod padding; diff --git a/generator/src/edges/edge.rs b/generator/src/edges/edge.rs deleted file mode 100644 index 69a0d23..0000000 --- a/generator/src/edges/edge.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub trait Edge { - fn horizontal(&self) -> f32; - - fn vertical(&self) -> f32; -} diff --git a/generator/src/edges/margin.rs b/generator/src/edges/margin.rs deleted file mode 100644 index 305ef65..0000000 --- a/generator/src/edges/margin.rs +++ /dev/null @@ -1,31 +0,0 @@ -use super::edge::Edge; - -#[derive(Clone, Default, Debug)] -pub struct Margin { - pub left: f32, - pub right: f32, - pub top: f32, - pub bottom: f32, -} - -impl Edge for Margin { - fn horizontal(&self) -> f32 { - self.left + self.right - } - - fn vertical(&self) -> f32 { - self.bottom + self.top - } -} - -impl Margin { - #[allow(dead_code)] - pub fn from_value(value: f32) -> Margin { - Margin { - left: value, - right: value, - top: value, - bottom: value, - } - } -} diff --git a/generator/src/edges/padding.rs b/generator/src/edges/padding.rs deleted file mode 100644 index 94c135f..0000000 --- a/generator/src/edges/padding.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::edge::Edge; - -#[derive(Clone, Default, Debug)] -pub struct Padding { - pub left: f32, - pub right: f32, - pub top: f32, - pub bottom: f32, -} - -impl Edge for Padding { - fn horizontal(&self) -> f32 { - self.left + self.right - } - - fn vertical(&self) -> f32 { - self.bottom + self.top - } -} - -impl Padding { - pub fn from_value(value: f32) -> Padding { - Padding { - left: value, - right: value, - top: value, - bottom: value, - } - } -} diff --git a/generator/src/highlight.rs b/generator/src/highlight.rs deleted file mode 100644 index 3df50e1..0000000 --- a/generator/src/highlight.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::collections::HashMap; - -use cosmic_text::{Attrs, Family, Style, Weight}; -use syntect::{ - easy::HighlightLines, - highlighting::{FontStyle, ThemeSet}, - parsing::{SyntaxReference, SyntaxSet}, - util::LinesWithEndings, -}; - -use crate::components::interface::render_error::RenderError; - -type SourceMap = HashMap<&'static str, &'static str>; - -pub struct Highlight { - content: String, - code_file_path: String, - extension: Option, - font_family: String, - highlighting_language_source_map: SourceMap, -} - -pub type HighlightResult<'a> = Vec<(&'a str, Attrs<'a>)>; - -impl Highlight { - pub fn new( - content: String, - font_family: String, - code_file_path: String, - extension: Option, - ) -> Highlight { - Highlight { - content, - code_file_path, - extension, - font_family, - highlighting_language_source_map: HashMap::from([("PHP", " Result { - // The extension exist only when users specified explicitly - // By default, using filepath to detect what syntax should use - let syntax = match &self.extension { - Some(extension) => syntax_set - .find_syntax_by_extension(&extension) - .ok_or(RenderError::HighlightCodeFailed(extension.to_string()))?, - None => syntax_set - .find_syntax_for_file(&self.code_file_path) - .map_err(|_| RenderError::NoSuchFile(self.code_file_path.to_string()))? - .ok_or(RenderError::HighlightCodeFailed( - self.code_file_path.to_string(), - ))?, - }; - - // The Syntect clearly distinguish between PHP and PHP Source - // Should use PHP as highlight language if the source content contains " Result, RenderError> { - let syntax_set = two_face::syntax::extra_newlines(); - let theme_set = ThemeSet::load_from_folder(theme_folder) - .map_err(|_| RenderError::HighlightThemeLoadFailed)?; - let syntax = &self.guess_syntax(&syntax_set)?; - let mut highlight = HighlightLines::new(syntax, &theme_set.themes[theme]); - let attrs = Attrs::new().family(Family::Name(self.font_family.as_ref())); - - // Highlight the content line by line using highlight_line function - Ok(LinesWithEndings::from(&self.content) - .map(|line| { - highlight - .highlight_line(line, &syntax_set) - .unwrap() - .into_iter() - .map(|(style, str)| { - let syntect::highlighting::Color { r, g, b, a: _ } = style.foreground; - let attrs = match style.font_style { - FontStyle::BOLD => attrs.weight(Weight::BOLD), - FontStyle::ITALIC => attrs.style(Style::Italic), - FontStyle::UNDERLINE => attrs.style(Style::Normal), - _ => attrs, - }; - - (str, attrs.color(cosmic_text::Color::rgb(r, g, b))) - }) - .collect::() - }) - .fold(vec![], |acc, cur| [acc, cur].concat()) - .into_iter() - .collect::()) - } -} diff --git a/generator/src/lib.rs b/generator/src/lib.rs index 4c1ed05..3702281 100644 --- a/generator/src/lib.rs +++ b/generator/src/lib.rs @@ -1,30 +1,100 @@ -mod code; -mod color; -mod components; -mod config; -mod copy; -mod copy_ascii; -mod edges; -mod highlight; -mod path; -mod save; -mod snapshot; -mod text; - -use config::TakeSnapshotParams; -use copy::copy_into_clipboard; -use copy_ascii::copy_ascii; -use nvim_oxi::{api, Dictionary, Function}; -use save::save_snapshot; - -#[nvim_oxi::plugin] -fn generator() -> nvim_oxi::Result { - let copy_into_clipboard: Function> = - Function::from_fn(copy_into_clipboard); - - Ok(Dictionary::from_iter([ - ("copy_into_clipboard", copy_into_clipboard), - ("save_snapshot", Function::from_fn(save_snapshot)), - ("copy_ascii", Function::from_fn(copy_ascii)), - ])) +mod snapshot_config; + +use std::{ffi::OsStr, path::Path}; + +use codesnap::snapshot::{image_snapshot::ImageSnapshot, snapshot_data::SnapshotData}; +use mlua::prelude::*; +use snapshot_config::SnapshotConfigLua; + +enum SnapshotType { + Png, + Svg, + Html, +} + +impl From for SnapshotType { + fn from(value: String) -> Self { + match value.as_str() { + "png" => SnapshotType::Png, + "svg" => SnapshotType::Svg, + "html" => SnapshotType::Html, + _ => SnapshotType::Png, + } + } +} + +impl SnapshotType { + fn snapshot_data( + &self, + image_snapshot: ImageSnapshot, + is_raw: bool, + ) -> LuaResult { + let data = match self { + SnapshotType::Png => { + if is_raw { + image_snapshot.raw_data() + } else { + image_snapshot.png_data() + } + } + SnapshotType::Svg => image_snapshot.svg_data(), + SnapshotType::Html => image_snapshot.html_data(), + } + .map_err(|_| mlua::Error::RuntimeError("Failed to generate snapshot data".to_string()))?; + + Ok(data) + } +} + +fn create_image_snapshot_by_config(config: &SnapshotConfigLua) -> LuaResult { + config + .0 + .create_snapshot() + .map_err(|_| mlua::Error::RuntimeError("Failed to create image snapshot".to_string())) +} + +fn save(_: &Lua, (path, config): (String, SnapshotConfigLua)) -> LuaResult<()> { + let snapshot_type: SnapshotType = Path::new(&path) + .extension() + .and_then(OsStr::to_str) + .ok_or_else(|| mlua::Error::RuntimeError("Invalid file extension".to_string()))? + .to_string() + .into(); + + SnapshotType::from(snapshot_type) + .snapshot_data(create_image_snapshot_by_config(&config)?, false)? + .save(&path) + .map_err(|_| mlua::Error::RuntimeError(format!("Failed to save snapshot data to {}", path))) +} + +fn copy(_: &Lua, (snapshot_type, config): (String, SnapshotConfigLua)) -> LuaResult<()> { + SnapshotType::from(snapshot_type) + .snapshot_data(create_image_snapshot_by_config(&config)?, true)? + .copy() + .map_err(|_| mlua::Error::RuntimeError("Failed to copy snapshot to clipboard".to_string())) +} + +fn copy_ascii(_: &Lua, config: SnapshotConfigLua) -> LuaResult<()> { + config + .0 + .create_ascii_snapshot() + .raw_data() + .map_err(|_| mlua::Error::RuntimeError("Failed to generate ASCII snapshot".to_string()))? + .copy() + .map_err(|_| { + mlua::Error::RuntimeError("Failed to copy ASCII snapshot to clipboard".to_string()) + })?; + + Ok(()) +} + +#[mlua::lua_module(skip_memory_check)] +fn generator(lua: &Lua) -> LuaResult { + let exports = lua.create_table()?; + + exports.set("save", lua.create_function(save)?)?; + exports.set("copy", lua.create_function(copy)?)?; + exports.set("copy_ascii", lua.create_function(copy_ascii)?)?; + + Ok(exports) } diff --git a/generator/src/path.rs b/generator/src/path.rs deleted file mode 100644 index 33d5164..0000000 --- a/generator/src/path.rs +++ /dev/null @@ -1,10 +0,0 @@ -use regex::Regex; -use std::env::{var, VarError}; - -pub fn parse_save_path(path: String) -> Result { - let home_path = var("HOME")?; - let regex = Regex::new(r"(~|$HOME)").unwrap(); - let path = regex.replace_all(&path, home_path); - - Ok(path.to_string()) -} diff --git a/generator/src/save.rs b/generator/src/save.rs deleted file mode 100644 index 4521cf0..0000000 --- a/generator/src/save.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::{config::TakeSnapshotParams, path::parse_save_path, snapshot::take_snapshot}; -use nvim_oxi::api; - -// The function will be called as FFI on Lua side -#[allow(dead_code)] -pub fn save_snapshot(config: TakeSnapshotParams) -> Result<(), api::Error> { - match &config.save_path { - Some(path) => { - if !path.ends_with(".png") { - return Err(api::Error::Other( - "The save_path must ends with .png".to_string(), - )); - } - - let pixmap = take_snapshot(config.clone())?; - let path = parse_save_path(path.to_string()) - .map_err(|err| api::Error::Other(err.to_string()))?; - - pixmap - .save_png(path) - .map_err(|err| api::Error::Other(err.to_string())) - } - None => Err(api::Error::Other( - "Cannot find 'save_path' in config".to_string(), - )), - } -} diff --git a/generator/src/snapshot.rs b/generator/src/snapshot.rs deleted file mode 100644 index 04402d5..0000000 --- a/generator/src/snapshot.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::sync::Arc; - -use tiny_skia::Pixmap; - -use crate::components::background::Background; -use crate::components::breadcrumbs::Breadcrumbs; -use crate::components::code_block::CodeBlock; -use crate::components::container::Container; -use crate::components::editor::code::Code; -use crate::components::editor::mac_title_bar::MacTitleBar; -use crate::components::highlight_code_block::HighlightCodeBlock; -use crate::components::interface::component::ComponentContext; -use crate::components::interface::render_error; -use crate::components::line_number::LineNumber; -use crate::components::rect::Rect; -use crate::components::watermark::Watermark; -use crate::config::TakeSnapshotParams; - -// Scale the screenshot to 3 times its size -const SCALE_FACTOR: f32 = 3.; -const LINE_HEIGHT: f32 = 20.; -const VIEW_WATERMARK_PADDING: f32 = 82.; - -// The params is come from neovim instance -pub fn take_snapshot(params: TakeSnapshotParams) -> render_error::Result { - let context = ComponentContext { - scale_factor: SCALE_FACTOR, - take_snapshot_params: Arc::new(params.clone()), - }; - let background_padding = Background::parse_background_padding( - params.bg_x_padding, - params.bg_y_padding, - params.bg_padding, - ); - - // If vertical background padding is less than 82., should hidden watermark component - // If watermark text is equal to "", the watermark component is hidden - let watermark = if background_padding.bottom >= VIEW_WATERMARK_PADDING { - params.watermark - } else { - "".to_string() - }; - let pixmap = Container::from_children(vec![Box::new(Background::new( - background_padding, - vec![ - Box::new(Rect::new( - 16., - params.min_width, - vec![ - Box::new(MacTitleBar::from_radius(8., params.mac_window_bar)), - Box::new(Breadcrumbs::from_path( - params.file_path, - 15., - params.breadcrumbs_separator, - params.has_breadcrumbs, - )), - Box::new(CodeBlock::from_children(vec![ - Box::new(HighlightCodeBlock::from_line_number( - params.highlight_start_line_number, - params.highlight_end_line_number, - LINE_HEIGHT, - )), - Box::new(LineNumber::new( - ¶ms.code, - params.start_line_number, - LINE_HEIGHT, - )), - Box::new(Code::new(params.code, LINE_HEIGHT, 15.)), - ])), - ], - )), - Box::new(Watermark::new(watermark)), - ], - ))]) - .draw_root(&context)?; - - Ok(pixmap) -} diff --git a/generator/src/snapshot_config.rs b/generator/src/snapshot_config.rs new file mode 100644 index 0000000..7eed36c --- /dev/null +++ b/generator/src/snapshot_config.rs @@ -0,0 +1,12 @@ +use codesnap::config::SnapshotConfig; +use mlua::{FromLua, LuaSerdeExt}; + +pub struct SnapshotConfigLua(pub SnapshotConfig); + +impl FromLua for SnapshotConfigLua { + fn from_lua(value: mlua::Value, lua: &mlua::Lua) -> mlua::Result { + let config: SnapshotConfig = lua.from_value::(value)?; + + Ok(SnapshotConfigLua(config)) + } +} diff --git a/generator/src/text.rs b/generator/src/text.rs deleted file mode 100644 index 498b4b4..0000000 --- a/generator/src/text.rs +++ /dev/null @@ -1,121 +0,0 @@ -use cosmic_text::{ - Align, Attrs, AttrsList, Buffer, BufferLine, Color, FontSystem, LineEnding, Metrics, Shaping, - SwashCache, -}; -use tiny_skia::{Paint, Pixmap, Rect, Transform}; - -pub struct FontRenderer { - font_system: FontSystem, - scale_factor: f32, - metrics: Metrics, -} - -impl FontRenderer { - pub fn new( - font_size: f32, - line_height: f32, - scale_factor: f32, - fonts_folder: &str, - ) -> FontRenderer { - let mut font_system = FontSystem::new(); - - font_system.db_mut().load_fonts_dir(fonts_folder); - - let metrics = Metrics::new(font_size, line_height).scale(scale_factor.clone()); - - FontRenderer { - metrics, - font_system, - scale_factor, - } - } - - pub fn draw_text( - &mut self, - x: f32, - y: f32, - w: f32, - h: f32, - spans: Vec<(&str, Attrs)>, - pixmap: &mut Pixmap, - ) { - let mut buffer = Buffer::new(&mut self.font_system, self.metrics); - buffer.set_size( - &mut self.font_system, - Some(w * self.scale_factor), - Some(h * self.scale_factor), - ); - buffer.set_rich_text( - &mut self.font_system, - spans, - Attrs::new(), - Shaping::Advanced, - ); - self.draw(x, y, &mut buffer, pixmap); - } - - pub fn draw_line( - &mut self, - x: f32, - y: f32, - w: f32, - h: f32, - line: &str, - attrs: Attrs, - align: Option, - pixmap: &mut Pixmap, - ) { - let mut buffer = Buffer::new(&mut self.font_system, self.metrics); - let mut line = if cfg!(unix) { - BufferLine::new( - line, - LineEnding::Lf, - AttrsList::new(attrs), - Shaping::Advanced, - ) - } else if cfg!(windows) { - BufferLine::new( - line, - LineEnding::CrLf, - AttrsList::new(attrs), - Shaping::Advanced, - ) - } else { - panic!("Unsupported OS") - }; - - line.set_align(align); - buffer.lines = vec![line]; - buffer.set_size(&mut self.font_system, Some(w), Some(h)); - self.draw(x, y, &mut buffer, pixmap); - } - - fn draw<'a>(&mut self, x: f32, y: f32, buffer: &mut Buffer, pixmap: &mut Pixmap) { - let mut swash_cache = SwashCache::new(); - let default_font_color = Color::rgb(255, 255, 255); - - buffer.draw( - &mut self.font_system, - &mut swash_cache, - default_font_color, - |font_x, font_y, w, h, color| { - let mut paint = Paint { - anti_alias: true, - ..Default::default() - }; - - paint.set_color_rgba8(color.r(), color.g(), color.b(), color.a()); - - let rect = Rect::from_xywh( - font_x as f32 + x * self.scale_factor, - font_y as f32 + y * self.scale_factor, - w as f32, - h as f32, - ) - .expect("Cannot draw text on pixmap"); - - pixmap.fill_rect(rect, &paint, Transform::identity(), None); - }, - ); - } -} diff --git a/lua/codesnap/config.lua b/lua/codesnap/config.lua index a91121b..a41da40 100644 --- a/lua/codesnap/config.lua +++ b/lua/codesnap/config.lua @@ -5,33 +5,7 @@ local static = require("codesnap.static") local table_utils = require("codesnap.utils.table") local config_module = {} -local assets_folder = static.cwd .. "/assets" - --- Auto generated codesnap filename based on the following rule: --- CodeSnap_y-m-d_at_h:m:s -local function auto_generate_snap_filename() - return os.date("CodeSnap_%Y-%m-%d_at_%H:%M:%S.png") -end - --- If the save_path is already configured, but no explicit filename is specified, --- it will be replaced with auto-generated filename -local function parse_save_path(save_path) - if save_path == nil or string_utils.ends_with(save_path, "png") then - return save_path - end - - local parsed_save_path = string_utils.ends_with(save_path, "/") and save_path or save_path .. "/" - - return parsed_save_path .. auto_generate_snap_filename() -end - -local function get_file_path(show_workspace) - local relative_path = path_utils.get_relative_path() - - return show_workspace and path_utils.get_workspace() .. "/" .. relative_path or relative_path -end - -function config_module.get_config(extension) +function config_module.get_config() local code = visual_utils.get_selected_text() local start_line_number = visual_utils.get_start_line_number() @@ -40,19 +14,20 @@ function config_module.get_config(extension) return end - local config = table_utils.merge({ - code = code, - extension = extension, - code_file_path = vim.fn.expand("%:p"), - fonts_folder = assets_folder .. "/fonts", - themes_folder = assets_folder .. "/themes", - theme = "base16-onedark", - file_path = static.config.has_breadcrumbs and get_file_path(static.config.show_workspace) or "", - start_line_number = static.config.has_line_number and start_line_number or nil, - }, static.config) - - config.save_path = parse_save_path(config.save_path) - + local config = table_utils.assign(static.config, { + code = { + content = code, + file_path = vim.fn.expand("%:p"), + line_number = { + start_number = start_line_number, + color = "#495162", + }, + }, + -- file_path = static.config.has_breadcrumbs and get_file_path(static.config.show_workspace) or "", + -- start_line_number = static.config.has_line_number and start_line_number or nil, + }) + + -- config.save_path = parse_save_path(config.save_path) return config end diff --git a/lua/codesnap/init.lua b/lua/codesnap/init.lua index 5da5971..0410419 100644 --- a/lua/codesnap/init.lua +++ b/lua/codesnap/init.lua @@ -2,75 +2,114 @@ local static = require("codesnap.static") local visual_utils = require("codesnap.utils.visual") local table_utils = require("codesnap.utils.table") local string_utils = require("codesnap.utils.string") +local path_utils = require("codesnap.utils.path") +local module = require("codesnap.module") local config_module = require("codesnap.config") local highlight_module = require("codesnap.highlight") local main = { cwd = static.cwd, - preview_switch = static.preview_switch, highlight_mode_config = nil, } -function main.setup(config) - static.config = table_utils.merge(static.config, config == nil and {} or config) -end +-- Prepare the path of the Rust module +-- Concat lib?.extension and ?.extension to package.cpath +package.cpath = path_utils.join(";", package.cpath, module.generator_file("?"), module.generator_file("lib?")) -function main.copy_into_clipboard_with_config(config) - require("generator").copy_into_clipboard(config) - vim.cmd("delmarks <>") - vim.notify("Save snapshot into clipboard successfully") -end - --- Take ASCII code snapshot into clipboard -function main.copy_ascii_snapshot(extension) - require("generator").copy_ascii(config_module.get_config(extension)) - vim.cmd("delmarks <>") - vim.notify("Save snapshot into clipboard successfully") +function main.setup(config) + static.config = table_utils.merge_config(static.config, config == nil and {} or config) end -function main.save_snapshot_with_config(config) - if string_utils.is_str_empty(static.config.save_path) then - error( - "If you want to save snapshot in somewhere, you should config the save_path before, refer: https://github.com/mistricky/codesnap.nvim?tab=readme-ov-file#save-the-snapshot", - 0 - ) - end - - local matched_extension = string.match(static.config.save_path, "%.(.+)$") +-- Save snapshot to specified save_path +--- @param save_path string +function main.save(save_path) + local generator = require("generator") - if matched_extension ~= "png" and matched_extension ~= nil then - error("The extension of save_path should be .png", 0) + if save_path == nil then + error("Save path is not specified", 0) end - require("generator").save_snapshot(config) + generator.save(save_path, config_module.get_config()) vim.cmd("delmarks <>") - ---@diagnostic disable-next-line: need-check-nil - vim.notify("Save snapshot in " .. config.save_path .. " successfully") + vim.notify("Save snapshot in " .. save_path .. " successfully!") end --- Take a snapshot and copy it into clipboard -function main.copy_into_clipboard(extension) - main.copy_into_clipboard_with_config(config_module.get_config(extension)) -end +-- Copy snapshot into clipboard +--- @param type? string +function main.copy(type) + local snapshot_type = type == nil and "png" or type + local generator = require("generator") --- Take a snapshot and save it into the specified path -function main.save_snapshot(extension) - main.save_snapshot_with_config(config_module.get_config(extension)) + generator.copy(snapshot_type, config_module.get_config()) + vim.cmd("delmarks <>") + vim.notify("The snapshot is copied into clipboard successfully!") end -function main.highlight_mode_copy_into_clipboard(extension) - main.highlight_mode_config = config_module.get_config(extension) +-- Generate ASCII code snapshot and copy it into clipboard +function main.copy_ascii() + local generator = require("generator") - highlight_module.create_highlight_selector_window( - "copy_into_clipboard_with_config", - visual_utils.get_selected_lines() - ) + generator.copy_ascii(config_module.get_config()) + vim.cmd("delmarks <>") + vim.notify("The ASCII code snapshot is copied into clipboard successfully!") end -function main.highlight_mode_save_snapshot(extension) - main.highlight_mode_config = config_module.get_config(extension) - - highlight_module.create_highlight_selector_window("save_snapshot_with_config", visual_utils.get_selected_lines()) -end +-- function main.copy_into_clipboard_with_config(config) +-- require("generator").copy_into_clipboard(config) +-- vim.cmd("delmarks <>") +-- vim.notify("Save snapshot into clipboard successfully") +-- end +-- +-- -- Take ASCII code snapshot into clipboard +-- function main.copy_ascii_snapshot(extension) +-- require("generator").copy_ascii(config_module.get_config(extension)) +-- vim.cmd("delmarks <>") +-- vim.notify("Save snapshot into clipboard successfully") +-- end +-- +-- function main.save_snapshot_with_config(config) +-- if string_utils.is_str_empty(static.config.save_path) then +-- error( +-- "If you want to save snapshot in somewhere, you should config the save_path before, refer: https://github.com/mistricky/codesnap.nvim?tab=readme-ov-file#save-the-snapshot", +-- 0 +-- ) +-- end +-- +-- local matched_extension = string.match(static.config.save_path, "%.(.+)$") +-- +-- if matched_extension ~= "png" and matched_extension ~= nil then +-- error("The extension of save_path should be .png", 0) +-- end +-- +-- require("generator").save_snapshot(config) +-- vim.cmd("delmarks <>") +-- ---@diagnostic disable-next-line: need-check-nil +-- vim.notify("Save snapshot in " .. config.save_path .. " successfully") +-- end +-- +-- -- Take a snapshot and copy it into clipboard +-- function main.copy_into_clipboard(extension) +-- main.copy_into_clipboard_with_config(config_module.get_config(extension)) +-- end +-- +-- -- Take a snapshot and save it into the specified path +-- function main.save_snapshot(extension) +-- main.save_snapshot_with_config(config_module.get_config(extension)) +-- end +-- +-- function main.highlight_mode_copy_into_clipboard(extension) +-- main.highlight_mode_config = config_module.get_config(extension) +-- +-- highlight_module.create_highlight_selector_window( +-- "copy_into_clipboard_with_config", +-- visual_utils.get_selected_lines() +-- ) +-- end +-- +-- function main.highlight_mode_save_snapshot(extension) +-- main.highlight_mode_config = config_module.get_config(extension) +-- +-- highlight_module.create_highlight_selector_window("save_snapshot_with_config", visual_utils.get_selected_lines()) +-- end return main diff --git a/lua/codesnap/module.lua b/lua/codesnap/module.lua new file mode 100644 index 0000000..3b8045d --- /dev/null +++ b/lua/codesnap/module.lua @@ -0,0 +1,24 @@ +local module = {} + +local path_utils = require("codesnap.utils.path") + +local OS_LIB_EXTENSION_MAP = { + mac = "dylib", + osx = "dylib", + windows = "dll", + linux = "so", +} + +local RUST_BUILD_DIR = path_utils.with_dir_name("../../../generator/target/debug") + +function module.get_lib_extension() + local extension = OS_LIB_EXTENSION_MAP[jit.os:lower()] + + return extension or "so" +end + +function module.generator_file(filename) + return path_utils.join("/", RUST_BUILD_DIR, filename .. "." .. module.get_lib_extension()) +end + +return module diff --git a/lua/codesnap/static.lua b/lua/codesnap/static.lua index 0c571c9..56aa802 100644 --- a/lua/codesnap/static.lua +++ b/lua/codesnap/static.lua @@ -2,21 +2,47 @@ local path_utils = require("codesnap.utils.path") return { config = { - mac_window_bar = true, - title = "CodeSnap.nvim", - code_font_family = "CaskaydiaCove Nerd Font", - watermark_font_family = "Pacifico", - watermark = "CodeSnap.nvim", - bg_theme = "default", - breadcrumbs_separator = "/", - has_breadcrumbs = false, - has_line_number = false, - show_workspace = false, - min_width = 0, - bg_x_padding = 122, - bg_y_padding = 82, - save_path = path_utils.get_default_save_path(), + window = { + mac_window_bar = true, + shadow = 20, + margin = { + x = 82, + y = 82, + }, + border = { + color = "#ffffff30", + }, + }, + code = { + font_family = "CaskaydiaCove Nerd Font", + theme = "candy", + }, + watermark = { + content = "CodeSnap", + font_family = "Pacifico", + color = "#ffffff", + }, + scale_factor = 3, + background = { + start = { + x = 0, + y = 0, + }, + ["end"] = { + x = "max", + y = 0, + }, + stops = { + { + position = 0, + color = "#6bcba5", + }, + { + position = 1, + color = "#caf4c2", + }, + }, + }, }, cwd = path_utils.back(path_utils.back(debug.getinfo(1, "S").source:sub(2):match("(.*[/\\])"))), - preview_switch = true, } diff --git a/lua/codesnap/utils/path.lua b/lua/codesnap/utils/path.lua index 37c06f8..6da3a00 100644 --- a/lua/codesnap/utils/path.lua +++ b/lua/codesnap/utils/path.lua @@ -2,6 +2,20 @@ local string_utils = require("codesnap.utils.string") local platform_utils = require("codesnap.utils.platform") local path_utils = {} +function path_utils.join(separator, ...) + local args = { ... } + + return table.concat(args, separator) +end + +function path_utils.dir_name() + return debug.getinfo(1).source:match("@?(.*/)") +end + +function path_utils.with_dir_name(path) + return path_utils.dir_name() .. path +end + function path_utils.get_escaped_cwd() local cwd = vim.fn.getcwd() diff --git a/lua/codesnap/utils/table.lua b/lua/codesnap/utils/table.lua index bfb993a..d7da6ef 100644 --- a/lua/codesnap/utils/table.lua +++ b/lua/codesnap/utils/table.lua @@ -2,9 +2,17 @@ local list_utils = require("codesnap.utils.list") local table_utils = {} function table_utils.assign(t, props) + local parsed_t = t or {} + for k, v in pairs(props) do - t[k] = v + if type(v) == "table" then + parsed_t[k] = table_utils.assign(parsed_t[k], v) + else + parsed_t[k] = v + end end + + return parsed_t end function table_utils.merge(t1, t2) @@ -15,6 +23,22 @@ function table_utils.merge(t1, t2) return t1 end +-- Merge two tables, if the value of the key in t2 is "none", it will be removed from t1 +-- which is useful for removing a key from the config, in CodeSnap, set border = None to remove the border +function table_utils.merge_config(t1, t2) + for k, v in pairs(t1) do + if type(v) == "table" and type(t2[k]) == "table" then + t1[k] = table_utils.merge_config(v, t2[k]) + elseif t2[k] == "none" then + t1[k] = nil + elseif t2[k] ~= nil then + t1[k] = t2[k] + end + end + + return t1 +end + function table_utils.is_array(t) return type(t[1]) == "number" end @@ -67,14 +91,4 @@ function table_utils.to_string(t) return parse(t) end --- function table_utils.to_string(t) --- local result = "" --- --- for key, value in pairs(t) do --- result = result .. key .. ":" .. tostring(value) .. "," --- end --- --- return "{" .. result .. "}" --- end - return table_utils diff --git a/lua/linux-x86_64generator.so b/lua/linux-x86_64generator.so deleted file mode 100755 index a2e7ea2..0000000 Binary files a/lua/linux-x86_64generator.so and /dev/null differ diff --git a/lua/mac-aarch64generator.so b/lua/mac-aarch64generator.so deleted file mode 100755 index b86a592..0000000 Binary files a/lua/mac-aarch64generator.so and /dev/null differ diff --git a/lua/mac-x86_64generator.so b/lua/mac-x86_64generator.so deleted file mode 100755 index 0463521..0000000 Binary files a/lua/mac-x86_64generator.so and /dev/null differ diff --git a/plugin/codesnap.lua b/plugin/codesnap.lua index 8fe68fa..db92b38 100644 --- a/plugin/codesnap.lua +++ b/plugin/codesnap.lua @@ -19,24 +19,30 @@ local function take_snapshot(take_snapshot_function) end end -vim.api.nvim_create_user_command("CodeSnap", take_snapshot(codesnap.copy_into_clipboard), { nargs = "*", range = "%" }) - -vim.api.nvim_create_user_command("CodeSnapSave", take_snapshot(codesnap.save_snapshot), { nargs = "*", range = "%" }) - -vim.api.nvim_create_user_command( - "CodeSnapASCII", - take_snapshot(codesnap.copy_ascii_snapshot), - { nargs = "*", range = "%" } -) - -vim.api.nvim_create_user_command( - "CodeSnapHighlight", - take_snapshot(codesnap.highlight_mode_copy_into_clipboard), - { nargs = "*", range = "%" } -) - -vim.api.nvim_create_user_command( - "CodeSnapSaveHighlight", - take_snapshot(codesnap.highlight_mode_save_snapshot), - { nargs = "*", range = "%" } -) +vim.api.nvim_create_user_command("CodeSnapSave", take_snapshot(codesnap.save), { nargs = "*", range = "%" }) + +vim.api.nvim_create_user_command("CodeSnap", take_snapshot(codesnap.copy), { nargs = "*", range = "%" }) + +vim.api.nvim_create_user_command("CodeSnapASCII", take_snapshot(codesnap.copy_ascii), { nargs = "*", range = "%" }) + +-- vim.api.nvim_create_user_command("CodeSnap", take_snapshot(codesnap.copy_into_clipboard), { nargs = "*", range = "%" }) +-- +-- vim.api.nvim_create_user_command("CodeSnapSave", take_snapshot(codesnap.save_snapshot), { nargs = "*", range = "%" }) +-- +-- vim.api.nvim_create_user_command( +-- "CodeSnapASCII", +-- take_snapshot(codesnap.copy_ascii_snapshot), +-- { nargs = "*", range = "%" } +-- ) +-- +-- vim.api.nvim_create_user_command( +-- "CodeSnapHighlight", +-- take_snapshot(codesnap.highlight_mode_copy_into_clipboard), +-- { nargs = "*", range = "%" } +-- ) +-- +-- vim.api.nvim_create_user_command( +-- "CodeSnapSaveHighlight", +-- take_snapshot(codesnap.highlight_mode_save_snapshot), +-- { nargs = "*", range = "%" } +-- )