cli.rs

 1use anyhow::Result;
 2use collections::HashMap;
 3pub use ipc_channel::ipc;
 4use serde::{Deserialize, Serialize};
 5
 6#[derive(Serialize, Deserialize)]
 7pub struct IpcHandshake {
 8    pub requests: ipc::IpcSender<CliRequest>,
 9    pub responses: ipc::IpcReceiver<CliResponse>,
10}
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum CliOpenBehavior {
15    ExistingWindow,
16    NewWindow,
17}
18
19#[derive(Debug, Serialize, Deserialize)]
20pub enum CliRequest {
21    Open {
22        paths: Vec<String>,
23        urls: Vec<String>,
24        diff_paths: Vec<[String; 2]>,
25        diff_all: bool,
26        wsl: Option<String>,
27        wait: bool,
28        open_new_workspace: Option<bool>,
29        #[serde(default)]
30        force_existing_window: bool,
31        reuse: bool,
32        env: Option<HashMap<String, String>>,
33        user_data_dir: Option<String>,
34        dev_container: bool,
35    },
36    SetOpenBehavior {
37        behavior: CliOpenBehavior,
38    },
39}
40
41#[derive(Debug, Serialize, Deserialize)]
42pub enum CliResponse {
43    Ping,
44    Stdout { message: String },
45    Stderr { message: String },
46    Exit { status: i32 },
47    PromptOpenBehavior,
48}
49
50/// When Zed started not as an *.app but as a binary (e.g. local development),
51/// there's a possibility to tell it to behave "regularly".
52///
53/// Note that in the main zed binary, this variable is unset after it's read for the first time,
54/// therefore it should always be accessed through the `FORCE_CLI_MODE` static.
55pub const FORCE_CLI_MODE_ENV_VAR_NAME: &str = "ZED_FORCE_CLI_MODE";
56
57/// Abstracts the transport for sending CLI responses (Zed → CLI).
58///
59/// Production code uses `IpcSender<CliResponse>`. Tests can provide in-memory
60/// implementations to avoid OS-level IPC.
61pub trait CliResponseSink: Send + 'static {
62    fn send(&self, response: CliResponse) -> Result<()>;
63}
64
65impl CliResponseSink for ipc::IpcSender<CliResponse> {
66    fn send(&self, response: CliResponse) -> Result<()> {
67        ipc::IpcSender::send(self, response).map_err(|error| anyhow::anyhow!("{error}"))
68    }
69}