From 448c1abba04e11f77e53629dc06fe47619a741d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Wed, 3 Feb 2021 19:36:54 +0900 Subject: [PATCH] View tree implementation: render multiple split views. Cursors are still a bit buggy and we should render in focus statusbar differently than in the other pane. --- Cargo.lock | 166 +++++++++++++++++++--------------- helix-term/src/application.rs | 19 ++-- helix-term/src/commands.rs | 111 +++++++++++------------ helix-term/src/ui/editor.rs | 50 ++++++---- helix-term/src/ui/mod.rs | 56 ++++++------ helix-view/Cargo.toml | 2 + helix-view/src/editor.rs | 34 +++---- helix-view/src/lib.rs | 1 + helix-view/src/view.rs | 10 +- 9 files changed, 240 insertions(+), 209 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc0d9e5a4..eb38e755e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,9 +11,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" [[package]] name = "async-channel" @@ -321,9 +321,9 @@ dependencies = [ [[package]] name = "dirs-sys-next" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99de365f605554ae33f115102a02057d4fc18b01f3284d6870be0938743cfe7d" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", @@ -388,9 +388,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70be434c505aee38639abccb918163b63158a4b4bb791b45b7023044bdc3c9c" +checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150" dependencies = [ "futures-channel", "futures-core", @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f01c61843314e95f96cc9245702248733a3a3d744e43e2e755e3c7af8348a0a9" +checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" dependencies = [ "futures-core", "futures-sink", @@ -413,15 +413,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8d3b0917ff63a2a96173133c02818fac4a746b0a57569d3baca9ec0e945e08" +checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" [[package]] name = "futures-executor" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee9ca2f7eb4475772cf39dd1cd06208dce2670ad38f4d9c7262b3e15f127068" +checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" dependencies = [ "futures-core", "futures-task", @@ -430,9 +430,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37c1a51b037b80922864b8eed90692c5cd8abd4c71ce49b77146caa47f3253b" +checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" [[package]] name = "futures-lite" @@ -445,15 +445,15 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.1", + "pin-project-lite 0.2.4", "waker-fn", ] [[package]] name = "futures-macro" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8719ca0e1f3c5e34f3efe4570ef2c0610ca6da85ae7990d472e9cbfba13664" +checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -463,24 +463,24 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6adabac1290109cfa089f79192fb6244ad2c3f1cc2281f3e1dd987592b71feb" +checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" [[package]] name = "futures-task" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92a0843a2ff66823a8f7c77bffe9a09be2b64e533562c412d63075643ec0038" +checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" dependencies = [ "once_cell", ] [[package]] name = "futures-util" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "036a2107cdeb57f6d7322f1b6c363dad67cd63ca3b7d1b925bdf75bd5d96cda9" +checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" dependencies = [ "futures-channel", "futures-core", @@ -489,7 +489,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.1", + "pin-project-lite 0.2.4", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -507,13 +507,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.16" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -621,6 +621,7 @@ dependencies = [ "helix-core", "helix-lsp", "once_cell", + "slotmap", "smol", "tui", "url", @@ -628,9 +629,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] @@ -719,9 +720,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.82" +version = "0.2.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" [[package]] name = "lock_api" @@ -734,11 +735,11 @@ dependencies = [ [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", ] [[package]] @@ -897,7 +898,7 @@ dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall", + "redox_syscall 0.1.57", "smallvec", "winapi", ] @@ -922,9 +923,9 @@ checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" [[package]] name = "pin-project-lite" -version = "0.2.1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36743d754ccdf9954c2e352ce2d4b106e024c814f6499c2dadff80da9a442d8" +checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" [[package]] name = "pin-utils" @@ -953,9 +954,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro-nested" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" @@ -1007,20 +1008,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] -name = "redox_users" -version = "0.3.5" +name = "redox_syscall" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.4", ] [[package]] name = "regex" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" +checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" dependencies = [ "aho-corasick", "memchr", @@ -1030,9 +1040,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.21" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" +checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" [[package]] name = "ropey" @@ -1066,18 +1076,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.118" +version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" dependencies = [ "proc-macro2", "quote", @@ -1142,10 +1152,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] -name = "smallvec" -version = "1.6.0" +name = "slotmap" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0" +checksum = "ab3003725ae562cf995f3dc82bb99e70926e09000396816765bb6d7adbe740b1" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "smol" @@ -1188,9 +1207,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.58" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" dependencies = [ "proc-macro2", "quote", @@ -1199,8 +1218,8 @@ dependencies = [ [[package]] name = "tendril" -version = "0.4.1" -source = "git+https://github.com/servo/tendril#9532724c32a0bf5e65acb56209373d97223bc530" +version = "0.4.2" +source = "git+https://github.com/servo/tendril#548cfaab79a3db13f350621d5b18a81d351463ba" dependencies = [ "futf", "mac", @@ -1238,29 +1257,28 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" +checksum = "d8208a331e1cb318dd5bd76951d2b8fc48ca38a69f5f4e4af1b6a9f8c6236915" dependencies = [ - "lazy_static", + "once_cell", ] [[package]] name = "time" -version = "0.1.44" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ "libc", - "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] [[package]] name = "tinyvec" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" dependencies = [ "tinyvec_macros", ] @@ -1360,6 +1378,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + [[package]] name = "waker-fn" version = "1.1.0" @@ -1379,15 +1403,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wepoll-sys" diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index f32db3b3c..6e0005345 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -39,11 +39,12 @@ impl Application { pub fn new(mut args: Args, executor: &'static smol::Executor<'static>) -> Result { let backend = CrosstermBackend::new(stdout()); let mut terminal = Terminal::new(backend)?; - let mut editor = Editor::new(); let size = terminal.size()?; + let mut editor = Editor::new(size); - if let Some(file) = args.values_of_t::("files").unwrap().pop() { - editor.open(file, (size.width, size.height), executor)?; + let files = args.values_of_t::("files").unwrap(); + for file in files { + editor.open(file, executor)?; } let mut compositor = Compositor::new(); @@ -132,11 +133,13 @@ pub async fn handle_language_server_message(&mut self, call: Option { let path = Some(params.uri.to_file_path().unwrap()); - let view = self - .editor - .views - .iter_mut() - .find(|view| view.doc.path == path); + let view: Option<&mut View> = None; + // TODO + // let view = self + // .editor + // .views + // .iter_mut() + // .find(|view| view.doc.path == path); if let Some(view) = view { let doc = view.doc.text().slice(..); diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index ff8704d8e..be43159d4 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -183,7 +183,7 @@ pub fn check_cursor_in_view(view: &View) -> bool { let doc = &view.doc; let cursor = doc.selection().cursor(); let line = doc.text().char_to_line(cursor); - let document_end = view.first_line + view.size.1.saturating_sub(1) as usize; + let document_end = view.first_line + view.area.height.saturating_sub(1) as usize; if (line > document_end.saturating_sub(PADDING)) | (line < view.first_line + PADDING) { return false; @@ -197,7 +197,7 @@ pub fn page_up(cx: &mut Context) { return; } - view.first_line = view.first_line.saturating_sub(view.size.1 as usize); + view.first_line = view.first_line.saturating_sub(view.area.height as usize); if !check_cursor_in_view(view) { let text = view.doc.text(); @@ -208,7 +208,7 @@ pub fn page_up(cx: &mut Context) { pub fn page_down(cx: &mut Context) { let view = cx.view(); - view.first_line += view.size.1 as usize + PADDING; + view.first_line += view.area.height as usize + PADDING; if view.first_line < view.doc.text().len_lines() { let text = view.doc.text(); @@ -223,7 +223,9 @@ pub fn half_page_up(cx: &mut Context) { return; } - view.first_line = view.first_line.saturating_sub(view.size.1 as usize / 2); + view.first_line = view + .first_line + .saturating_sub(view.area.height as usize / 2); if !check_cursor_in_view(view) { let text = &view.doc.text(); @@ -235,8 +237,8 @@ pub fn half_page_up(cx: &mut Context) { pub fn half_page_down(cx: &mut Context) { let view = cx.view(); let lines = view.doc.text().len_lines(); - if view.first_line < lines.saturating_sub(view.size.1 as usize) { - view.first_line += view.size.1 as usize / 2; + if view.first_line < lines.saturating_sub(view.area.height as usize) { + view.first_line += view.area.height as usize / 2; } if !check_cursor_in_view(view) { let text = view.doc.text(); @@ -367,8 +369,7 @@ pub fn change_selection(cx: &mut Context) { pub fn collapse_selection(cx: &mut Context) { let selection = cx - .view() - .doc + .doc() .selection() .transform(|range| Range::new(range.head, range.head)); @@ -377,8 +378,7 @@ pub fn collapse_selection(cx: &mut Context) { pub fn flip_selections(cx: &mut Context) { let selection = cx - .view() - .doc + .doc() .selection() .transform(|range| Range::new(range.head, range.anchor)); @@ -396,8 +396,7 @@ pub fn insert_mode(cx: &mut Context) { enter_insert_mode(cx); let selection = cx - .view() - .doc + .doc() .selection() .transform(|range| Range::new(range.to(), range.from())); cx.doc().set_selection(selection); @@ -431,37 +430,40 @@ pub fn command_mode(cx: &mut Context) { |_input: &str| { // TODO: i need this duplicate list right now to avoid borrow checker issues let command_list = vec![ - String::from("q"), - String::from("aaa"), - String::from("bbb"), - String::from("ccc"), - String::from("ddd"), - String::from("eee"), - String::from("averylongcommandaverylongcommandaverylongcommandaverylongcommandaverylongcommand"), - String::from("q"), - String::from("aaa"), - String::from("bbb"), - String::from("ccc"), - String::from("ddd"), - String::from("eee"), - String::from("q"), - String::from("aaa"), - String::from("bbb"), - String::from("ccc"), - String::from("ddd"), - String::from("eee"), - String::from("q"), - String::from("aaa"), - String::from("bbb"), - String::from("ccc"), - String::from("ddd"), - String::from("eee"), - String::from("q"), - String::from("aaa"), - String::from("bbb"), - String::from("ccc"), - String::from("ddd"), - String::from("eee"), + "q".to_string(), + "o".to_string(), + "w".to_string(), + // String::from("q"), + // String::from("aaa"), + // String::from("bbb"), + // String::from("ccc"), + // String::from("ddd"), + // String::from("eee"), + // String::from("averylongcommandaverylongcommandaverylongcommandaverylongcommandaverylongcommand"), + // String::from("q"), + // String::from("aaa"), + // String::from("bbb"), + // String::from("ccc"), + // String::from("ddd"), + // String::from("eee"), + // String::from("q"), + // String::from("aaa"), + // String::from("bbb"), + // String::from("ccc"), + // String::from("ddd"), + // String::from("eee"), + // String::from("q"), + // String::from("aaa"), + // String::from("bbb"), + // String::from("ccc"), + // String::from("ddd"), + // String::from("eee"), + // String::from("q"), + // String::from("aaa"), + // String::from("bbb"), + // String::from("ccc"), + // String::from("ddd"), + // String::from("eee"), ]; command_list .into_iter() @@ -478,8 +480,7 @@ pub fn command_mode(cx: &mut Context) { match *parts.as_slice() { ["q"] => editor.should_close = true, ["o", path] => { - let size = editor.view().size; - editor.open(path.into(), size, executor); + editor.open(path.into(), executor); } _ => (), } @@ -499,12 +500,13 @@ pub fn file_picker(cx: &mut Context) { } pub fn buffer_picker(cx: &mut Context) { - cx.callback = Some(Box::new( - |compositor: &mut Compositor, editor: &mut Editor| { - let picker = ui::buffer_picker(&editor.views, editor.focus); - compositor.push(Box::new(picker)); - }, - )); + unimplemented!() + // cx.callback = Some(Box::new( + // |compositor: &mut Compositor, editor: &mut Editor| { + // let picker = ui::buffer_picker(&editor.views, editor.focus); + // compositor.push(Box::new(picker)); + // }, + // )); } // calculate line numbers for each selection range @@ -617,12 +619,7 @@ fn append_changes_to_history(cx: &mut Context) { // TODO: trigger lsp/documentDidChange with changes // HAXX: we need to reconstruct the state as it was before the changes.. - let old_state = cx - .view() - .doc - .old_state - .take() - .expect("no old_state available"); + let old_state = cx.doc().old_state.take().expect("no old_state available"); // TODO: take transaction by value? cx.doc().history.commit_revision(&transaction, &old_state); diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index a97ee7138..721dccc07 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -37,15 +37,20 @@ pub fn render_view( surface: &mut Surface, theme: &Theme, ) { - let area = Rect::new(OFFSET, 0, viewport.width - OFFSET, viewport.height - 2); // - 2 for statusline and prompt + let area = Rect::new( + viewport.x + OFFSET, + viewport.y, + viewport.width - OFFSET, + viewport.height - 2, + ); // - 2 for statusline and prompt self.render_buffer(view, area, surface, theme); // clear with background color // TODO: this seems to prevent setting style later // surface.set_style(viewport, theme.get("ui.background")); - let area = Rect::new(0, viewport.height - 2, viewport.width, 1); - self.render_statusline(view, area, surface, theme); + let area = Rect::new(viewport.x, viewport.height - 2, viewport.width, 1); + self.render_statusline(&view.doc, area, surface, theme); } // TODO: ideally not &mut View but highlights require it because of cursor cache @@ -203,34 +208,46 @@ pub fn render_buffer( let last_line = view.last_line(); for (i, line) in (view.first_line..last_line).enumerate() { if view.doc.diagnostics.iter().any(|d| d.line == line) { - surface.set_stringn(0, i as u16, "●", 1, warning); + surface.set_stringn( + viewport.x + 0 - OFFSET, + viewport.y + i as u16, + "●", + 1, + warning, + ); } - surface.set_stringn(1, i as u16, format!("{:>5}", line + 1), 5, style); + surface.set_stringn( + viewport.x + 1 - OFFSET, + viewport.y + i as u16, + format!("{:>5}", line + 1), + 5, + style, + ); } } pub fn render_statusline( &self, - view: &View, + doc: &Document, viewport: Rect, surface: &mut Surface, theme: &Theme, ) { let text_color = text_color(); - let mode = match view.doc.mode() { + let mode = match doc.mode() { Mode::Insert => "INS", Mode::Normal => "NOR", Mode::Goto => "GOTO", }; // statusline surface.set_style( - Rect::new(0, viewport.y, viewport.width, 1), + Rect::new(viewport.x, viewport.y, viewport.width, 1), theme.get("ui.statusline"), ); - surface.set_string(1, viewport.y, mode, text_color); + surface.set_string(viewport.x + 1, viewport.y, mode, text_color); - if let Some(path) = view.doc.relative_path() { + if let Some(path) = doc.relative_path() { let path = path.to_string_lossy(); surface.set_string(6, viewport.y, path, text_color); // TODO: append [+] if modified @@ -239,7 +256,7 @@ pub fn render_statusline( surface.set_string( viewport.width - 10, viewport.y, - format!("{}", view.doc.diagnostics.len()), + format!("{}", doc.diagnostics.len()), text_color, ); } @@ -251,9 +268,8 @@ fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult { Event::Resize(width, height) => { // TODO: simplistic ensure cursor in view for now // TODO: loop over views - let view = cx.editor.view_mut(); - view.size = (width, height); - view.ensure_cursor_in_view(); + cx.editor.tree.resize(Rect::new(0, 0, width, height)); + // TODO: restore view.ensure_cursor_in_view(); EventResult::Consumed(None) } Event::Key(event) => { @@ -306,8 +322,10 @@ fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) { // SAFETY: we cheat around the view_mut() borrow because it doesn't allow us to also borrow // theme. Theme is immutable mutating view won't disrupt theme_ref. let theme_ref = unsafe { &*(&cx.editor.theme as *const Theme) }; - let view = cx.editor.view_mut(); - self.render_view(view, area, surface, theme_ref); + for view in cx.editor.tree.views() { + // TODO: use parent area + self.render_view(view, view.area, surface, theme_ref); + } // TODO: drop unwrap } diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index bd40b249d..7c12b9182 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -82,38 +82,38 @@ pub fn file_picker(root: &str, ex: &'static smol::Executor) -> Picker { path.strip_prefix("./").unwrap().to_str().unwrap().into() }, move |editor: &mut Editor, path: &PathBuf| { - let size = editor.view().size; - editor.open(path.into(), size, ex); + editor.open(path.into(), ex); }, ) } use helix_view::View; pub fn buffer_picker(views: &[View], current: usize) -> Picker<(Option, usize)> { - use helix_view::Editor; - Picker::new( - views - .iter() - .enumerate() - .map(|(i, view)| (view.doc.relative_path().map(Path::to_path_buf), i)) - .collect(), - move |(path, index): &(Option, usize)| { - // format_fn - match path { - Some(path) => { - if *index == current { - format!("{} (*)", path.to_str().unwrap()).into() - } else { - path.to_str().unwrap().into() - } - } - None => "[NEW]".into(), - } - }, - |editor: &mut Editor, &(_, index): &(Option, usize)| { - if index < editor.views.len() { - editor.focus = index; - } - }, - ) + unimplemented!(); + // use helix_view::Editor; + // Picker::new( + // views + // .iter() + // .enumerate() + // .map(|(i, view)| (view.doc.relative_path().map(Path::to_path_buf), i)) + // .collect(), + // move |(path, index): &(Option, usize)| { + // // format_fn + // match path { + // Some(path) => { + // if *index == current { + // format!("{} (*)", path.to_str().unwrap()).into() + // } else { + // path.to_str().unwrap().into() + // } + // } + // None => "[NEW]".into(), + // } + // }, + // |editor: &mut Editor, &(_, index): &(Option, usize)| { + // if index < editor.views.len() { + // editor.focus = index; + // } + // }, + // ) } diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 0a4358114..938f35e51 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -24,3 +24,5 @@ url = "2" smol = "1" futures-util = "0.3" + +slotmap = "1" diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 54a098f9b..eb7450661 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1,45 +1,36 @@ use crate::theme::Theme; +use crate::tree::Tree; use crate::{Document, View}; +use slotmap::DefaultKey as Key; use std::path::PathBuf; use anyhow::Error; pub struct Editor { - pub views: Vec, - pub focus: usize, + pub tree: Tree, + // pub documents: Vec, + pub focus: Key, pub should_close: bool, pub theme: Theme, // TODO: share one instance pub language_servers: helix_lsp::Registry, } -impl Default for Editor { - fn default() -> Self { - Self::new() - } -} - impl Editor { - pub fn new() -> Self { + pub fn new(area: tui::layout::Rect) -> Self { let theme = Theme::default(); let language_servers = helix_lsp::Registry::new(); Self { - views: Vec::new(), - focus: 0, + tree: Tree::new(area), + focus: Key::default(), should_close: false, theme, language_servers, } } - pub fn open( - &mut self, - path: PathBuf, - size: (u16, u16), - executor: &smol::Executor, - ) -> Result<(), Error> { - let pos = self.views.len(); + pub fn open(&mut self, path: PathBuf, executor: &smol::Executor) -> Result<(), Error> { let mut doc = Document::load(path, self.theme.scopes())?; // try to find a language server based on the language name @@ -60,16 +51,17 @@ pub fn open( .unwrap(); } - self.views.push(View::new(doc, size)?); + let view = View::new(doc)?; + let pos = self.tree.insert(view); self.focus = pos; Ok(()) } pub fn view(&self) -> &View { - self.views.get(self.focus).unwrap() + self.tree.get(self.focus) } pub fn view_mut(&mut self) -> &mut View { - self.views.get_mut(self.focus).unwrap() + self.tree.get_mut(self.focus) } } diff --git a/helix-view/src/lib.rs b/helix-view/src/lib.rs index f28c8116d..05de7e9f9 100644 --- a/helix-view/src/lib.rs +++ b/helix-view/src/lib.rs @@ -1,6 +1,7 @@ pub mod document; pub mod editor; pub mod theme; +pub mod tree; pub mod view; pub use document::Document; diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index df41e3aed..24b50d81f 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -17,15 +17,15 @@ pub struct View { pub doc: Document, pub first_line: usize, - pub size: (u16, u16), + pub area: Rect, } impl View { - pub fn new(doc: Document, size: (u16, u16)) -> Result { + pub fn new(doc: Document) -> Result { let view = Self { doc, first_line: 0, - size, + area: Rect::default(), // will get calculated upon inserting into tree }; Ok(view) @@ -34,7 +34,7 @@ pub fn new(doc: Document, size: (u16, u16)) -> Result { pub fn ensure_cursor_in_view(&mut self) { let cursor = self.doc.state.selection().cursor(); let line = self.doc.text().char_to_line(cursor); - let document_end = self.first_line + (self.size.1 as usize).saturating_sub(2); + let document_end = self.first_line + (self.area.height as usize).saturating_sub(2); // TODO: side scroll @@ -50,7 +50,7 @@ pub fn ensure_cursor_in_view(&mut self) { /// Calculates the last visible line on screen #[inline] pub fn last_line(&self) -> usize { - let viewport = Rect::new(6, 0, self.size.0, self.size.1 - 2); // - 2 for statusline and prompt + let viewport = Rect::new(6, 0, self.area.width, self.area.height - 2); // - 2 for statusline and prompt std::cmp::min( self.first_line + (viewport.height as usize), self.doc.text().len_lines() - 1,