From 8b633986debfa3a5f9a70afec9d4f2930f56f9a4 Mon Sep 17 00:00:00 2001 From: keith Date: Sun, 15 Dec 2019 00:31:25 -0800 Subject: [PATCH] Shaper fully working and cached to preserve performance to some extent --- Cargo.lock | 133 +++++++++++++++++++++ Cargo.toml | 1 + src/editor.rs | 10 +- src/events.rs | 13 ++- src/keybindings.rs | 4 +- src/main.rs | 7 +- src/window.rs | 279 +++++++++++++++++++++++++++------------------ 7 files changed, 323 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4647c38..f253000 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,14 @@ name = "adler32" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ahash" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "const-random 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "aho-corasick" version = "0.7.6" @@ -112,6 +120,14 @@ name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "c2-chacha" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "calloop" version = "0.4.4" @@ -186,6 +202,24 @@ dependencies = [ "objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "const-random" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "const-random-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "const-random-macro" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "core-foundation" version = "0.6.4" @@ -348,11 +382,30 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "getrandom" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "hashbrown" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ahash 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "heck" version = "0.3.1" @@ -455,6 +508,14 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lru" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hashbrown 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -550,6 +611,7 @@ version = "0.1.0" dependencies = [ "derive-new 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lru 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "neovim-lib 0.6.0 (git+https://github.com/daa84/neovim-lib)", "rmpv 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "skulpin 0.3.0", @@ -683,6 +745,21 @@ name = "pkg-config" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro-hack" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "0.4.30" @@ -720,6 +797,43 @@ dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "raw-window-handle" version = "0.3.3" @@ -1062,6 +1176,11 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "wayland-client" version = "0.23.6" @@ -1238,6 +1357,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" +"checksum ahash 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6f33b5018f120946c1dcf279194f238a9f146725593ead1c08fa47ff22b0b5d3" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum andrew 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e" "checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" @@ -1251,6 +1371,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum calloop 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160" "checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" "checksum cexpr 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d" @@ -1259,6 +1380,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cocoa 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400" +"checksum const-random 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b641a8c9867e341f3295564203b1c250eb8ce6cb6126e007941f78c4d2ed7fe" +"checksum const-random-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c750ec12b83377637110d5a57f5ae08e895b06c4b16e2bdbf1a94ef717428c59" "checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" @@ -1277,7 +1400,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +"checksum hashbrown 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum instant 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6c346c299e3fe8ef94dc10c2c0253d858a69aac1245157a3bf4125915d528caf" @@ -1292,6 +1417,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" "checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum lru 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0609345ddee5badacf857d4f547e0e5a2e987db77085c24cd887f73573a04237" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" @@ -1316,11 +1442,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" @@ -1363,6 +1495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" "checksum wayland-client 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda" "checksum wayland-commons 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb" "checksum wayland-protocols 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9" diff --git a/Cargo.toml b/Cargo.toml index 86cca2d..6816f33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ authors = ["keith "] edition = "2018" [dependencies] +lru = "0.4.3" skulpin = { path = "c:/dev/Projects/skulpin" } derive-new = "0.5" env_logger = "0.7.1" diff --git a/src/editor.rs b/src/editor.rs index d681c56..5bb66ab 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -66,8 +66,7 @@ pub type GridCell = Option<(char, Style)>; #[derive(new, Debug, Clone)] pub struct DrawCommand { pub text: String, - pub row: u64, - pub col_start: u64, + pub grid_position: (u64, u64), pub style: Style } @@ -90,7 +89,6 @@ impl CursorType { } pub struct Editor { - pub nvim: Neovim, pub grid: Vec>, pub cursor_pos: (u64, u64), pub cursor_type: CursorType, @@ -104,9 +102,8 @@ pub struct Editor { } impl Editor { - pub fn new(nvim: Neovim, width: u64, height: u64) -> Editor { + pub fn new(width: u64, height: u64) -> Editor { let mut editor = Editor { - nvim, grid: Vec::new(), cursor_pos: (0, 0), cursor_type: CursorType::Block, @@ -160,7 +157,7 @@ impl Editor { match command { Some(command) => command.text.push(character.clone()), None => { - command.replace(DrawCommand::new(character.to_string(), row_index, col_index, style)); + command.replace(DrawCommand::new(character.to_string(), (col_index, row_index), style)); } } } @@ -222,7 +219,6 @@ impl Editor { } pub fn resize(&mut self, new_width: u64, new_height: u64) { - self.nvim.ui_try_resize(new_width as i64, new_height as i64).expect("Resize failed"); self.size = (new_width, new_height); } diff --git a/src/events.rs b/src/events.rs index 03e31cb..41788e2 100644 --- a/src/events.rs +++ b/src/events.rs @@ -150,6 +150,16 @@ fn parse_mode_change(mode_change_arguments: Vec) -> Result { } } +fn parse_grid_resize(grid_resize_arguments: Vec) -> Result { + if let [grid_id, width, height] = grid_resize_arguments.as_slice() { + Ok(RedrawEvent::Resize { + grid: parse_u64(&grid_id)?, width: parse_u64(&width)?, height: parse_u64(&height)? + }) + } else { + Err(EventParseError::InvalidEventFormat) + } +} + fn parse_default_colors(default_colors_arguments: Vec) -> Result { if let [ foreground, background, special, _term_foreground, _term_background @@ -247,7 +257,7 @@ fn parse_grid_scroll(grid_scroll_arguments: Vec) -> Result { } pub fn parse_redraw_event(event_value: Value) -> Result> { - let mut event_contents = parse_array(&event_value)?.to_vec(); + let event_contents = parse_array(&event_value)?.to_vec(); let name_value = event_contents.get(0).ok_or(EventParseError::InvalidEventFormat)?; let event_name = parse_string(&name_value)?; let events = event_contents; @@ -263,6 +273,7 @@ pub fn parse_redraw_event(event_value: Value) -> Result> { "mode_change" => Some(parse_mode_change(event_parameters)?), "busy_start" => Some(RedrawEvent::BusyStart), "busy_stop" => Some(RedrawEvent::BusyStop), + "grid_resize" => Some(parse_grid_resize(event_parameters)?), "default_colors_set" => Some(parse_default_colors(event_parameters)?), "hl_attr_define" => Some(parse_hl_attr_define(event_parameters)?), "grid_line" => Some(parse_grid_line(event_parameters)?), diff --git a/src/keybindings.rs b/src/keybindings.rs index 4c99914..924e8a7 100644 --- a/src/keybindings.rs +++ b/src/keybindings.rs @@ -1,5 +1,3 @@ -use std::fmt; - use skulpin::winit::event::{KeyboardInput, ElementState, ModifiersState, VirtualKeyCode}; fn parse_keycode(keycode: VirtualKeyCode) -> Option<(String, bool)> { @@ -126,7 +124,7 @@ fn append_modifiers(modifiers: ModifiersState, keycode_text: String, special: bo "/" => "?".to_string(), other => { special = true; - format!("S-{}", result) + format!("S-{}", other) } }; } diff --git a/src/main.rs b/src/main.rs index 5c8f62f..026d276 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,7 @@ mod events; mod window; mod keybindings; -#[macro_use] -extern crate derive_new; +#[macro_use] extern crate derive_new; use std::panic; use std::process::{Command, Stdio, exit}; @@ -69,12 +68,12 @@ fn main() { options.set_rgb(true); nvim.ui_attach(INITIAL_WIDTH as i64, INITIAL_HEIGHT as i64, &options).unwrap(); - let editor = Arc::new(Mutex::new(Editor::new(nvim, INITIAL_WIDTH, INITIAL_HEIGHT))); + let editor = Arc::new(Mutex::new(Editor::new(INITIAL_WIDTH, INITIAL_HEIGHT))); let nvim_editor = editor.clone(); thread::spawn(move || { nvim_event_loop(receiver, &nvim_editor); }); - ui_loop(editor); + ui_loop(editor, nvim, (INITIAL_WIDTH, INITIAL_HEIGHT)); } diff --git a/src/window.rs b/src/window.rs index 8f60e3c..bf61f8d 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,125 +1,189 @@ +use std::borrow::Cow; use std::sync::{Arc, Mutex}; -use std::any::Any; +use std::time::{Duration, Instant}; -use skulpin::{CoordinateSystem, CoordinateSystemHelper, RendererBuilder}; -use skulpin::skia_safe::{Canvas, colors, Color4f, Font, FontStyle, Point, Paint, Rect, Shaper, Typeface}; -use skulpin::skia_safe::paint::Style; -use skulpin::skia_safe::matrix::ScaleToFit; +use lru::LruCache; + +use skulpin::{CoordinateSystem, RendererBuilder}; +use skulpin::skia_safe::{Canvas, colors, Font, FontStyle, Paint, Point, Rect, Shaper, TextBlob, Typeface}; use skulpin::skia_safe::icu; -use skulpin::winit::dpi::{LogicalSize, LogicalPosition}; -use skulpin::winit::event::{ElementState, Event, MouseScrollDelta, KeyboardInput, VirtualKeyCode, WindowEvent}; +use skulpin::winit::dpi::LogicalSize; +use skulpin::winit::event::{ElementState, Event, MouseScrollDelta, WindowEvent}; use skulpin::winit::event_loop::{ControlFlow, EventLoop}; use skulpin::winit::window::WindowBuilder; -use neovim_lib::NeovimApi; +use neovim_lib::{Neovim, NeovimApi}; -use crate::editor::{DrawCommand, Editor, Colors, CursorType}; +use crate::editor::{Editor, CursorType, Style, Colors}; use crate::keybindings::construct_keybinding_string; const FONT_NAME: &str = "Delugia Nerd Font"; const FONT_SIZE: f32 = 14.0; -fn draw( - editor: &Arc>, - canvas: &mut Canvas, - cursor_pos: &mut (f32, f32), - shaper: &Shaper, - paint: &mut Paint, - font: &Font, +struct CachingShaper { + shaper: Shaper, + cache: LruCache +} + +impl CachingShaper { + pub fn new() -> CachingShaper { + CachingShaper { + shaper: Shaper::new(None), + cache: LruCache::new(1000) + } + } + + pub fn shape(&self, text: &str, font: &Font) -> TextBlob { + let (blob, _) = self.shaper.shape_text_blob(text, font, true, 1000.0, Point::default()).unwrap(); + blob + } + + pub fn shape_cached(&mut self, text: String, font: &Font) -> &TextBlob { + if !self.cache.contains(&text) { + self.cache.put(text.clone(), self.shape(&text, &font)); + } + + self.cache.get(&text).unwrap() + } +} + +struct Renderer { + editor: Arc>, + + paint: Paint, + font: Font, + shaper: CachingShaper, + font_width: f32, - font_height: f32 -) { - let (draw_commands, default_colors, cursor_grid_pos, cursor_type, cursor_foreground, cursor_background, cursor_enabled) = { - let editor = editor.lock().unwrap(); - ( - editor.build_draw_commands().clone(), - editor.default_colors.clone(), - editor.cursor_pos.clone(), - editor.cursor_type.clone(), - editor.cursor_foreground(), - editor.cursor_background(), - editor.cursor_enabled - ) - }; - - canvas.clear(default_colors.background.clone().unwrap().to_color()); - - for command in draw_commands { - let x = command.col_start as f32 * font_width; - let y = command.row as f32 * font_height + font_height - font_height * 0.2; - let top = y - font_height * 0.8; - let width = command.text.chars().count() as f32 * font_width; - let height = font_height; + font_height: f32, + cursor_pos: (f32, f32), + + previous_frame_instant: Instant +} + +impl Renderer { + pub fn new(editor: Arc>) -> Renderer { + let paint = Paint::new(colors::WHITE, None); + let typeface = Typeface::new(FONT_NAME, FontStyle::default()).expect("Could not load font file."); + let font = Font::from_typeface(typeface, FONT_SIZE); + let shaper = CachingShaper::new(); + + let (_, bounds) = font.measure_str("0", Some(&paint)); + let font_width = bounds.width(); + + let (_, metrics) = font.metrics(); + let font_height = metrics.descent - metrics.ascent; // bounds.height() * 1.68; + let cursor_pos = (0.0, 0.0); + + let previous_frame_instant = Instant::now(); + + Renderer { editor, paint, font, shaper, font_width, font_height, cursor_pos, previous_frame_instant } + } + + fn draw_text(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), style: &Style, default_colors: &Colors, update_cache: bool) { + let (grid_x, grid_y) = grid_pos; + let x = grid_x as f32 * self.font_width; + let y = grid_y as f32 * self.font_height + self.font_height - self.font_height * 0.2; + let top = y - self.font_height * 0.8; + let width = text.chars().count() as f32 * self.font_width; + let height = self.font_height; let region = Rect::new(x, top, x + width, top + height); - paint.set_color(command.style.background(&default_colors).to_color()); - canvas.draw_rect(region, &paint); + self.paint.set_color(style.background(default_colors).to_color()); + canvas.draw_rect(region, &self.paint); - if command.style.underline || command.style.undercurl { - let (_, metrics) = font.metrics(); - let width = command.text.chars().count() as f32 * font_width; + if style.underline || style.undercurl { + let (_, metrics) = self.font.metrics(); + let width = text.chars().count() as f32 * self.font_width; let underline_position = metrics.underline_position().unwrap(); - paint.set_color(command.style.special(&default_colors).to_color()); - canvas.draw_line((x, y + underline_position), (x + width, y + underline_position), &paint); + self.paint.set_color(style.special(&default_colors).to_color()); + canvas.draw_line((x, y + underline_position), (x + width, y + underline_position), &self.paint); } - paint.set_color(command.style.foreground(&default_colors).to_color()); - let text = command.text.trim_end(); - canvas.draw_str(text, (x, y), &font, &paint); - // if text.len() > 0 { - // if let Some((blob, _)) = shaper.shape_text_blob(&text, font, false, 10000.0, Point::default()) { - // canvas.draw_text_blob(&blob, (x, top), &paint); - // } - // } - + self.paint.set_color(style.foreground(&default_colors).to_color()); + let text = text.trim_end(); + + //canvas.draw_str(text, (x, y), &font, &paint); + if text.len() > 0 { + let reference; + let blob = if update_cache { + self.shaper.shape_cached(text.to_string(), &self.font) + } else { + reference = self.shaper.shape(text, &self.font); + &reference + }; + canvas.draw_text_blob(blob, (x, top), &self.paint); + } } - let (cursor_grid_x, cursor_grid_y) = cursor_grid_pos; - let target_cursor_x = cursor_grid_x as f32 * font_width; - let target_cursor_y = cursor_grid_y as f32 * font_height; - let (previous_cursor_x, previous_cursor_y) = cursor_pos; + pub fn draw(&mut self, canvas: &mut Canvas) { + let (draw_commands, default_colors, cursor_grid_pos, cursor_type, cursor_foreground, cursor_background, cursor_enabled) = { + let editor = self.editor.lock().unwrap(); + ( + editor.build_draw_commands().clone(), + editor.default_colors.clone(), + editor.cursor_pos.clone(), + editor.cursor_type.clone(), + editor.cursor_foreground(), + editor.cursor_background(), + editor.cursor_enabled + ) + }; - let cursor_x = (target_cursor_x - *previous_cursor_x) * 0.5 + *previous_cursor_x; - let cursor_y = (target_cursor_y - *previous_cursor_y) * 0.5 + *previous_cursor_y; + canvas.clear(default_colors.background.clone().unwrap().to_color()); - *cursor_pos = (cursor_x, cursor_y); - if cursor_enabled { - let cursor_width = match cursor_type { - CursorType::Vertical => font_width / 8.0, - CursorType::Horizontal | CursorType::Block => font_width - }; - let cursor_height = match cursor_type { - CursorType::Horizontal => font_width / 8.0, - CursorType::Vertical | CursorType::Block => font_height - }; - let cursor = Rect::new(cursor_x, cursor_y, cursor_x + cursor_width, cursor_y + cursor_height); - paint.set_color(cursor_background.to_color()); - canvas.draw_rect(cursor, &paint); - - if let CursorType::Block = cursor_type { - paint.set_color(cursor_foreground.to_color()); - let editor = editor.lock().unwrap(); - let character = editor.grid[cursor_grid_y as usize][cursor_grid_x as usize].clone() - .map(|(character, _)| character) - .unwrap_or(' '); - let text_y = cursor_y + font_height - font_height * 0.2; - canvas.draw_str(character.to_string(), (cursor_x, text_y), &font, &paint); + for command in draw_commands { + self.draw_text(canvas, &command.text, command.grid_position, &command.style, &default_colors, true); } - } -} -pub fn ui_loop(editor: Arc>) { - let shaper = Shaper::new(None); - let typeface = Typeface::new(FONT_NAME, FontStyle::default()).expect("Could not load font file."); - let font = Font::from_typeface(typeface, FONT_SIZE); - let mut paint = Paint::new(colors::WHITE, None); + let (cursor_grid_x, cursor_grid_y) = cursor_grid_pos; + let target_cursor_x = cursor_grid_x as f32 * self.font_width; + let target_cursor_y = cursor_grid_y as f32 * self.font_height; + let (previous_cursor_x, previous_cursor_y) = self.cursor_pos; + + let cursor_x = (target_cursor_x - previous_cursor_x) * 0.5 + previous_cursor_x; + let cursor_y = (target_cursor_y - previous_cursor_y) * 0.5 + previous_cursor_y; - let (width, bounds) = font.measure_str("0", Some(&paint)); - let font_width = width; - let font_height = bounds.height() * 1.68; + self.cursor_pos = (cursor_x, cursor_y); + if cursor_enabled { + let cursor_width = match cursor_type { + CursorType::Vertical => self.font_width / 8.0, + CursorType::Horizontal | CursorType::Block => self.font_width + }; + let cursor_height = match cursor_type { + CursorType::Horizontal => self.font_width / 8.0, + CursorType::Vertical | CursorType::Block => self.font_height + }; + let cursor = Rect::new(cursor_x, cursor_y, cursor_x + cursor_width, cursor_y + cursor_height); + self.paint.set_color(cursor_background.to_color()); + canvas.draw_rect(cursor, &self.paint); + if let CursorType::Block = cursor_type { + self.paint.set_color(cursor_foreground.to_color()); + let editor = self.editor.lock().unwrap(); + let character = editor.grid[cursor_grid_y as usize][cursor_grid_x as usize].clone() + .map(|(character, _)| character) + .unwrap_or(' '); + let text_y = cursor_y + self.font_height - self.font_height * 0.2; + canvas.draw_text_blob( + self.shaper.shape_cached(character.to_string(), &self.font), + (cursor_x, text_y), &self.paint); + } + } + } +} + +pub fn ui_loop(editor: Arc>, nvim: Neovim, initial_size: (u64, u64)) { + let mut nvim = nvim; + let mut renderer = Renderer::new(editor); let event_loop = EventLoop::<()>::with_user_event(); - let logical_size = LogicalSize::new((100.0 * font_width) as f64, (50.0 * font_height) as f64); + + let (width, height) = initial_size; + let logical_size = LogicalSize::new( + (width as f32 * renderer.font_width) as f64, + // Add 1.0 here to make sure resizing horizontally doesn't change the grid height + (height as f32 * renderer.font_height + 1.0) as f64 + ); let window = WindowBuilder::new() .with_title("Neovide") @@ -127,13 +191,11 @@ pub fn ui_loop(editor: Arc>) { .build(&event_loop) .expect("Failed to create window"); - let mut renderer = RendererBuilder::new() + let mut skulpin_renderer = RendererBuilder::new() .coordinate_system(CoordinateSystem::Logical) - .prefer_mailbox_present_mode() .build(&window) .expect("Failed to create renderer"); - let mut cursor_pos = (0.0, 0.0); let mut mouse_down = false; let mut mouse_pos = (0, 0); @@ -151,10 +213,9 @@ pub fn ui_loop(editor: Arc>) { .. } => { if new_size.width > 0.0 && new_size.height > 0.0 { - editor.lock().unwrap().resize( - (new_size.width as f32 / font_width) as u64, - (new_size.height as f32 / font_height) as u64 - ) + let new_width = (new_size.width as f32 / renderer.font_width) as u64; + let new_height = (new_size.height as f32 / renderer.font_height) as u64; + nvim.ui_try_resize(new_width as i64, new_height as i64).expect("Resize failed"); } }, @@ -166,7 +227,7 @@ pub fn ui_loop(editor: Arc>) { .. } => { if let Some(string) = construct_keybinding_string(input) { - editor.lock().unwrap().nvim.input(&string).expect("Input call failed..."); + nvim.input(&string).expect("Input call failed..."); } }, @@ -177,11 +238,11 @@ pub fn ui_loop(editor: Arc>) { }, .. } => { - let grid_x = (position.x as f32 / font_width) as i64; - let grid_y = (position.y as f32 / font_height) as i64; + let grid_x = (position.x as f32 / renderer.font_width) as i64; + let grid_y = (position.y as f32 / renderer.font_height) as i64; mouse_pos = (grid_x, grid_y); if mouse_down { - editor.lock().unwrap().nvim.input_mouse("left", "drag", "", 0, grid_y, grid_x); + nvim.input_mouse("left", "drag", "", 0, grid_y, grid_x).expect("Could not send mouse input"); } } @@ -203,7 +264,7 @@ pub fn ui_loop(editor: Arc>) { } }; let (grid_x, grid_y) = mouse_pos; - editor.lock().unwrap().nvim.input_mouse("left", input_type, "", 0, grid_y, grid_x); + nvim.input_mouse("left", input_type, "", 0, grid_y, grid_x).expect("Could not send mouse input"); } Event::WindowEvent { @@ -219,7 +280,7 @@ pub fn ui_loop(editor: Arc>) { "down" }; let (grid_x, grid_y) = mouse_pos; - editor.lock().unwrap().nvim.input_mouse("wheel", input_type, "", 0, grid_y, grid_x); + nvim.input_mouse("wheel", input_type, "", 0, grid_y, grid_x).expect("Could not send mouse input"); } Event::EventsCleared => { @@ -230,8 +291,8 @@ pub fn ui_loop(editor: Arc>) { event: WindowEvent::RedrawRequested, .. } => { - if let Err(e) = renderer.draw(&window, |canvas, _coordinate_system_helper| { - draw(&editor, canvas, &mut cursor_pos, &shaper, &mut paint, &font, font_width, font_height); + if let Err(e) = skulpin_renderer.draw(&window, |canvas, _coordinate_system_helper| { + renderer.draw(canvas); }) { println!("Error during draw: {:?}", e); *control_flow = ControlFlow::Exit