Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use anyhow::bail;
use helix_config::*;
use serde::{Deserialize, Serialize};

options! {
    struct DebugAdapterConfig {
        #[name = "debugger.name"]
        name: Option<String> = None,
        #[name = "debugger.transport"]
        #[read = copy]
        transport: Transport = Transport::Stdio,
        #[name = "debugger.command"]
        #[read = deref]
        command: String = "",
        #[name = "debugger.args"]
        #[read = deref]
        args: List<String> = List::default(),
        #[name = "debugger.port-arg"]
        #[read = deref]
        port_arg: String = "",
        #[name = "debugger.templates"]
        #[read = deref]
        templates: List<DebugTemplate> = List::default(),
        #[name = "debugger.quirks.absolut-path"]
        #[read = copy]
        absolut_path: bool = false,
        #[name = "terminal.command"]
        terminal_command: Option<String> = get_terminal_provider().map(|term| term.command),
        #[name = "terminal.args"]
        #[read = deref]
        terminal_args: List<String> = get_terminal_provider().map(|term| term.args.into_boxed_slice()).unwrap_or_default(),
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Transport {
    Stdio,
    Tcp,
}

impl Ty for Transport {
    fn from_value(val: Value) -> anyhow::Result<Self> {
        match &*String::from_value(val)? {
            "stdio" => Ok(Transport::Stdio),
            "tcp" => Ok(Transport::Tcp),
            val => bail!("expected 'stdio' or 'tcp' (got {val:?})"),
        }
    }
    fn to_value(&self) -> Value {
        match self {
            Transport::Stdio => "stdio".into(),
            Transport::Tcp => "tcp".into(),
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(untagged)]
pub enum DebugArgumentValue {
    String(String),
    Array(Vec<String>),
    Boolean(bool),
}

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct AdvancedCompletion {
    pub name: Option<String>,
    pub completion: Option<String>,
    pub default: Option<String>,
}

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case", untagged)]
pub enum DebugConfigCompletion {
    Named(String),
    Advanced(AdvancedCompletion),
}

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct DebugTemplate {
    pub name: String,
    pub request: String,
    pub completion: Vec<DebugConfigCompletion>,
    pub args: Map<DebugArgumentValue>,
}

// TODO: integrate this better with the new config system (less nesting)
// the best way to do that is probably a rewrite. I think these templates
// are probably overkill here. This may be easier to solve by moving the logic
// to scheme
config_serde_adapter!(DebugTemplate);

#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
pub struct TerminalConfig {
    pub command: String,
    #[serde(default)]
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub args: Vec<String>,
}

#[cfg(windows)]
pub fn get_terminal_provider() -> Option<TerminalConfig> {
    use helix_config::env::binary_exists;

    if binary_exists("wt") {
        return Some(TerminalConfig {
            command: "wt".into(),
            args: vec![
                "new-tab".into(),
                "--title".into(),
                "DEBUG".into(),
                "cmd".into(),
                "/C".into(),
            ],
        });
    }

    Some(TerminalConfig {
        command: "conhost".into(),
        args: vec!["cmd".into(), "/C".into()],
    })
}

#[cfg(not(any(windows, target_os = "wasm32")))]
fn get_terminal_provider() -> Option<TerminalConfig> {
    use helix_config::env::{binary_exists, env_var_is_set};

    if env_var_is_set("TMUX") && binary_exists("tmux") {
        return Some(TerminalConfig {
            command: "tmux".into(),
            args: vec!["split-window".into()],
        });
    }

    if env_var_is_set("WEZTERM_UNIX_SOCKET") && binary_exists("wezterm") {
        return Some(TerminalConfig {
            command: "wezterm".into(),
            args: vec!["cli".into(), "split-pane".into()],
        });
    }

    None
}