1pub mod pane;
2pub mod pane_group;
3pub mod workspace;
4pub mod workspace_view;
5
6pub use pane::*;
7pub use pane_group::*;
8pub use workspace::*;
9pub use workspace_view::*;
10
11use crate::{
12 settings::Settings,
13 watch::{self, Receiver},
14};
15use gpui::{MutableAppContext, PathPromptOptions};
16use std::path::PathBuf;
17
18pub fn init(app: &mut MutableAppContext) {
19 app.add_global_action("workspace:open", open);
20 app.add_global_action("workspace:open_paths", open_paths);
21 app.add_global_action("app:quit", quit);
22 pane::init(app);
23 workspace_view::init(app);
24}
25
26pub struct OpenParams {
27 pub paths: Vec<PathBuf>,
28 pub settings: watch::Receiver<Settings>,
29}
30
31fn open(settings: &Receiver<Settings>, ctx: &mut MutableAppContext) {
32 if let Some(paths) = ctx.platform().prompt_for_paths(PathPromptOptions {
33 files: true,
34 directories: true,
35 multiple: true,
36 }) {
37 ctx.dispatch_global_action(
38 "workspace:open_paths",
39 OpenParams {
40 paths,
41 settings: settings.clone(),
42 },
43 );
44 }
45}
46
47fn open_paths(params: &OpenParams, app: &mut MutableAppContext) {
48 log::info!("open paths {:?}", params.paths);
49
50 // Open paths in existing workspace if possible
51 for window_id in app.window_ids().collect::<Vec<_>>() {
52 if let Some(handle) = app.root_view::<WorkspaceView>(window_id) {
53 if handle.update(app, |view, ctx| {
54 if view.contains_paths(¶ms.paths, ctx.app()) {
55 view.open_paths(¶ms.paths, ctx.app_mut());
56 log::info!("open paths on existing workspace");
57 true
58 } else {
59 false
60 }
61 }) {
62 return;
63 }
64 }
65 }
66
67 log::info!("open new workspace");
68
69 // Add a new workspace if necessary
70 let workspace = app.add_model(|ctx| Workspace::new(params.paths.clone(), ctx));
71 app.add_window(|ctx| WorkspaceView::new(workspace, params.settings.clone(), ctx));
72}
73
74fn quit(_: &(), app: &mut MutableAppContext) {
75 app.platform().quit();
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::{settings, test::*};
82 use gpui::App;
83 use serde_json::json;
84
85 #[test]
86 fn test_open_paths_action() {
87 App::test((), |app| {
88 let settings = settings::channel(&app.font_cache()).unwrap().1;
89
90 init(app);
91
92 let dir = temp_tree(json!({
93 "a": {
94 "aa": null,
95 "ab": null,
96 },
97 "b": {
98 "ba": null,
99 "bb": null,
100 },
101 "c": {
102 "ca": null,
103 "cb": null,
104 },
105 }));
106
107 app.dispatch_global_action(
108 "workspace:open_paths",
109 OpenParams {
110 paths: vec![
111 dir.path().join("a").to_path_buf(),
112 dir.path().join("b").to_path_buf(),
113 ],
114 settings: settings.clone(),
115 },
116 );
117 assert_eq!(app.window_ids().count(), 1);
118
119 app.dispatch_global_action(
120 "workspace:open_paths",
121 OpenParams {
122 paths: vec![dir.path().join("a").to_path_buf()],
123 settings: settings.clone(),
124 },
125 );
126 assert_eq!(app.window_ids().count(), 1);
127 let workspace_view_1 = app
128 .root_view::<WorkspaceView>(app.window_ids().next().unwrap())
129 .unwrap();
130 assert_eq!(
131 workspace_view_1
132 .read(app)
133 .workspace
134 .read(app)
135 .worktrees()
136 .len(),
137 2
138 );
139
140 app.dispatch_global_action(
141 "workspace:open_paths",
142 OpenParams {
143 paths: vec![
144 dir.path().join("b").to_path_buf(),
145 dir.path().join("c").to_path_buf(),
146 ],
147 settings: settings.clone(),
148 },
149 );
150 assert_eq!(app.window_ids().count(), 2);
151 });
152 }
153}