vtcode_core/terminal_setup/features/
multiline.rs1use crate::terminal_setup::detector::TerminalType;
7use anyhow::Result;
8
9pub fn generate_config(terminal_type: TerminalType) -> Result<String> {
11 let config = match terminal_type {
12 TerminalType::Ghostty => generate_ghostty_config(),
13 TerminalType::Kitty => generate_kitty_config(),
14 TerminalType::Alacritty => generate_alacritty_config(),
15 TerminalType::WezTerm => generate_wezterm_config(),
16 TerminalType::TerminalApp => generate_terminal_app_instructions(),
17 TerminalType::Xterm => generate_xterm_instructions(),
18 TerminalType::Zed => generate_zed_config(),
19 TerminalType::Warp => {
20 String::new()
22 }
23 TerminalType::ITerm2 => generate_iterm2_instructions(),
24 TerminalType::VSCode => generate_vscode_instructions(),
25 TerminalType::WindowsTerminal => generate_windows_terminal_config(),
26 TerminalType::Hyper => generate_hyper_config(),
27 TerminalType::Tabby => generate_tabby_config(),
28 TerminalType::Unknown => {
29 anyhow::bail!("Cannot generate multiline config for unknown terminal")
30 }
31 };
32
33 Ok(config)
34}
35
36fn generate_wezterm_config() -> String {
38 r#"keys = {
39 { key = "Enter", mods = "SHIFT", action = wezterm.action.SendString("\n") },
40}
41"#
42 .to_string()
43}
44
45fn generate_terminal_app_instructions() -> String {
47 r#"Terminal.app uses profile key mappings.
48Add Shift+Enter mapping to send \n in your active profile."#
49 .to_string()
50}
51
52fn generate_xterm_instructions() -> String {
54 r#"xterm multiline can be configured through X resources or window manager key mapping.
55Ensure Shift+Enter sends a newline sequence."#
56 .to_string()
57}
58
59fn generate_ghostty_config() -> String {
61 "keybind = shift+enter=text:\\n".to_string()
62}
63
64fn generate_kitty_config() -> String {
66 "map shift+enter send_text all \\n".to_string()
67}
68
69fn generate_alacritty_config() -> String {
71 r#"[[keyboard.bindings]]
72key = "Return"
73mods = "Shift"
74chars = "\n"
75"#
76 .to_string()
77}
78
79fn generate_zed_config() -> String {
81 r#"{
82 "bindings": {
83 "shift-enter": "editor::Newline"
84 }
85}
86"#
87 .to_string()
88}
89
90fn generate_windows_terminal_config() -> String {
92 r#"{
93 "actions": [
94 {
95 "command": {
96 "action": "sendInput",
97 "input": "\n"
98 },
99 "keys": "shift+enter"
100 }
101 ]
102}
103"#
104 .to_string()
105}
106
107fn generate_hyper_config() -> String {
109 r#"// In your .hyper.js config:
110module.exports = {
111 config: {
112 // ... other config
113 },
114 keymaps: {
115 'window:devtools': 'cmd+alt+i',
116 'window:reload': 'cmd+shift+r',
117 'tab:new': 'cmd+t',
118 'shift+enter': 'editor:newline'
119 }
120}
121"#
122 .to_string()
123}
124
125fn generate_tabby_config() -> String {
127 r#"hotkeys:
128 multiline-input:
129 - Shift-Enter
130terminal:
131 sendInputOnEnter: true
132"#
133 .to_string()
134}
135
136fn generate_iterm2_instructions() -> String {
138 r#"iTerm2 Manual Setup Instructions:
139
1401. Open iTerm2 Preferences (Cmd+,)
1412. Go to Profiles → Keys
1423. Click the "+" button to add a new key mapping
1434. Press Shift+Enter when prompted
1445. Set Action to "Send Text"
1456. Enter "\n" (without quotes) in the text field
1467. Click OK to save
147
148This will bind Shift+Enter to insert a newline character.
149"#
150 .to_string()
151}
152
153fn generate_vscode_instructions() -> String {
155 r#"VS Code Terminal Manual Setup:
156
157Add this to your keybindings.json (Cmd+K Cmd+S to open):
158
159{
160 "key": "shift+enter",
161 "command": "workbench.action.terminal.sendSequence",
162 "when": "terminalFocus",
163 "args": { "text": "\n" }
164}
165
166Or use the UI:
1671. Open Command Palette (Cmd+Shift+P)
1682. Search for "Preferences: Open Keyboard Shortcuts (JSON)"
1693. Add the keybinding above to the array
170"#
171 .to_string()
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_generate_ghostty_config() {
180 let config = generate_config(TerminalType::Ghostty).unwrap();
181 assert!(config.contains("keybind"));
182 assert!(config.contains("shift+enter"));
183 }
184
185 #[test]
186 fn test_generate_kitty_config() {
187 let config = generate_config(TerminalType::Kitty).unwrap();
188 assert!(config.contains("map shift+enter"));
189 assert!(config.contains("send_text"));
190 }
191
192 #[test]
193 fn test_generate_alacritty_config() {
194 let config = generate_config(TerminalType::Alacritty).unwrap();
195 assert!(config.contains("keyboard.bindings"));
196 assert!(config.contains("Return"));
197 assert!(config.contains("Shift"));
198 }
199
200 #[test]
201 fn test_generate_windows_terminal_config() {
202 let config = generate_config(TerminalType::WindowsTerminal).unwrap();
203 assert!(config.contains("sendInput"));
204 assert!(config.contains("shift+enter"));
205 }
206
207 #[test]
208 fn test_warp_no_config_needed() {
209 let config = generate_config(TerminalType::Warp).unwrap();
210 assert!(config.is_empty());
211 }
212
213 #[test]
214 fn test_iterm2_instructions() {
215 let config = generate_config(TerminalType::ITerm2).unwrap();
216 assert!(config.contains("Manual Setup"));
217 assert!(config.contains("Preferences"));
218 }
219
220 #[test]
221 fn test_unknown_terminal_error() {
222 let result = generate_config(TerminalType::Unknown);
223 result.unwrap_err();
224 }
225}