WIP: feat: implement workspaces support #12
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
once_cell = "1"
|
||||
async-recursion = "0.3.2"
|
||||
async-trait = "0.1.7"
|
||||
futures = "0.3"
|
||||
tokio = { version = "1", features = ["full"]}
|
|
@ -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::*};
|
||||
}
|
||||
|
|
|
@ -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<gtk::StackPage>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for EchidnaSidebar {
|
||||
|
|
|
@ -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<imp::EchidnaSidebar>)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,18 +17,14 @@
|
|||
<property name="hhomogeneous">1</property>
|
||||
<property name="width-request">170</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<object class="GtkStackPage" id="explorer">
|
||||
<!-- Explorer Tab -->
|
||||
<property name="name">explorer</property>
|
||||
<property name="title">Explorer</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Explorer</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</property>
|
||||
|
||||
|
|
|
@ -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();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
pub mod file;
|
||||
pub mod imp;
|
||||
pub mod menubar;
|
||||
|
||||
pub mod workspace;
|
||||
use glib::object::IsA;
|
||||
use gtk::subclass::prelude::*;
|
||||
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
/* 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 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, FileChooserNative, ResponseType, TreeStore};
|
||||
use relative_path::RelativePath;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct MonacoFolder {
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct MonacoWorkspace {
|
||||
folders: Vec<MonacoFolder>,
|
||||
}
|
||||
|
||||
trait WorkspaceImplementedEditor {
|
||||
fn action_open_workspace(
|
||||
&self,
|
||||
window: ApplicationWindow,
|
||||
app: super::EchidnaEditor,
|
||||
_action: &SimpleAction,
|
||||
_variant: Option<&glib::Variant>,
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
impl WorkspaceImplementedEditor for EchidnaEditor {
|
||||
fn action_open_workspace(
|
||||
&self,
|
||||
window: ApplicationWindow,
|
||||
app: super::EchidnaEditor,
|
||||
_action: &SimpleAction,
|
||||
_variant: Option<&glib::Variant>,
|
||||
) {
|
||||
let dialog = FileChooserNative::new(
|
||||
Some("Open a file"),
|
||||
Some(&window),
|
||||
FileChooserAction::Open,
|
||||
Some("Open"),
|
||||
Some("Cancel"),
|
||||
);
|
||||
dialog.set_visible(true);
|
||||
dialog.connect_response(clone!(@weak window, @weak app =>
|
||||
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);
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
} else if response == ResponseType::Cancel {
|
||||
dialog.destroy();
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
/**
|
||||
* __Open Workspace__
|
||||
*
|
||||
* Basically, this is just the same as Open Folder, but it's many folders.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
*/
|
||||
fn open_workspace(&self, file: File) {
|
||||
let cancellable = Cancellable::new();
|
||||
let filepath_raw = &file
|
||||
.path()
|
||||
.expect("Could not get the file path of the file.");
|
||||
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
|
||||
));
|
||||
let content_type = info
|
||||
.content_type()
|
||||
.expect(format!("Found no content type for {:?}", filepath));
|
||||
println!(
|
||||
"Opened {} and found its content type is {}.",
|
||||
"file",
|
||||
content_type.to_string()
|
||||
);
|
||||
let content_cancellable = Cancellable::new();
|
||||
let content = file
|
||||
.load_contents(Some(&content_cancellable))
|
||||
.expect("Could not load the file contents for {:?}", filepath);
|
||||
|
||||
let (int_vec, _byte_string) = content;
|
||||
let workspace = serde_json::from_slice::<MonacoWorkspace>(&int_vec).expect(format!(
|
||||
"Could not parse the workspace file of {:?}",
|
||||
filepath
|
||||
));
|
||||
|
||||
for folder in workspace.folders {
|
||||
let path = RelativePath::new(&folder.path);
|
||||
let folder = File::for_path(path.to_path(filepath));
|
||||
|
||||
// Do something with the folder, perhaps lists its child and .
|
||||
self.open_folder(folder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
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
|
||||
)
|
||||
.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();
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/* 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 core::pin::Pin;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use gio::{Cancellable, File};
|
||||
use glib::clone;
|
||||
use gtk::{prelude::*, FileChooserAction, FileChooserNative, ResponseType};
|
||||
use relative_path::RelativePath;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
use tokio::runtime;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct MonacoFolder {
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct MonacoWorkspace {
|
||||
folders: Vec<MonacoFolder>,
|
||||
}
|
||||
|
||||
pub trait WorkspaceImplementedEditor {
|
||||
fn action_open_workspace(&self);
|
||||
|
||||
fn open_workspace(&self, file: File);
|
||||
}
|
||||
|
||||
impl WorkspaceImplementedEditor for EchidnaWindow {
|
||||
fn action_open_workspace(&self) {
|
||||
let dialog: FileChooserNative = FileChooserNative::new(
|
||||
Some("Open a file"),
|
||||
Some(self),
|
||||
FileChooserAction::Open,
|
||||
Some("Open"),
|
||||
Some("Cancel"),
|
||||
);
|
||||
dialog.set_visible(true);
|
||||
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();
|
||||
win.open_workspace(file);
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
} else if response == ResponseType::Cancel {
|
||||
dialog.destroy();
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
/**
|
||||
* __Open Workspace__
|
||||
*
|
||||
* Basically, this is just the same as Open Folder, but it's many folders.
|
||||
*
|
||||
* - 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 - - 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) {
|
||||
let cancellable = Cancellable::new();
|
||||
let filepath_raw = &file
|
||||
.path()
|
||||
.expect("Could not get the file path of the file.");
|
||||
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).as_str());
|
||||
let content_type = info
|
||||
.content_type()
|
||||
.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
|
||||
.load_contents(Some(&content_cancellable))
|
||||
.expect(format!("Could not load the file contents for {:?}", filepath).as_str());
|
||||
|
||||
let workspace = serde_json::from_slice::<MonacoWorkspace>(&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.")
|
||||
)
|
||||
);
|
||||
|
||||
println!("Pushing {:?} into the futures for opening.", folder.path());
|
||||
|
||||
// Do something with the folder, perhaps lists its child and .
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue