1mod assets;
2mod only_instance;
3mod open_listener;
4
5pub use assets::*;
6use client2::{Client, UserStore};
7use gpui2::{AsyncAppContext, Handle};
8pub use only_instance::*;
9pub use open_listener::*;
10
11use anyhow::{Context, Result};
12use cli::{
13 ipc::{self, IpcSender},
14 CliRequest, CliResponse, IpcHandshake,
15};
16use futures::{channel::mpsc, SinkExt, StreamExt};
17use std::{sync::Arc, thread};
18
19pub fn connect_to_cli(
20 server_name: &str,
21) -> Result<(mpsc::Receiver<CliRequest>, IpcSender<CliResponse>)> {
22 let handshake_tx = cli::ipc::IpcSender::<IpcHandshake>::connect(server_name.to_string())
23 .context("error connecting to cli")?;
24 let (request_tx, request_rx) = ipc::channel::<CliRequest>()?;
25 let (response_tx, response_rx) = ipc::channel::<CliResponse>()?;
26
27 handshake_tx
28 .send(IpcHandshake {
29 requests: request_tx,
30 responses: response_rx,
31 })
32 .context("error sending ipc handshake")?;
33
34 let (mut async_request_tx, async_request_rx) =
35 futures::channel::mpsc::channel::<CliRequest>(16);
36 thread::spawn(move || {
37 while let Ok(cli_request) = request_rx.recv() {
38 if smol::block_on(async_request_tx.send(cli_request)).is_err() {
39 break;
40 }
41 }
42 Ok::<_, anyhow::Error>(())
43 });
44
45 Ok((async_request_rx, response_tx))
46}
47
48pub struct AppState {
49 pub client: Arc<Client>,
50 pub user_store: Handle<UserStore>,
51}
52
53pub async fn handle_cli_connection(
54 (mut requests, _responses): (mpsc::Receiver<CliRequest>, IpcSender<CliResponse>),
55 _app_state: Arc<AppState>,
56 mut _cx: AsyncAppContext,
57) {
58 if let Some(request) = requests.next().await {
59 match request {
60 CliRequest::Open { paths: _, wait: _ } => {
61 // let mut caret_positions = HashMap::new();
62
63 // let paths = if paths.is_empty() {
64 // todo!()
65 // workspace::last_opened_workspace_paths()
66 // .await
67 // .map(|location| location.paths().to_vec())
68 // .unwrap_or_default()
69 // } else {
70 // paths
71 // .into_iter()
72 // .filter_map(|path_with_position_string| {
73 // let path_with_position = PathLikeWithPosition::parse_str(
74 // &path_with_position_string,
75 // |path_str| {
76 // Ok::<_, std::convert::Infallible>(
77 // Path::new(path_str).to_path_buf(),
78 // )
79 // },
80 // )
81 // .expect("Infallible");
82 // let path = path_with_position.path_like;
83 // if let Some(row) = path_with_position.row {
84 // if path.is_file() {
85 // let row = row.saturating_sub(1);
86 // let col =
87 // path_with_position.column.unwrap_or(0).saturating_sub(1);
88 // caret_positions.insert(path.clone(), Point::new(row, col));
89 // }
90 // }
91 // Some(path)
92 // })
93 // .collect()
94 // };
95
96 // let mut errored = false;
97 // todo!("workspace")
98 // match cx
99 // .update(|cx| workspace::open_paths(&paths, &app_state, None, cx))
100 // .await
101 // {
102 // Ok((workspace, items)) => {
103 // let mut item_release_futures = Vec::new();
104
105 // for (item, path) in items.into_iter().zip(&paths) {
106 // match item {
107 // Some(Ok(item)) => {
108 // if let Some(point) = caret_positions.remove(path) {
109 // if let Some(active_editor) = item.downcast::<Editor>() {
110 // active_editor
111 // .downgrade()
112 // .update(&mut cx, |editor, cx| {
113 // let snapshot =
114 // editor.snapshot(cx).display_snapshot;
115 // let point = snapshot
116 // .buffer_snapshot
117 // .clip_point(point, Bias::Left);
118 // editor.change_selections(
119 // Some(Autoscroll::center()),
120 // cx,
121 // |s| s.select_ranges([point..point]),
122 // );
123 // })
124 // .log_err();
125 // }
126 // }
127
128 // let released = oneshot::channel();
129 // cx.update(|cx| {
130 // item.on_release(
131 // cx,
132 // Box::new(move |_| {
133 // let _ = released.0.send(());
134 // }),
135 // )
136 // .detach();
137 // });
138 // item_release_futures.push(released.1);
139 // }
140 // Some(Err(err)) => {
141 // responses
142 // .send(CliResponse::Stderr {
143 // message: format!("error opening {:?}: {}", path, err),
144 // })
145 // .log_err();
146 // errored = true;
147 // }
148 // None => {}
149 // }
150 // }
151
152 // if wait {
153 // let background = cx.background();
154 // let wait = async move {
155 // if paths.is_empty() {
156 // let (done_tx, done_rx) = oneshot::channel();
157 // if let Some(workspace) = workspace.upgrade(&cx) {
158 // let _subscription = cx.update(|cx| {
159 // cx.observe_release(&workspace, move |_, _| {
160 // let _ = done_tx.send(());
161 // })
162 // });
163 // drop(workspace);
164 // let _ = done_rx.await;
165 // }
166 // } else {
167 // let _ =
168 // futures::future::try_join_all(item_release_futures).await;
169 // };
170 // }
171 // .fuse();
172 // futures::pin_mut!(wait);
173
174 // loop {
175 // // Repeatedly check if CLI is still open to avoid wasting resources
176 // // waiting for files or workspaces to close.
177 // let mut timer = background.timer(Duration::from_secs(1)).fuse();
178 // futures::select_biased! {
179 // _ = wait => break,
180 // _ = timer => {
181 // if responses.send(CliResponse::Ping).is_err() {
182 // break;
183 // }
184 // }
185 // }
186 // }
187 // }
188 // }
189 // Err(error) => {
190 // errored = true;
191 // responses
192 // .send(CliResponse::Stderr {
193 // message: format!("error opening {:?}: {}", paths, error),
194 // })
195 // .log_err();
196 // }
197 // }
198
199 // responses
200 // .send(CliResponse::Exit {
201 // status: i32::from(errored),
202 // })
203 // .log_err();
204 }
205 }
206 }
207}