From e6d69db4992a04a45d26336efb2fd6bc47db03fc Mon Sep 17 00:00:00 2001 From: Nefo Fortressia Date: Thu, 11 Nov 2021 06:15:48 +0700 Subject: [PATCH 1/8] chore: pin pre-commit repos to their latest version --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index faf9a85..42d12f7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,11 @@ repos: - repo: https://github.com/commitizen-tools/commitizen - rev: master + rev: v2.20.0 hooks: - id: commitizen stages: [commit-msg] - repo: https://github.com/doublify/pre-commit-rust - rev: master + rev: v1.0 hooks: - id: fmt - id: cargo-check From 966a909ab86bc9b252573e296aac7bbab4fad272 Mon Sep 17 00:00:00 2001 From: Nefo Fortressia Date: Thu, 11 Nov 2021 06:20:11 +0700 Subject: [PATCH 2/8] refactor: make workspace.rs implements on EchidnaWindow The code was moved from the EchidnaEditor struct, but we haven't updated it to implement EchidnaWindow instead of EchidnaEditor. --- src/components/window/workspace.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/window/workspace.rs b/src/components/window/workspace.rs index 9cc5c6c..459973a 100644 --- a/src/components/window/workspace.rs +++ b/src/components/window/workspace.rs @@ -1,15 +1,16 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -use super::imp::EchidnaEditor; +use super::EchidnaWindow; use gio::Cancellable; use gio::{File, FileQueryInfoFlags, FileType, SimpleAction}; use glib::clone; -use glib::subclass::types::ObjectSubclassExt; use glib::types::Type; use gtk::prelude::*; -use gtk::{ApplicationWindow, FileChooserAction, FileChooserDialog, ResponseType, TreeStore}; +use gtk::{ + Application, ApplicationWindow, FileChooserAction, FileChooserDialog, ResponseType, TreeStore, + TreeView, +}; use relative_path::RelativePath; use serde::{Deserialize, Serialize}; use std::path::Path; @@ -28,7 +29,7 @@ trait WorkspaceImplementedEditor { fn action_open_workspace( &self, window: ApplicationWindow, - app: super::EchidnaEditor, + app: Application, _action: &SimpleAction, _variant: Option<&glib::Variant>, ); @@ -38,11 +39,11 @@ trait WorkspaceImplementedEditor { fn open_folder(&self, file: File); } -impl WorkspaceImplementedEditor for EchidnaEditor { +impl WorkspaceImplementedEditor for EchidnaWindow { fn action_open_workspace( &self, window: ApplicationWindow, - app: super::EchidnaEditor, + app: Application, _action: &SimpleAction, _variant: Option<&glib::Variant>, ) { @@ -56,14 +57,14 @@ impl WorkspaceImplementedEditor for EchidnaEditor { ], ); dialog.set_visible(true); - dialog.connect_response(clone!(@weak window, @weak app => + dialog.connect_response(clone!(@weak self as win => move |dialog, response| { if response == ResponseType::Accept { let file_option = dialog.file(); match file_option { Some(file) => { dialog.destroy(); - Self::from_instance(&app).open_workspace(file); + win.open_workspace(file); }, None => {} } @@ -125,7 +126,6 @@ impl WorkspaceImplementedEditor for EchidnaEditor { self.open_folder(folder); } } -} /** * From cc6d3316700c36632190bc9df6337807aee715ca Mon Sep 17 00:00:00 2001 From: Nefo Fortressia Date: Thu, 11 Nov 2021 07:30:25 +0700 Subject: [PATCH 3/8] fix: fix some format! macro issues in workspace.rs --- src/components/window/workspace.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/components/window/workspace.rs b/src/components/window/workspace.rs index 459973a..7668350 100644 --- a/src/components/window/workspace.rs +++ b/src/components/window/workspace.rs @@ -95,28 +95,22 @@ impl WorkspaceImplementedEditor for EchidnaWindow { let filepath = Path::new(&filepath_raw); let info = file .query_info("*", gio::FileQueryInfoFlags::NONE, Some(&cancellable)) - .expect(format!( - "Could not retrieve file information for {:?}", - filepath - )); + .expect(format!("Could not retrieve file information for {:?}", filepath).as_str()); let content_type = info .content_type() - .expect(format!("Found no content type for {:?}", filepath)); + .expect(format!("Found no content type for {:?}", filepath).as_str()); println!( "Opened {} and found its content type is {}.", "file", content_type.to_string() ); let content_cancellable = Cancellable::new(); - let content = file + let (content, _) = file .load_contents(Some(&content_cancellable)) - .expect("Could not load the file contents for {:?}", filepath); + .expect(format!("Could not load the file contents for {:?}", filepath).as_str()); - let (int_vec, _byte_string) = content; - let workspace = serde_json::from_slice::(&int_vec).expect(format!( - "Could not parse the workspace file of {:?}", - filepath - )); + let workspace = serde_json::from_slice::(&content) + .expect(format!("Could not parse the workspace file of {:?}", filepath).as_str()); for folder in workspace.folders { let path = RelativePath::new(&folder.path); From 8afa897776c8c8c42a254ebf8c5d9e11a1c3f28d Mon Sep 17 00:00:00 2001 From: Nefo Fortressia Date: Thu, 11 Nov 2021 07:32:14 +0700 Subject: [PATCH 4/8] fix: fix not defined errors in recursive_add_files_into_tree_store() recursive_add_files_into_tree_store() tried to refer to 'filepath', which is not defined. Use the parent_file's path to replace 'filepath'. The function also tried to refer to 'files', which is also not defined. Seems to be a typo of 'child_files'. --- src/components/window/workspace.rs | 45 ++++++++++++++---------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/components/window/workspace.rs b/src/components/window/workspace.rs index 7668350..3462051 100644 --- a/src/components/window/workspace.rs +++ b/src/components/window/workspace.rs @@ -121,31 +121,28 @@ impl WorkspaceImplementedEditor for EchidnaWindow { } } -/** - * - * - */ -fn recursive_add_files_into_tree_store(&self, parent_file: File, tree: &TreeStore) { - let child_enumerate_cancellable = Cancellable::new(); - let child_files = parent_file - .enumerate_children( - "*", - FileQueryInfoFlags::NONE, - Some(&child_enumerate_cancellable), - ) - .expect( - format!( - "Could not look up the children files of {:?} because:\n{:#?}", - filepath + /** + * + * + */ + fn recursive_add_files_into_tree_store(&self, parent_file: File, tree: &TreeStore) { + let child_enumerate_cancellable = Cancellable::new(); + + let child_files = parent_file + .enumerate_children( + "*", + FileQueryInfoFlags::NONE, + Some(&child_enumerate_cancellable), ) - .as_str(), - ); - let filepath = &parent_file - .path() - .expect("Could not get the file path of the file."); - - for file_iter in files { - let file_info = file_iter.expect(); + .expect( + format!( + "Could not look up the children files of {:?} because:", + parent_file.path().expect("No path for the parent file") + ) + .as_str(), + ); + for file_iter in child_files { + let file_info = file_iter.expect("Could not get the file info"); let file = parent_file.child(file_info.name()); let tree_iter = tree.append(None); tree.set_value(&tree_iter, 2, &file_info.name().to_str().to_value()); From b65788f30093bed01a08acf15c6c857fcf9801c3 Mon Sep 17 00:00:00 2001 From: Nefo Fortressia Date: Sat, 18 Dec 2021 11:32:00 +0700 Subject: [PATCH 5/8] feat: implement EchidnaSidebar.to_imp() --- src/components/sidebar/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/sidebar/mod.rs b/src/components/sidebar/mod.rs index 7aa464a..b9c623e 100644 --- a/src/components/sidebar/mod.rs +++ b/src/components/sidebar/mod.rs @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ pub mod imp; +use gtk::subclass::prelude::*; glib::wrapper! { pub struct EchidnaSidebar(ObjectSubclass) @@ -14,4 +15,8 @@ impl EchidnaSidebar { pub fn new() -> Self { glib::Object::new(&[]).expect("Failed to create 'EchidnaSidebar' component.") } + + pub fn to_imp(&self) -> &imp::EchidnaSidebar { + imp::EchidnaSidebar::from_instance(self) + } } From 4edeeaf080b1b0dc33d6e0e6b108d31810b14d6f Mon Sep 17 00:00:00 2001 From: Nefo Fortressia Date: Sat, 18 Dec 2021 11:40:21 +0700 Subject: [PATCH 6/8] feat: add a GtkStackPage in EchidnaSidebar --- src/components/sidebar/imp.rs | 5 ++++- src/components/sidebar/sidebar.ui | 8 ++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/sidebar/imp.rs b/src/components/sidebar/imp.rs index cc41ea5..2bc2ad4 100644 --- a/src/components/sidebar/imp.rs +++ b/src/components/sidebar/imp.rs @@ -8,7 +8,10 @@ use gtk::CompositeTemplate; #[derive(Default, CompositeTemplate)] #[template(file = "./sidebar.ui")] -pub struct EchidnaSidebar {} +pub struct EchidnaSidebar { + #[template_child] + pub explorer: TemplateChild, +} #[glib::object_subclass] impl ObjectSubclass for EchidnaSidebar { diff --git a/src/components/sidebar/sidebar.ui b/src/components/sidebar/sidebar.ui index 372a406..dd5b36d 100644 --- a/src/components/sidebar/sidebar.ui +++ b/src/components/sidebar/sidebar.ui @@ -17,18 +17,14 @@ 1 170 - + explorer Explorer GTK_ORIENTATION_VERTICAL - - - Explorer - - + From 6b3b45a1bcb90076e0f7c0fd237635b3f9273699 Mon Sep 17 00:00:00 2001 From: Nefo Fortressia Date: Sat, 18 Dec 2021 11:46:12 +0700 Subject: [PATCH 7/8] feat: partially implement workspace opening This implementation will not work atm. We still need to implement a connection between the main thread and the Tokio runtime. rt.spawn() requires the future to implement Sync, which open_folder() does not. This is because it contains pointers to GTK4 objects, which aren't thread-safe. Or, alternatively just use another alternative runtime that doesn't require Sync. Idk if there are any. --- Cargo.lock | 266 +++++++++++++++++++++++++++-- Cargo.toml | 6 +- src/components/mod.rs | 2 +- src/components/window/menubar.rs | 12 +- src/components/window/mod.rs | 2 +- src/components/window/workspace.rs | 179 +++++++++++-------- 6 files changed, 378 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a961a24..0567db1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,28 @@ version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -20,6 +42,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + [[package]] name = "cairo-rs" version = "0.14.7" @@ -62,10 +90,19 @@ dependencies = [ "smallvec", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "echidna" version = "0.1.0" dependencies = [ + "async-recursion", + "async-trait", + "futures", "gdk4", "gio", "glib", @@ -75,6 +112,7 @@ dependencies = [ "serde", "serde_json", "sourceview5", + "tokio", ] [[package]] @@ -94,25 +132,41 @@ dependencies = [ ] [[package]] -name = "futures-channel" -version = "0.3.17" +name = "futures" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" dependencies = [ "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" [[package]] name = "futures-executor" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" dependencies = [ "futures-core", "futures-task", @@ -121,25 +175,46 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" + +[[package]] +name = "futures-macro" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" [[package]] name = "futures-task" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" +checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" dependencies = [ - "autocfg", + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -410,6 +485,24 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "itertools" version = "0.10.1" @@ -431,6 +524,30 @@ version = "0.2.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + [[package]] name = "memoffset" version = "0.6.4" @@ -440,6 +557,47 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "once_cell" version = "1.8.0" @@ -471,6 +629,31 @@ dependencies = [ "system-deps 3.2.0", ] +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + [[package]] name = "pest" version = "2.1.3" @@ -550,6 +733,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + [[package]] name = "relative-path" version = "1.5.0" @@ -571,6 +763,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "semver" version = "0.11.0" @@ -620,6 +818,15 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.4" @@ -767,6 +974,37 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "toml" version = "0.5.8" diff --git a/Cargo.toml b/Cargo.toml index 3265340..bdc71c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,8 @@ serde = { version = "^1.0.130", features = ["derive"] } relative-path = "^1.5.0" gdk = { version = "^0.3.0", package = "gdk4"} sourceview = { package = "sourceview5", version = "^0.1.0", git = "https://github.com/EchidnaHQ/sourceview" } -once_cell = "1" \ No newline at end of file +once_cell = "1" +async-recursion = "0.3.2" +async-trait = "0.1.7" +futures = "0.3" +tokio = { version = "1", features = ["full"]} \ No newline at end of file diff --git a/src/components/mod.rs b/src/components/mod.rs index 5353e5a..234d52a 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -15,5 +15,5 @@ pub use tab_label::TabLabel; pub use window::EchidnaWindow; pub mod prelude { - pub use super::window::{file::*, menubar::*}; + pub use super::window::{file::*, menubar::*, workspace::*}; } diff --git a/src/components/window/menubar.rs b/src/components/window/menubar.rs index f51f47f..9e6fc79 100644 --- a/src/components/window/menubar.rs +++ b/src/components/window/menubar.rs @@ -2,8 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use super::file::FileImplementedEditor; use super::EchidnaWindow; +use crate::prelude::*; use gio::{MenuModel, SimpleAction}; use glib::clone; use gtk::prelude::*; @@ -122,5 +122,15 @@ impl MenubarImplementedEditor for EchidnaWindow { window.action_save_file_as(); })); } + { + let action_open_workspace = SimpleAction::new("open-workspace", None); + + self.add_action(&action_open_workspace); + + action_open_workspace.connect_activate(clone!(@weak self as window => + move |_action, _variant| { + window.action_open_workspace(); + })); + } } } diff --git a/src/components/window/mod.rs b/src/components/window/mod.rs index 40ed731..d07b5cb 100644 --- a/src/components/window/mod.rs +++ b/src/components/window/mod.rs @@ -5,7 +5,7 @@ pub mod file; pub mod imp; pub mod menubar; - +pub mod workspace; use glib::object::IsA; use gtk::subclass::prelude::*; diff --git a/src/components/window/workspace.rs b/src/components/window/workspace.rs index 433262f..83aec5e 100644 --- a/src/components/window/workspace.rs +++ b/src/components/window/workspace.rs @@ -2,15 +2,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use super::EchidnaWindow; +use async_recursion::async_recursion; +use async_trait::async_trait; +use core::pin::Pin; +use futures::stream::FuturesUnordered; use gio::Cancellable; -use gio::{File, FileQueryInfoFlags, FileType, SimpleAction}; +use gio::{File, FileQueryInfoFlags, FileType}; use glib::clone; use glib::types::Type; use gtk::prelude::*; -use gtk::{ApplicationWindow, FileChooserAction, FileChooserNative, ResponseType, TreeStore}; +use gtk::{FileChooserAction, FileChooserNative, ResponseType, TreeIter, TreeStore, TreeView}; use relative_path::RelativePath; use serde::{Deserialize, Serialize}; use std::path::Path; +use tokio::runtime; #[derive(Deserialize, Serialize)] struct MonacoFolder { @@ -22,31 +27,78 @@ struct MonacoWorkspace { folders: Vec, } -trait WorkspaceImplementedEditor { - fn action_open_workspace( - &self, - window: ApplicationWindow, - app: Application, - _action: &SimpleAction, - _variant: Option<&glib::Variant>, +/* +Loads a folder into the tree view. + +- Create a new tree +- Enumerate over child files of 'file'. (PS: In the Unix family of OS-es, directories are files too) +*/ + +async fn open_folder(explorer_box: >k::Box, file: File) { + let tree = TreeStore::new(&[gdk::Texture::static_type(), Type::STRING]); + println!("Opening folder {:?}", file.path()); + recursive_add_files_into_tree_store(&file, &tree, None).await; + + let tree_view = TreeView::new(); + + tree_view.set_model(Some(&tree)); + + explorer_box.prepend(&tree_view); +} +#[async_recursion(?Send)] +async fn recursive_add_files_into_tree_store( + parent_file: &File, + tree: &TreeStore, + parent_iter: Option<&'async_recursion TreeIter>, +) { + let child_enumerate_cancellable = Cancellable::new(); + + println!( + "Adding file {:?} and if it's a folder, with its children, to the tree store.", + parent_file.path() ); + let child_files = parent_file + .enumerate_children( + "*", + FileQueryInfoFlags::NONE, + Some(&child_enumerate_cancellable), + ) + .expect( + format!( + "Could not look up the children files of {:?} because:", + parent_file.path().expect("No path for the parent file") + ) + .as_str(), + ); + for file_iter in child_files { + let file_info = file_iter.expect("Could not get the file info"); + let file = parent_file.child(file_info.name()); + + println!( + "Found child {:?} of {:?}", + file_info.name(), + parent_file.path() + ); + + let tree_iter = tree.append(parent_iter); + tree.set_value(&tree_iter, 1, &file_info.name().to_str().to_value()); + if file_info.file_type() == FileType::Directory { + recursive_add_files_into_tree_store(&file, tree, Some(&tree_iter)).await; + } + } +} +#[async_trait] +pub trait WorkspaceImplementedEditor { + fn action_open_workspace(&self); fn open_workspace(&self, file: File); - fn recursive_add_files_into_tree_store(&self, parent_file: File, tree: &TreeStore); - fn open_folder(&self, file: File); } - +#[async_trait] impl WorkspaceImplementedEditor for EchidnaWindow { - fn action_open_workspace( - &self, - window: ApplicationWindow, - app: Application, - _action: &SimpleAction, - _variant: Option<&glib::Variant>, - ) { - let dialog = FileChooserNative::new( + fn action_open_workspace(&self) { + let dialog: FileChooserNative = FileChooserNative::new( Some("Open a file"), - Some(&window), + Some(self), FileChooserAction::Open, Some("Open"), Some("Cancel"), @@ -76,10 +128,7 @@ impl WorkspaceImplementedEditor for EchidnaWindow { * * - Open a FileChooserNative, set to only view .code-workspace files. * - If the user pressed cancel, destroy the dialog. If the user opened a .code-workspace file: - * - Get the workspace file, load and parse its content, .code-workspace files are in JSON with comments. But JSON only should be fine, for now. - * - Iterate over folders listed in the workspace file. - * - Find the absolute path of the folder: Relative to the workspace file. - * - Create a GFile instance of that path, and call open_folder(file: File) and pass the GFile instance to it. + * - Get the workspace file, load and parse its content, .code-workspace files are - - Create a GFile instance of that path, and call open_folder(file: File) and pass the GFile instance to it. * */ fn open_workspace(&self, file: File) { @@ -106,55 +155,43 @@ impl WorkspaceImplementedEditor for EchidnaWindow { let workspace = serde_json::from_slice::(&content) .expect(format!("Could not parse the workspace file of {:?}", filepath).as_str()); + let explorer_box: >k::Box = &self + .to_imp() + .sidebar + .to_imp() + .explorer + .child() + .downcast() + .expect("Could not downcast the Explorer activity tab's child widget to GtkBox."); + let folder_futures_unordered: FuturesUnordered<_> = workspace.folders.iter().map(|folder_path|{ + let path = RelativePath::new(&folder_path.path); + let folder = File::for_path( + path.to_path( + filepath + .parent() + .expect("Could not get the parent of 'filepath'. 'filepath' terminates in a root or prefix.") + ) + ); - for folder in workspace.folders { - let path = RelativePath::new(&folder.path); - let folder = File::for_path(path.to_path(filepath)); + println!("Pushing {:?} into the futures for opening.", folder.path()); // Do something with the folder, perhaps lists its child and . - self.open_folder(folder); + open_folder(&explorer_box, folder) + }).collect(); + + let rt = runtime::Runtime::new().unwrap(); + + for future in Pin::new(&folder_futures_unordered).iter_pin_ref() { + + /* + TODO: Implement a connection between the main thread and the Tokio runtime. + + GTK4 is not thread-safe thus it does not implement Sync on its objects, which is a requirement for tokio Runtime::spawn(). + + Or maybe using Tokio is stupid for this and we should just use another runtime that doesn't require Send, which idk if there are any atm. + */ + + // rt.spawn(future); } } - - /** - * - * - */ - fn recursive_add_files_into_tree_store(&self, parent_file: File, tree: &TreeStore) { - let child_enumerate_cancellable = Cancellable::new(); - let child_files = parent_file - .enumerate_children( - "*", - FileQueryInfoFlags::NONE, - Some(&child_enumerate_cancellable), - ) - .expect( - format!( - "Could not look up the children files of {:?} because:", - parent_file.path().expect("No path for the parent file") - ) - .as_str(), - ); - for file_iter in child_files { - let file_info = file_iter.expect("Could not get the file info"); - let file = parent_file.child(file_info.name()); - let tree_iter = tree.append(None); - tree.set_value(&tree_iter, 2, &file_info.name().to_str().to_value()); - - if file_info.file_type() == FileType::Directory { - self.recursive_add_files_into_tree_store(file, tree); - } - } - } - - /* - Loads a folder into the tree view. - - - Create a new tree - - Enumerate over child files of 'file'. (PS: In the Unix family of OS-es, directories are files too) - */ - fn open_folder(&self, file: File) { - let tree = TreeStore::new(&[gdk::Texture::static_type(), Type::STRING]); - self.recursive_add_files_into_tree_store(file, &tree); - } } From 7bb8a5eef5ee0647a00295f74bb778122d3efaba Mon Sep 17 00:00:00 2001 From: Nefo Fortressia Date: Sat, 18 Dec 2021 14:27:20 +0700 Subject: [PATCH 8/8] refactor: split workspace.rs into different files workspace.rs was a very spaghetti file. --- .../window/{workspace.rs => workspace/mod.rs} | 77 ++----------------- .../window/workspace/open_folder.rs | 20 +++++ .../window/workspace/recursive_add_files.rs | 49 ++++++++++++ 3 files changed, 77 insertions(+), 69 deletions(-) rename src/components/window/{workspace.rs => workspace/mod.rs} (69%) create mode 100644 src/components/window/workspace/open_folder.rs create mode 100644 src/components/window/workspace/recursive_add_files.rs diff --git a/src/components/window/workspace.rs b/src/components/window/workspace/mod.rs similarity index 69% rename from src/components/window/workspace.rs rename to src/components/window/workspace/mod.rs index 83aec5e..ed638b5 100644 --- a/src/components/window/workspace.rs +++ b/src/components/window/workspace/mod.rs @@ -1,17 +1,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +mod open_folder; + +pub use open_folder::*; +mod recursive_add_files; use super::EchidnaWindow; -use async_recursion::async_recursion; -use async_trait::async_trait; use core::pin::Pin; use futures::stream::FuturesUnordered; -use gio::Cancellable; -use gio::{File, FileQueryInfoFlags, FileType}; +use gio::{Cancellable, File}; use glib::clone; -use glib::types::Type; -use gtk::prelude::*; -use gtk::{FileChooserAction, FileChooserNative, ResponseType, TreeIter, TreeStore, TreeView}; +use gtk::{prelude::*, FileChooserAction, FileChooserNative, ResponseType}; use relative_path::RelativePath; use serde::{Deserialize, Serialize}; use std::path::Path; @@ -27,73 +27,12 @@ struct MonacoWorkspace { folders: Vec, } -/* -Loads a folder into the tree view. - -- Create a new tree -- Enumerate over child files of 'file'. (PS: In the Unix family of OS-es, directories are files too) -*/ - -async fn open_folder(explorer_box: >k::Box, file: File) { - let tree = TreeStore::new(&[gdk::Texture::static_type(), Type::STRING]); - println!("Opening folder {:?}", file.path()); - recursive_add_files_into_tree_store(&file, &tree, None).await; - - let tree_view = TreeView::new(); - - tree_view.set_model(Some(&tree)); - - explorer_box.prepend(&tree_view); -} -#[async_recursion(?Send)] -async fn recursive_add_files_into_tree_store( - parent_file: &File, - tree: &TreeStore, - parent_iter: Option<&'async_recursion TreeIter>, -) { - let child_enumerate_cancellable = Cancellable::new(); - - println!( - "Adding file {:?} and if it's a folder, with its children, to the tree store.", - parent_file.path() - ); - let child_files = parent_file - .enumerate_children( - "*", - FileQueryInfoFlags::NONE, - Some(&child_enumerate_cancellable), - ) - .expect( - format!( - "Could not look up the children files of {:?} because:", - parent_file.path().expect("No path for the parent file") - ) - .as_str(), - ); - for file_iter in child_files { - let file_info = file_iter.expect("Could not get the file info"); - let file = parent_file.child(file_info.name()); - - println!( - "Found child {:?} of {:?}", - file_info.name(), - parent_file.path() - ); - - let tree_iter = tree.append(parent_iter); - tree.set_value(&tree_iter, 1, &file_info.name().to_str().to_value()); - if file_info.file_type() == FileType::Directory { - recursive_add_files_into_tree_store(&file, tree, Some(&tree_iter)).await; - } - } -} -#[async_trait] pub trait WorkspaceImplementedEditor { fn action_open_workspace(&self); fn open_workspace(&self, file: File); } -#[async_trait] + impl WorkspaceImplementedEditor for EchidnaWindow { fn action_open_workspace(&self) { let dialog: FileChooserNative = FileChooserNative::new( diff --git a/src/components/window/workspace/open_folder.rs b/src/components/window/workspace/open_folder.rs new file mode 100644 index 0000000..f437657 --- /dev/null +++ b/src/components/window/workspace/open_folder.rs @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use super::recursive_add_files::*; +use gio::File; +use glib::Type; +use gtk::{prelude::*, TreeStore, TreeView}; + +pub async fn open_folder(explorer_box: >k::Box, file: File) { + let tree = TreeStore::new(&[gdk::Texture::static_type(), Type::STRING]); + println!("Opening folder {:?}", file.path()); + recursive_add_files_into_tree_store(&file, &tree, None).await; + + let tree_view = TreeView::new(); + + tree_view.set_model(Some(&tree)); + + explorer_box.prepend(&tree_view); +} diff --git a/src/components/window/workspace/recursive_add_files.rs b/src/components/window/workspace/recursive_add_files.rs new file mode 100644 index 0000000..0db23ee --- /dev/null +++ b/src/components/window/workspace/recursive_add_files.rs @@ -0,0 +1,49 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use async_recursion::async_recursion; +use gio::{Cancellable, File, FileQueryInfoFlags, FileType}; +use gtk::{prelude::*, TreeIter, TreeStore}; +#[async_recursion(?Send)] +pub async fn recursive_add_files_into_tree_store( + parent_file: &File, + tree: &TreeStore, + parent_iter: Option<&'async_recursion TreeIter>, +) { + let child_enumerate_cancellable = Cancellable::new(); + + println!( + "Adding file {:?} and if it's a folder, with its children, to the tree store.", + parent_file.path() + ); + let child_files = parent_file + .enumerate_children( + "*", + FileQueryInfoFlags::NONE, + Some(&child_enumerate_cancellable), + ) + .expect( + format!( + "Could not look up the children files of {:?} because:", + parent_file.path().expect("No path for the parent file") + ) + .as_str(), + ); + for file_iter in child_files { + let file_info = file_iter.expect("Could not get the file info"); + let file = parent_file.child(file_info.name()); + + println!( + "Found child {:?} of {:?}", + file_info.name(), + parent_file.path() + ); + + let tree_iter = tree.append(parent_iter); + tree.set_value(&tree_iter, 1, &file_info.name().to_str().to_value()); + if file_info.file_type() == FileType::Directory { + recursive_add_files_into_tree_store(&file, tree, Some(&tree_iter)).await; + } + } +}