From a088d8b580cb6f6d7067cc08511f8fd4321b1a50 Mon Sep 17 00:00:00 2001 From: Mist Date: Mon, 19 Feb 2024 22:27:17 +0800 Subject: [PATCH] [Feat] finished mvp version --- .cargo/config | 11 - .gitignore | 15 +- Cargo.lock | 660 ------------------ Cargo.toml | 10 - lua/codesnap/client.lua | 59 ++ lua/codesnap/init.lua | 20 +- lua/codesnap/static.lua | 10 +- lua/codesnap/utils/list.lua | 10 + lua/codesnap/utils/logger.lua | 11 + lua/codesnap/utils/path.lua | 9 + lua/codesnap/utils/table.lua | 53 ++ lua/codesnap/utils/visual.lua | 30 + plugin/codesnap.lua | 30 +- snap-client/package-lock.json | 164 ++++- snap-client/package.json | 8 +- snap-client/public/index.html | 4 + snap-client/src/app.tsx | 63 +- snap-client/src/components/control-bar.tsx | 1 - .../components/control-bar/color-picker.tsx | 3 + .../components/control-bar/control-bar.tsx | 53 ++ .../src/components/control-bar/index.ts | 1 + snap-client/src/components/editor/editor.tsx | 42 ++ snap-client/src/components/editor/frame.tsx | 18 + snap-client/src/components/editor/index.ts | 2 + .../components/editor/mac-style-titlebar.tsx | 18 + snap-client/src/components/index.ts | 2 + snap-client/src/components/panel.tsx | 7 + snap-client/src/hooks/index.ts | 3 + snap-client/src/hooks/use-config.ts | 18 + snap-client/src/hooks/use-event.ts | 32 + snap-client/src/hooks/use-storage.ts | 33 + snap-client/src/index.tsx | 1 + snap-client/src/input.css | 106 +++ snap-client/tailwind.config.ts | 17 +- snap-server/src/event.rs | 7 +- snap-server/src/event_handler.rs | 29 +- snap-server/src/event_handler/arguments.rs | 9 + snap-server/src/event_handler/config.rs | 17 + snap-server/src/event_handler/messages.rs | 2 + snap-server/src/main.rs | 20 +- snap-server/src/server.rs | 37 +- 41 files changed, 911 insertions(+), 734 deletions(-) delete mode 100644 .cargo/config delete mode 100644 Cargo.lock delete mode 100644 Cargo.toml create mode 100644 lua/codesnap/client.lua create mode 100644 lua/codesnap/utils/logger.lua create mode 100644 lua/codesnap/utils/path.lua create mode 100644 lua/codesnap/utils/visual.lua delete mode 100644 snap-client/src/components/control-bar.tsx create mode 100644 snap-client/src/components/control-bar/color-picker.tsx create mode 100644 snap-client/src/components/control-bar/control-bar.tsx create mode 100644 snap-client/src/components/control-bar/index.ts create mode 100644 snap-client/src/components/editor/editor.tsx create mode 100644 snap-client/src/components/editor/frame.tsx create mode 100644 snap-client/src/components/editor/index.ts create mode 100644 snap-client/src/components/editor/mac-style-titlebar.tsx create mode 100644 snap-client/src/components/panel.tsx create mode 100644 snap-client/src/hooks/index.ts create mode 100644 snap-client/src/hooks/use-config.ts create mode 100644 snap-client/src/hooks/use-event.ts create mode 100644 snap-client/src/hooks/use-storage.ts create mode 100644 snap-server/src/event_handler/arguments.rs create mode 100644 snap-server/src/event_handler/config.rs diff --git a/.cargo/config b/.cargo/config deleted file mode 100644 index d47f983..0000000 --- a/.cargo/config +++ /dev/null @@ -1,11 +0,0 @@ -[target.x86_64-apple-darwin] -rustflags = [ - "-C", "link-arg=-undefined", - "-C", "link-arg=dynamic_lookup", -] - -[target.aarch64-apple-darwin] -rustflags = [ - "-C", "link-arg=-undefined", - "-C", "link-arg=dynamic_lookup", -] diff --git a/.gitignore b/.gitignore index 31b976d..56ab412 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,17 @@ /lua_modules /.luarocks -# OS -.DS_Store - # Cargo target + +# Nodejs +node_modules +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local +output.css diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 6c30a83..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,660 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bindgen" -version = "0.68.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", -] - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "bstr" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "either" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libloading" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "libuv-sys2" -version = "1.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6125e1a220a5698a154ce76762d2ef8884baf9f77da7ceb8a3bd8c5ce27df343" -dependencies = [ - "bindgen", - "cc", - "pkg-config", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "lua-src" -version = "546.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da0daa7eee611a4c30c8f5ee31af55266e26e573971ba9336d2993e2da129b2" -dependencies = [ - "cc", -] - -[[package]] -name = "luajit-src" -version = "210.5.6+9cc2e42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b365d859c9ffc187f48bb3e25ec80c3b40cf3f68f53544f4adeaee70554157" -dependencies = [ - "cc", - "which", -] - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "mini-internal" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51c55587ac25c2d63a75e4171221b2803a9b9e83aeb7bdfde5833c4cd578b50d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniserde" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621df4a46e5de4c1541242407da38281ea0e320b94e238477688a36a1a059f7" -dependencies = [ - "itoa", - "mini-internal", - "ryu", -] - -[[package]] -name = "mlua" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3561f79659ff3afad7b25e2bf2ec21507fe601ebecb7f81088669ec4bfd51e" -dependencies = [ - "bstr", - "mlua-sys", - "num-traits", - "once_cell", - "rustc-hash", -] - -[[package]] -name = "mlua-sys" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2847b42764435201d8cbee1f517edb79c4cca4181877b90047587c89e1b7bce4" -dependencies = [ - "cc", - "cfg-if", - "lua-src", - "luajit-src", - "pkg-config", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-traits" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "nvim-oxi" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c9aef30b9ac1033e2d176b76f5eabab48d710a25cf0aa01068b5224a179d88" -dependencies = [ - "miniserde", - "mlua", - "oxi-api", - "oxi-libuv", - "oxi-luajit", - "oxi-macros", - "oxi-types", - "thiserror", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "oxi-api" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e969161dafa13429fe816dfcbdd6cb138c3ed872e263f2a7cab3c41acd8cf174" -dependencies = [ - "oxi-luajit", - "oxi-macros", - "oxi-types", - "serde", - "serde_repr", - "thiserror", -] - -[[package]] -name = "oxi-libuv" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da0c7850edec97513b9f4d77ce9b2f3c80eb60b259c8035e334f3f290785b76" -dependencies = [ - "libuv-sys2", - "once_cell", - "oxi-luajit", - "thiserror", -] - -[[package]] -name = "oxi-luajit" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a644c4c3c35816a6eb174570fc54a968c6047b8b845c1f253c0184fd8aeb25ab" -dependencies = [ - "once_cell", - "thiserror", -] - -[[package]] -name = "oxi-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae7527f018ccf611bf798ecae060c199ba921998125c836c7f236c2425ba0d89" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "oxi-types" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05813abd7733b9ef9618811d66627ce80db6b8321140613872989c6aae5c25db" -dependencies = [ - "libc", - "oxi-luajit", - "serde", - "thiserror", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "serde" -version = "1.0.196" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.196" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_repr" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "snap" -version = "0.1.0" -dependencies = [ - "nvim-oxi", -] - -[[package]] -name = "syn" -version = "2.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "which" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fa5e0c10bf77f44aac573e498d1a82d5fbd5e91f6fc0a99e7be4b38e85e101c" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 4f245b4..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "snap" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -nvim-oxi = {version = "0.4.2", features = ["neovim-nightly", "libuv", "mlua", "test", "__vendored_luajit"]} diff --git a/lua/codesnap/client.lua b/lua/codesnap/client.lua new file mode 100644 index 0000000..22b126c --- /dev/null +++ b/lua/codesnap/client.lua @@ -0,0 +1,59 @@ +local logger = require("codesnap.utils.logger") +local path_utils = require("codesnap.utils.path") + +local client = { + job_id = 0, +} + +function client:connect() + return vim.fn.jobstart({ + path_utils.back(path_utils.back(debug.getinfo(1, "S").source:sub(2):match("(.*[/\\])"))) + .. "/snap-server/target/debug/snap-server", + }, { + stderr_buffered = true, + rpc = true, + on_stderr = function(_, err) + vim.fn.jobstop(self.job_id) + logger.error(err) + end, + on_exit = function() + vim.fn.chanclose(self.job_id) + self.job_id = 0 + end, + }) +end + +function client:init() + return self.job_id == 0 and client:connect() or self.job_id +end + +function client:start() + self.job_id = client:init() + + if self.job_id == 0 then + logger.error("cannot start rpc process") + return + end + + if self.job_id == -1 then + logger.error("rpc process is not executable") + vim.fn.jobstop(self.job_id) + return + end + + return self +end + +function client:send(event, message) + vim.fn.rpcnotify(self.job_id, event, message) +end + +function client:stop() + if self.job_id == 0 or self.job_id == -1 then + return + end + + vim.fn.jobstop(self.job_id) +end + +return client diff --git a/lua/codesnap/init.lua b/lua/codesnap/init.lua index a832410..a703bb5 100644 --- a/lua/codesnap/init.lua +++ b/lua/codesnap/init.lua @@ -1,10 +1,26 @@ -local table_utils = require("utils.table") +local table_utils = require("codesnap.utils.table") local static = require("codesnap.static") +local client = require("codesnap.client") +local visual_utils = require("codesnap.utils.visual") local main = {} function main.setup(config) - static.config = table_utils.merge(static.config, config) + static.config = table_utils.merge(static.config, config == nil and {} or config) + + print(vim.inspect(static.config)) + print(table_utils.serialize_json(static.config)) + print() + + if static.config.auto_load then + client:start() + end + + client:send("config_setup", static.config) +end + +function main.preview_code() + client:send("preview_code", { content = visual_utils.get_selected_text(), language = vim.bo.filetype }) end return main diff --git a/lua/codesnap/static.lua b/lua/codesnap/static.lua index 48194e5..ec8bba9 100644 --- a/lua/codesnap/static.lua +++ b/lua/codesnap/static.lua @@ -1,13 +1,11 @@ return { config = { - breadcrumbs = false, + breadcrumbs = true, column_number = true, mac_window_bar = true, - background = { - color = "#ff0000", - grandient = true, - }, + opacity = true, watermark = "CodeSnap.nvim", + auto_load = true, }, - preview_switch = false, + preview_switch = true, } diff --git a/lua/codesnap/utils/list.lua b/lua/codesnap/utils/list.lua index ee2d2de..d9195cf 100644 --- a/lua/codesnap/utils/list.lua +++ b/lua/codesnap/utils/list.lua @@ -20,4 +20,14 @@ function list_utils.includes(list, value) end) ~= nil end +function list_utils.map(list, fn) + local result = {} + + for i, value in ipairs(list) do + table.insert(result, fn(value, i)) + end + + return result +end + return list_utils diff --git a/lua/codesnap/utils/logger.lua b/lua/codesnap/utils/logger.lua new file mode 100644 index 0000000..168de3a --- /dev/null +++ b/lua/codesnap/utils/logger.lua @@ -0,0 +1,11 @@ +local logger = {} + +function logger.log(level, message) + vim.api.nvim_notify("[" .. level .. "] CodeSnap: " .. tostring(vim.inspect(message)), vim.log.levels[level], {}) +end + +function logger.error(message) + logger.log("ERROR", message) +end + +return logger diff --git a/lua/codesnap/utils/path.lua b/lua/codesnap/utils/path.lua new file mode 100644 index 0000000..617bcb7 --- /dev/null +++ b/lua/codesnap/utils/path.lua @@ -0,0 +1,9 @@ +local path_utils = {} + +function path_utils.back(path) + local parsed_path, _ = path:gsub("/[^\\/]+/?$", "") + + return parsed_path +end + +return path_utils diff --git a/lua/codesnap/utils/table.lua b/lua/codesnap/utils/table.lua index 965313e..732912a 100644 --- a/lua/codesnap/utils/table.lua +++ b/lua/codesnap/utils/table.lua @@ -1,3 +1,4 @@ +local list_utils = require("codesnap.utils.list") local table_utils = {} function table_utils.assign(t, props) @@ -14,4 +15,56 @@ function table_utils.merge(t1, t2) return t1 end +function table_utils.is_array(t) + return type(t[1]) == "number" +end + +function table_utils.typeof(value) + if type(value) == "table" then + if table_utils.is_array(value) then + return "array" + else + return "table" + end + end + + return type(value) +end + +function table_utils.serialize_array(t) + local result = list_utils.map(t, function(ele) + table_utils.serialize_json(ele) + end) + + return "[" .. result.concat(t, ",") .. "]" +end + +function table_utils.serialize_table(t) + local result = {} + + for key, value in pairs(t) do + table.insert(result, string.format('"%s":%s', key, table_utils.serialize_json(value))) + end + + return "{" .. table.concat(result, ",") .. "}" +end + +function table_utils.serialize_string(value) + return '"' .. value .. '"' +end + +function table_utils.serialize_json(t) + local complex_type_parser = { + array = table_utils.serialize_array, + table = table_utils.serialize_table, + string = table_utils.serialize_string, + } + + local parse = complex_type_parser[table_utils.typeof(t)] or function(v) + return v + end + + return parse(t) +end + return table_utils diff --git a/lua/codesnap/utils/visual.lua b/lua/codesnap/utils/visual.lua new file mode 100644 index 0000000..07f7e22 --- /dev/null +++ b/lua/codesnap/utils/visual.lua @@ -0,0 +1,30 @@ +local visual_utils = {} + +function visual_utils.get_selected_text() + local start_pos = vim.fn.getpos("v") + local end_pos = vim.fn.getpos(".") + + if start_pos[2] == end_pos[2] then + return vim.api.nvim_buf_get_lines(0, start_pos[2] - 1, start_pos[2], false)[1]:sub(start_pos[3], end_pos[3] - 1) + else + -- 如果选中的是多行文本,则需要分别获取每一行的文本 + local selected_text = {} + for i = start_pos[2], end_pos[2] do + -- 使用 vim.api.nvim_buf_get_lines() 函数获取选中的文本 + local line_text = vim.api.nvim_buf_get_lines(0, i - 1, i, false)[1] + -- 如果是选中的第一行,需要从 mark 'v' 的列开始获取 + if i == start_pos[2] then + line_text = line_text:sub(start_pos[3]) + end + -- 如果是选中的最后一行,需要获取到当前光标的列 + if i == end_pos[2] then + line_text = line_text:sub(1, end_pos[3] - 1) + end + table.insert(selected_text, line_text) + end + -- 输出当前选中的文本 + return table.concat(selected_text, "\n") + end +end + +return visual_utils diff --git a/plugin/codesnap.lua b/plugin/codesnap.lua index 625b392..99602a7 100644 --- a/plugin/codesnap.lua +++ b/plugin/codesnap.lua @@ -1,5 +1,29 @@ local codesnap = require("codesnap") +local static = require("codesnap.static") +local client = require("codesnap.client") -vim.api.nvim_create_user_command("CodeSnap", function() - codesnap.setup() -end, {}) +-- snap code +vim.api.nvim_create_user_command("CodeSnap", function() end, {}) + +vim.api.nvim_create_user_command("CodeSnapPreviewOn", function() end, {}) + +vim.api.nvim_create_user_command("CodeSnapPreviewOff", function() end, {}) + +vim.api.nvim_create_autocmd({ "CursorMoved" }, { + callback = function() + local mode = vim.api.nvim_get_mode().mode + + if mode ~= "v" or not static.preview_switch then + return + end + + codesnap.preview_code() + end, +}) + +vim.api.nvim_create_autocmd({ "VimLeavePre" }, { + pattern = "*", + callback = function() + client:stop() + end, +}) diff --git a/snap-client/package-lock.json b/snap-client/package-lock.json index a5971d9..1187181 100644 --- a/snap-client/package-lock.json +++ b/snap-client/package-lock.json @@ -8,6 +8,7 @@ "name": "my-app", "version": "0.1.0", "dependencies": { + "@tailwindcss/typography": "^0.5.10", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -15,14 +16,17 @@ "@types/node": "^16.18.81", "@types/react": "^18.2.55", "@types/react-dom": "^18.2.19", + "highlight.js": "^11.9.0", + "html-to-image": "^1.11.11", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", + "react-use-websocket": "^3.0.0", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, "devDependencies": { - "react-use-websocket": "^3.0.0", + "daisyui": "^3.9.4", "tailwindcss": "^3.4.1" } }, @@ -3660,6 +3664,32 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz", + "integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==", + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@testing-library/dom": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", @@ -6362,6 +6392,16 @@ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" }, + "node_modules/css-selector-tokenizer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz", + "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, "node_modules/css-tree": { "version": "1.0.0-alpha.37", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", @@ -6559,6 +6599,26 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/daisyui": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.9.4.tgz", + "integrity": "sha512-fvi2RGH4YV617/6DntOVGcOugOPym9jTGWW2XySb5ZpvdWO4L7bEG77VHirrnbRUEWvIEVXkBpxUz2KFj0rVnA==", + "dev": true, + "dependencies": { + "colord": "^2.9", + "css-selector-tokenizer": "^0.8", + "postcss": "^8", + "postcss-js": "^4", + "tailwindcss": "^3.1" + }, + "engines": { + "node": ">=16.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/daisyui" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -8065,6 +8125,12 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "node_modules/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -8878,6 +8944,14 @@ "he": "bin/he" } }, + "node_modules/highlight.js": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", + "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -8980,6 +9054,11 @@ "node": ">=12" } }, + "node_modules/html-to-image": { + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.11.tgz", + "integrity": "sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==" + }, "node_modules/html-webpack-plugin": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", @@ -12108,11 +12187,21 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -14817,7 +14906,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-3.0.0.tgz", "integrity": "sha512-BInlbhXYrODBPKIplDAmI0J1VPM+1KhCLN09o+dzgQ8qMyrYs4t5kEYmCrTqyRuMTmpahylHFZWQXpfYyDkqOw==", - "dev": true, "peerDependencies": { "react": ">= 16.8.0", "react-dom": ">= 16.8.0" @@ -20429,6 +20517,28 @@ "loader-utils": "^2.0.0" } }, + "@tailwindcss/typography": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz", + "integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==", + "requires": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + } + } + }, "@testing-library/dom": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", @@ -22460,6 +22570,16 @@ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" }, + "css-selector-tokenizer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz", + "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, "css-tree": { "version": "1.0.0-alpha.37", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", @@ -22602,6 +22722,19 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "daisyui": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.9.4.tgz", + "integrity": "sha512-fvi2RGH4YV617/6DntOVGcOugOPym9jTGWW2XySb5ZpvdWO4L7bEG77VHirrnbRUEWvIEVXkBpxUz2KFj0rVnA==", + "dev": true, + "requires": { + "colord": "^2.9", + "css-selector-tokenizer": "^0.8", + "postcss": "^8", + "postcss-js": "^4", + "tailwindcss": "^3.1" + } + }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -23723,6 +23856,12 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, "fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -24282,6 +24421,11 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "highlight.js": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", + "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==" + }, "hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -24364,6 +24508,11 @@ "terser": "^5.10.0" } }, + "html-to-image": { + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.11.tgz", + "integrity": "sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==" + }, "html-webpack-plugin": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", @@ -26594,11 +26743,21 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==" + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -28373,7 +28532,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-3.0.0.tgz", "integrity": "sha512-BInlbhXYrODBPKIplDAmI0J1VPM+1KhCLN09o+dzgQ8qMyrYs4t5kEYmCrTqyRuMTmpahylHFZWQXpfYyDkqOw==", - "dev": true, "requires": {} }, "read-cache": { diff --git a/snap-client/package.json b/snap-client/package.json index b237f66..dccc594 100644 --- a/snap-client/package.json +++ b/snap-client/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@tailwindcss/typography": "^0.5.10", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -10,12 +11,14 @@ "@types/node": "^16.18.81", "@types/react": "^18.2.55", "@types/react-dom": "^18.2.19", + "highlight.js": "^11.9.0", + "html-to-image": "^1.11.11", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", + "react-use-websocket": "^3.0.0", "typescript": "^4.9.5", - "web-vitals": "^2.1.4", - "react-use-websocket": "^3.0.0" + "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", @@ -44,6 +47,7 @@ ] }, "devDependencies": { + "daisyui": "^3.9.4", "tailwindcss": "^3.4.1" } } diff --git a/snap-client/public/index.html b/snap-client/public/index.html index aa069f2..887db46 100644 --- a/snap-client/public/index.html +++ b/snap-client/public/index.html @@ -3,6 +3,10 @@ + + + + (null); - const handleClickSendMessage = useCallback(() => { - sendMessage("Hello"); + const handleCopyButtonClick = useCallback(async () => { + if (!frameRef.current) { + return; + } + + const blob = await toBlob(frameRef.current); + const clipboardItem = new ClipboardItem({ "image/png": blob! }); + + navigator.clipboard.write([clipboardItem]); }, []); - console.info(lastMessage); - return ( -
- - {lastMessage?.data ?? ""} - - +
+

+ CodeSnap.nvim +

+ + +
+ + + {event?.code?.content ?? CODE_EMPTY_PLACEHOLDER} + + +
+
); } diff --git a/snap-client/src/components/control-bar.tsx b/snap-client/src/components/control-bar.tsx deleted file mode 100644 index 785bac2..0000000 --- a/snap-client/src/components/control-bar.tsx +++ /dev/null @@ -1 +0,0 @@ -export const ControlBar = {}; diff --git a/snap-client/src/components/control-bar/color-picker.tsx b/snap-client/src/components/control-bar/color-picker.tsx new file mode 100644 index 0000000..88509ae --- /dev/null +++ b/snap-client/src/components/control-bar/color-picker.tsx @@ -0,0 +1,3 @@ +export const ColorPicker = () => { + return
; +}; diff --git a/snap-client/src/components/control-bar/control-bar.tsx b/snap-client/src/components/control-bar/control-bar.tsx new file mode 100644 index 0000000..9e56463 --- /dev/null +++ b/snap-client/src/components/control-bar/control-bar.tsx @@ -0,0 +1,53 @@ +import { ColorPicker } from "./color-picker"; + +interface ControlBarProps { + onCopyClick(): void; +} + +export const ControlBar = ({ onCopyClick }: ControlBarProps) => { + return ( +
+ +
+ + + +
+
+ ); +}; diff --git a/snap-client/src/components/control-bar/index.ts b/snap-client/src/components/control-bar/index.ts new file mode 100644 index 0000000..644e990 --- /dev/null +++ b/snap-client/src/components/control-bar/index.ts @@ -0,0 +1 @@ +export * from "./control-bar"; diff --git a/snap-client/src/components/editor/editor.tsx b/snap-client/src/components/editor/editor.tsx new file mode 100644 index 0000000..57fc61b --- /dev/null +++ b/snap-client/src/components/editor/editor.tsx @@ -0,0 +1,42 @@ +import { MacStyleTitleBar } from "./mac-style-titlebar"; +import hljs from "highlight.js"; + +export interface EditorProps { + macStyleTitleBar?: boolean; + language?: string; + opacity?: boolean; + children: string; +} + +const highlightLanguage = (code: string, language?: string) => { + if (!language) { + return hljs.highlightAuto(code).value; + } + + try { + return hljs.highlight(code, { language }).value; + } catch { + return hljs.highlightAuto(code).value; + } +}; + +export const Editor = ({ + children, + language, + opacity = true, + macStyleTitleBar = true, +}: EditorProps) => ( +
+ {macStyleTitleBar && } +
+      
+    
+
+); diff --git a/snap-client/src/components/editor/frame.tsx b/snap-client/src/components/editor/frame.tsx new file mode 100644 index 0000000..f74fa6c --- /dev/null +++ b/snap-client/src/components/editor/frame.tsx @@ -0,0 +1,18 @@ +import { forwardRef, PropsWithChildren } from "react"; + +export interface FrameProps { + watermark?: string; +} + +export const Frame = forwardRef>( + ({ children, watermark }, ref) => ( +
+ {children} + {watermark && ( +

+ {watermark} +

+ )} +
+ ), +); diff --git a/snap-client/src/components/editor/index.ts b/snap-client/src/components/editor/index.ts new file mode 100644 index 0000000..a3d93b9 --- /dev/null +++ b/snap-client/src/components/editor/index.ts @@ -0,0 +1,2 @@ +export * from "./frame"; +export * from "./editor"; diff --git a/snap-client/src/components/editor/mac-style-titlebar.tsx b/snap-client/src/components/editor/mac-style-titlebar.tsx new file mode 100644 index 0000000..a65355e --- /dev/null +++ b/snap-client/src/components/editor/mac-style-titlebar.tsx @@ -0,0 +1,18 @@ +interface ButtonProps { + color: string; +} + +const Button = ({ color }: ButtonProps) => ( +
+); + +export const MacStyleTitleBar = () => ( +
+
+); diff --git a/snap-client/src/components/index.ts b/snap-client/src/components/index.ts index 644e990..0765ac0 100644 --- a/snap-client/src/components/index.ts +++ b/snap-client/src/components/index.ts @@ -1 +1,3 @@ export * from "./control-bar"; +export * from "./panel"; +export * from "./editor"; diff --git a/snap-client/src/components/panel.tsx b/snap-client/src/components/panel.tsx new file mode 100644 index 0000000..6023a04 --- /dev/null +++ b/snap-client/src/components/panel.tsx @@ -0,0 +1,7 @@ +import { PropsWithChildren } from "react"; + +export interface PanelProps {} + +export const Panel = ({ children }: PropsWithChildren) => ( +
{children}
+); diff --git a/snap-client/src/hooks/index.ts b/snap-client/src/hooks/index.ts new file mode 100644 index 0000000..a53cdcc --- /dev/null +++ b/snap-client/src/hooks/index.ts @@ -0,0 +1,3 @@ +export * from "./use-event"; +export * from "./use-storage"; +export * from "./use-config"; diff --git a/snap-client/src/hooks/use-config.ts b/snap-client/src/hooks/use-config.ts new file mode 100644 index 0000000..c4ca2aa --- /dev/null +++ b/snap-client/src/hooks/use-config.ts @@ -0,0 +1,18 @@ +import { useLocalStorage } from "./use-storage"; + +export interface Config { + breadcrumbs: boolean; + column_number: boolean; + mac_window_bar: boolean; + opacity: boolean; + watermark: string; + auto_load: boolean; +} + +const CONFIG_STORAGE_KEY = "CONFIG_STORAGE_KEY"; + +export const useConfig = (defaultConfig?: Config) => { + const [config] = useLocalStorage(CONFIG_STORAGE_KEY, defaultConfig); + + return config; +}; diff --git a/snap-client/src/hooks/use-event.ts b/snap-client/src/hooks/use-event.ts new file mode 100644 index 0000000..f9c12d7 --- /dev/null +++ b/snap-client/src/hooks/use-event.ts @@ -0,0 +1,32 @@ +import { useMemo } from "react"; +import { Config } from "./use-config"; + +export enum EventType { + CONFIG_SETUP = "config_setup", + CODE = "code", +} + +type CodeMessage = { + content: string; + language: string; +}; + +type ParsedConfig = { + [EventType.CODE]: CodeMessage; + [EventType.CONFIG_SETUP]: Config; +}; + +export const useEvent = ( + event: MessageEvent | null, +): Partial | undefined => + useMemo(() => { + if (!event) { + return undefined; + } + + const parsedEvent = JSON.parse(event.data); + + return { + [parsedEvent.name]: parsedEvent.data, + }; + }, [event]); diff --git a/snap-client/src/hooks/use-storage.ts b/snap-client/src/hooks/use-storage.ts new file mode 100644 index 0000000..5aaf1b3 --- /dev/null +++ b/snap-client/src/hooks/use-storage.ts @@ -0,0 +1,33 @@ +import { useCallback, useMemo } from "react"; + +const createStorageHook = + (storage: Storage) => + ( + key: string, + defaultData?: T, + ): [NonNullable | null, (value: T) => void] => { + const setValue = useCallback( + (value: T) => { + storage.setItem(key, JSON.stringify(value)); + }, + [key], + ); + + const value = useMemo(() => { + const value = storage.getItem(key); + + if (defaultData) { + setValue(defaultData); + + return defaultData; + } + + return value ? JSON.parse(value) : value; + }, [key, defaultData, setValue]); + + return [value, setValue]; + }; + +export const useLocalStorage = createStorageHook(localStorage); + +export const useSessionStorage = createStorageHook(sessionStorage); diff --git a/snap-client/src/index.tsx b/snap-client/src/index.tsx index 2f8febf..54831f6 100644 --- a/snap-client/src/index.tsx +++ b/snap-client/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import ReactDOM from "react-dom/client"; import "./output.css"; +import "highlight.js/styles/atom-one-dark.css"; import App from "./app"; import reportWebVitals from "./reportWebVitals"; diff --git a/snap-client/src/input.css b/snap-client/src/input.css index a90f074..a704ceb 100644 --- a/snap-client/src/input.css +++ b/snap-client/src/input.css @@ -2,3 +2,109 @@ @tailwind components; @tailwind utilities; +html, body, #root { + height: 100%; + background-image: + linear-gradient(to right, rgba(36, 46, 54, 0.2) 2px, transparent 1px), + linear-gradient(to bottom, rgba(36, 46, 54, 0.2) 2px, transparent 1px); + background-size: 2.5rem 2.5rem; + background-position: center center; +} + +@layer components { + .rainbow-text { + background-image: linear-gradient(90deg,hsl(var(--s)) 4%,color-mix(in oklch, hsl(var(--sf)), hsl(163.22deg 80% 43%))); + -webkit-text-fill-color: transparent; + background-clip: text; + } + + .editor-shadow { + box-shadow: 0 20px 68px rgba(0, 0, 0, 0.55); + } + + .code * { + font-family: 'CaskaydiaCove Nerd Font'; + } + + .pacifico-regular { + font-family: "Pacifico", cursive; + font-weight: 400; + font-style: normal; + } + + .bg-stripe { + background: linear-gradient(to right, #1fa2ff, #12d8fa, #a6ffcb); + } + .bg-flare { + background: linear-gradient(to right, #f12711, #f5af19); + } + .bg-vanusa { + background: linear-gradient(to right, #da4453, #89216b); + } + .bg-sublime-light { + background: linear-gradient(to right, #fc5c7d, #6a82fb); + } + .bg-bighead { + background: linear-gradient(to right, #c94b4b, #4b134f); + } + .bg-velvet-sun { + background: linear-gradient(to right, #e1eec3, #f05053); + } + .bg-argon { + background: linear-gradient(to right, #03001e, #7303c0, #ec38bc, #fdeff9); + } + .bg-celestial { + background: linear-gradient(to right, #c33764, #1d2671); + } + .bg-relay { + background: linear-gradient(to right, #3a1c71, #d76d77, #ffaf7b); + } + .bg-crystal-clear { + background: linear-gradient(to right, #159957, #155799); + } + .bg-ibiza-sunset { + background: linear-gradient(to right, #ee0979, #ff6a00); + } + .bg-fresh-turboscent { + background: linear-gradient(to right, #f1f2b5, #135058); + } + .bg-cheer-up-emo-kid { + background: linear-gradient(to right, #556270, #ff6b6b); + } + .bg-starfall { + background: linear-gradient(to right, #f0c27b, #4b1248); + } + .bg-nelson { + background: linear-gradient(to right, #f2709c, #ff9472); + } + .bg-forever-lost { + background: linear-gradient(to right, #5d4157, #a8caba); + } + .bg-blurry-beach { + background: linear-gradient(to right, #d53369, #cbad6d); + } + .bg-influenza { + background: linear-gradient(to right, #c04848, #480048); + } + .bg-jshine { + background: linear-gradient(to right, #12c2e9, #c471ed, #f64f59); + } + .bg-calm-darya { + background: linear-gradient(to right, #5f2c82, #49a09d); + } + .bg-titanium { + background: linear-gradient(to right, #283048, #859398); + } + .bg-pinky { + background: linear-gradient(to right, #dd5e89, #f7bb97); + } + .bg-purple-paradise { + background: linear-gradient(to right, #1d2b64, #f8cdda); + } + .bg-horizon { + background: linear-gradient(to right, #003973, #e5e5be); + } + .bg-noon-to-dusk { + background: linear-gradient(to right, #ff6e7f, #bfe9ff); + } +} diff --git a/snap-client/tailwind.config.ts b/snap-client/tailwind.config.ts index 4f3d2f5..33f0af3 100644 --- a/snap-client/tailwind.config.ts +++ b/snap-client/tailwind.config.ts @@ -2,8 +2,19 @@ import type { Config } from "tailwindcss"; export default { content: ["./src/**/*.{js,jsx,ts,tsx}"], - theme: { - extend: {}, + plugins: [require("daisyui"), require("@tailwindcss/typography")], + daisyui: { + themes: ["dark"], + }, + theme: { + fontFamily: { + caskaydiacove: "CaskaydiaCove Nerd Font", + }, + extend: { + colors: { + "one-dark-base": "#282C34", + "border-color": "#545F64", + }, + }, }, - plugins: [], } satisfies Config; diff --git a/snap-server/src/event.rs b/snap-server/src/event.rs index 4a6294b..363b5bd 100644 --- a/snap-server/src/event.rs +++ b/snap-server/src/event.rs @@ -13,8 +13,11 @@ impl Event where T: Serialize, { - pub fn new(name: String, data: T) -> Event { - Event { name, data } + pub fn new(name: &str, data: T) -> Event { + Event { + name: name.to_string(), + data, + } } } diff --git a/snap-server/src/event_handler.rs b/snap-server/src/event_handler.rs index e206354..814a68f 100644 --- a/snap-server/src/event_handler.rs +++ b/snap-server/src/event_handler.rs @@ -1,18 +1,23 @@ -mod messages; +pub mod arguments; +pub mod config; +pub mod messages; pub mod neovim; use actix::{Actor, Addr, AsyncContext, Context}; +use arguments::parse_string_first; +pub use config::Config; pub use messages::Message; use neovim::Neovim; -use serde_json::json; +use serde_json::{json, Value}; use std::{ + any::Any, collections::HashMap, sync::{Arc, Mutex}, }; use crate::{ event::Event, - server::{ClientMessage, Server}, + server::{ClientMessage, ConfigSetupMessage, Server}, }; pub struct EventHandler { @@ -37,22 +42,20 @@ impl EventHandler { let receiver = self.neovim.lock().unwrap().create_receiver(); for (event_name, values) in receiver { + self.neovim.lock().unwrap().print(&event_name); + match Message::from(event_name.clone()) { Message::PreviewCode => self.server.do_send(ClientMessage { msg: Event::new( - "hello".to_string(), - serde_json::from_str::( - values - .iter() - .map(|value| value.to_string()) - .collect::>() - .first() - .unwrap(), - ) - .unwrap(), + "code", + serde_json::from_str::(parse_string_first(&values).as_str()) + .unwrap(), ) .into(), }), + Message::ConfigSetup => self.server.do_send(ConfigSetupMessage { + msg: parse_string_first(&values), + }), Message::Unknown => self .neovim .lock() diff --git a/snap-server/src/event_handler/arguments.rs b/snap-server/src/event_handler/arguments.rs new file mode 100644 index 0000000..bd69caf --- /dev/null +++ b/snap-server/src/event_handler/arguments.rs @@ -0,0 +1,9 @@ +use neovim_lib::Value; + +pub fn parse_string(values: &Vec) -> Vec { + values.iter().map(|value| value.to_string()).collect() +} + +pub fn parse_string_first(values: &Vec) -> String { + parse_string(values).first().unwrap().to_string() +} diff --git a/snap-server/src/event_handler/config.rs b/snap-server/src/event_handler/config.rs new file mode 100644 index 0000000..53dc89d --- /dev/null +++ b/snap-server/src/event_handler/config.rs @@ -0,0 +1,17 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Debug, Deserialize, Clone)] +pub struct Config { + breadcrumbs: bool, + column_number: bool, + mac_window_bar: bool, + opacity: bool, + watermark: Option, + auto_load: bool, +} + +impl From<&str> for Config { + fn from(value: &str) -> Self { + return serde_json::from_str(value).unwrap(); + } +} diff --git a/snap-server/src/event_handler/messages.rs b/snap-server/src/event_handler/messages.rs index 2c777ec..d4cc366 100644 --- a/snap-server/src/event_handler/messages.rs +++ b/snap-server/src/event_handler/messages.rs @@ -1,6 +1,7 @@ #[derive(PartialEq, Hash)] pub enum Message { PreviewCode, + ConfigSetup, Unknown, } @@ -10,6 +11,7 @@ impl From for Message { fn from(value: String) -> Self { match value.as_str() { "preview_code" => Message::PreviewCode, + "config_setup" => Message::ConfigSetup, _ => Message::Unknown, } } diff --git a/snap-server/src/main.rs b/snap-server/src/main.rs index 6bbdda5..ccb0c57 100644 --- a/snap-server/src/main.rs +++ b/snap-server/src/main.rs @@ -11,7 +11,7 @@ use actix_web::{ App, Error, HttpRequest, HttpResponse, HttpServer, }; use actix_web_actors::ws; -use event_handler::neovim::Neovim; +use event_handler::{neovim::Neovim, Config}; use event_handler::{EventHandler, Message}; use server::Server; use session::Session; @@ -43,3 +43,21 @@ async fn main() -> std::io::Result<()> { .run() .await } + +// fn main() { +// let data = r#" +// { +// "breadcrumbs":true, +// "watermark":"CodeSnap.nvim", +// "mac_window_bar":true, +// "column_number":true, +// "auto_load":true, +// "background":{ +// "grandient":true +// } +// }"#; +// +// let config: Config = serde_json::from_str(data).unwrap(); +// +// println!("{:?}", config) +// } diff --git a/snap-server/src/server.rs b/snap-server/src/server.rs index d6aa879..f080c17 100644 --- a/snap-server/src/server.rs +++ b/snap-server/src/server.rs @@ -1,11 +1,15 @@ use actix::{Actor, Context, Handler, Message, Recipient}; use rand::{rngs::ThreadRng, Rng}; +use serde::Serialize; use std::{ collections::HashMap, sync::{Arc, Mutex}, }; -use crate::event_handler::neovim::Neovim; +use crate::{ + event::Event, + event_handler::{neovim::Neovim, Config}, +}; type SessionID = usize; @@ -31,10 +35,17 @@ pub struct ClientMessage { pub msg: String, } +#[derive(Message)] +#[rtype(result = "()")] +pub struct ConfigSetupMessage { + pub msg: String, +} + pub struct Server { rng: ThreadRng, sessions: HashMap>, neovim: Arc>, + config: Option, } impl Server { @@ -43,6 +54,7 @@ impl Server { rng: rand::thread_rng(), sessions: HashMap::new(), neovim, + config: None, } } @@ -51,6 +63,14 @@ impl Server { session.do_send(ServerMessage(message.to_string())) } } + + fn send_event_to_clients(&self, event: Event) + where + T: Serialize, + { + let stringify_event: String = event.into(); + self.send_message_to_clients(stringify_event.as_str()) + } } impl Actor for Server { @@ -65,6 +85,10 @@ impl Handler for Server { self.sessions.insert(id, msg.addr); + if let Some(config) = &self.config { + self.send_event_to_clients(Event::new("config_setup", config)); + } + id } } @@ -84,3 +108,14 @@ impl Handler for Server { self.send_message_to_clients(&msg.msg) } } + +impl Handler for Server { + type Result = (); + + fn handle(&mut self, msg: ConfigSetupMessage, _: &mut Self::Context) -> Self::Result { + let config = Config::from(msg.msg.as_str()); + + self.config = Some(config.clone()); + self.send_event_to_clients(Event::new("config_setup", config)); + } +}