Skip to content

Commit 68e3fd4

Browse files
committed
refactor terminal launchers, add wezterm
1 parent 644394d commit 68e3fd4

File tree

7 files changed

+239
-188
lines changed

7 files changed

+239
-188
lines changed

README.md

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,23 +112,14 @@ local config = {
112112
-- How to run neovim "neovide" or "terminal" (default: neovide)
113113
type = "neovide",
114114

115-
-- path to your neovim or terminal executable (optional)
115+
-- path to your launcher executable (optional)
116116
executable = nil,
117117

118-
-- extra arguments passed to the `executable` (or neovide)
119-
extra_arguments = nil,
118+
-- arguments passed to the `executable` (or neovide)
119+
arguments = nil,
120120

121121
-- choose file based sockets (fsock, unix only) or network based sockets (netsock) or use nil for the default
122122
socket_type = nil,
123-
124-
-- configure how the terminal is run (optional)
125-
terminal = {
126-
-- argument to define how to set the class name of the terminal, usually something like "--class="
127-
class_argument = nil,
128-
129-
-- argument to define how to run neovim, usually "-e"
130-
run_argument = nil,
131-
}
132123
},
133124

134125
debugger = {
@@ -193,6 +184,25 @@ local defold = require "defold"
193184
local root = defold.plugin_root()
194185
```
195186

187+
### Custom terminal
188+
189+
In order to use a custom terminal you have to configure the `launcher` section of the settings:
190+
191+
```lua
192+
{
193+
"atomicptr/defold.nvim",
194+
-- redacted for brevity...
195+
opts = {
196+
-- in this example we configure `wezterm`
197+
launcher = {
198+
type = "terminal",
199+
executable = "/run/current-system/sw/bin/wezterm",
200+
arguments = { "start", "--class={CLASSNAME}", "--", "{NVIM}" },
201+
},
202+
},
203+
}
204+
```
205+
196206
## Available Commands
197207

198208
Here's how you can interact with Defold directly from Neovim:

crates/bridge/src/launcher.rs

Lines changed: 109 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use which::which;
1111
use crate::{
1212
neovide,
1313
plugin_config::{LauncherType, PluginConfig, SocketType},
14+
terminals::{RunArg, Terminal},
1415
utils::{self, is_port_in_use},
1516
};
1617

@@ -21,6 +22,7 @@ const VAR_CLASSNAME: &str = "{CLASSNAME}";
2122
const VAR_ADDRESS: &str = "{ADDR}";
2223
const VAR_LINE: &str = "{LINE}";
2324
const VAR_FILE: &str = "{FILE}";
25+
const VAR_NVIM: &str = "{NVIM}";
2426

2527
#[derive(Debug)]
2628
struct Launcher(PathBuf, Vec<String>);
@@ -32,10 +34,21 @@ impl Launcher {
3234
let exe = self.0;
3335
let args = self.1;
3436

35-
let out = Command::new(exe).args(args).output()?;
37+
let mut cmd = Command::new(exe);
38+
cmd.args(args);
39+
40+
tracing::debug!("Command Run: {cmd:?}");
41+
42+
let out = cmd.output()?;
43+
44+
if !out.stdout.is_empty() {
45+
tracing::debug!("Command Out: {}", String::from_utf8(out.stdout)?);
46+
}
3647

3748
if !out.stderr.is_empty() {
38-
bail!(String::from_utf8(out.stderr)?);
49+
let res = String::from_utf8(out.stderr)?;
50+
tracing::error!("Command Err: {res}");
51+
bail!(res);
3952
}
4053

4154
Ok(())
@@ -59,14 +72,6 @@ impl Launcher {
5972
}
6073
}
6174

62-
const DEFAULT_TERMINALS: [(&str, &str, &str); 5] = [
63-
("alacritty", "--class=", "-e"),
64-
("foot", "--app-id=", "-e"),
65-
("ghostty", "--class=", "-e"),
66-
("kitty", "--class=", "-e"),
67-
("st", "-c=", "-e"),
68-
];
69-
7075
fn create_launcher(cfg: &PluginConfig, nvim: &String) -> Result<Launcher> {
7176
match cfg.launcher_type {
7277
Some(LauncherType::Neovide) => {
@@ -90,9 +95,9 @@ fn create_launcher(cfg: &PluginConfig, nvim: &String) -> Result<Launcher> {
9095

9196
let mut args = Vec::new();
9297

93-
if let Some(extra_args) = &cfg.extra_arguments {
94-
for extra_arg in extra_args {
95-
args.push(extra_arg.clone());
98+
if let Some(exe_args) = &cfg.arguments {
99+
for exe_arg in exe_args {
100+
args.push(exe_arg.clone());
96101
}
97102
}
98103

@@ -120,131 +125,52 @@ fn create_launcher(cfg: &PluginConfig, nvim: &String) -> Result<Launcher> {
120125
Ok(Launcher(executable.clone(), args))
121126
}
122127
Some(LauncherType::Terminal) => {
123-
let executable: Option<PathBuf> = cfg.executable.clone().map(Into::into);
124-
125-
let executable = if let Some(exe) = executable
126-
&& exe.exists()
127-
{
128-
let class_arg = &cfg.terminal_class_argument;
129-
let run_arg = &cfg.terminal_run_argument;
130-
let mut args = Vec::new();
131-
132-
if let Some(extra_args) = &cfg.extra_arguments {
133-
for extra_arg in extra_args {
134-
args.push(extra_arg.clone());
135-
}
136-
}
137-
138-
// only add class on linux
139-
if cfg!(target_os = "linux")
140-
&& let Some(class_arg) = class_arg
141-
{
142-
if class_arg.ends_with('=') {
143-
args.push(class_arg.clone() + VAR_CLASSNAME);
144-
} else {
145-
args.push(class_arg.clone());
146-
args.push(VAR_CLASSNAME.to_string());
147-
}
148-
}
128+
let mut args = Vec::new();
149129

150-
if let Some(run_arg) = run_arg {
151-
if run_arg.ends_with('=') {
152-
args.push(run_arg.clone() + nvim);
153-
} else {
154-
args.push(run_arg.clone());
155-
args.push(nvim.clone());
156-
}
130+
if let Some(exe_args) = &cfg.arguments {
131+
for exe_arg in exe_args {
132+
args.push(exe_arg.clone());
157133
}
158-
159-
args.push("--listen".to_string());
160-
args.push(VAR_ADDRESS.to_string());
161-
162-
args.push("--remote".to_string());
163-
args.push(VAR_LINE.to_string());
164-
args.push(VAR_FILE.to_string());
165-
166-
Some(Launcher(exe, args))
167-
} else {
168-
None
169134
}
170-
.or_else(|| {
171-
let mut args = Vec::new();
172135

173-
if let Some(extra_args) = &cfg.extra_arguments {
174-
for extra_arg in extra_args {
175-
args.push(extra_arg.clone());
176-
}
177-
}
178-
179-
// executable specifies only the name of which terminal we want to use
180-
if let Some(exe_name) = &cfg.executable
181-
&& let Some((name, class_arg, run_arg)) = DEFAULT_TERMINALS
182-
.iter()
183-
.find(|(name, _, _)| *name == exe_name)
184-
&& let Ok(path) = which(name)
185-
{
186-
// only add class on linux
187-
if cfg!(target_os = "linux") {
188-
if class_arg.ends_with('=') {
189-
args.push((*class_arg).to_string() + VAR_CLASSNAME);
190-
} else {
191-
args.push((*class_arg).to_string());
192-
args.push(VAR_CLASSNAME.to_string());
193-
}
194-
}
195-
196-
if run_arg.ends_with('=') {
197-
args.push((*run_arg).to_string() + nvim);
198-
} else {
199-
args.push((*run_arg).to_string());
200-
args.push((*nvim).clone());
201-
}
136+
if let Some(executable) = &cfg.executable.clone().map(PathBuf::from)
137+
&& executable.is_absolute()
138+
&& executable.exists()
139+
{
140+
let term = Terminal {
141+
executable: cfg.executable.clone().unwrap(),
142+
arguments: Vec::new(),
143+
run_arg: None,
144+
class_arg: None,
145+
};
146+
147+
tracing::debug!("Terminal specified by absolute path {term:?}");
148+
149+
return make_launcher_from_terminal(&term, args, nvim)
150+
.context(ERR_TERMINAL_NOT_FOUND);
151+
} else if let Some(exe_name) = &cfg.executable
152+
&& let Some(term) = Terminal::find_by_name(exe_name)
153+
&& term.find_executable().is_some()
154+
{
155+
tracing::debug!("Looking for terminal by name {exe_name} found {term:?}");
202156

203-
args.push("--listen".to_string());
204-
args.push(VAR_ADDRESS.to_string());
157+
// executable specifies only the name o f which terminal we want to use
158+
return make_launcher_from_terminal(&term, args, nvim)
159+
.context(ERR_TERMINAL_NOT_FOUND);
160+
}
205161

206-
args.push("--remote".to_string());
207-
args.push(VAR_LINE.to_string());
208-
args.push(VAR_FILE.to_string());
162+
tracing::debug!(
163+
"No terminal specific terminal specified or not found, looking for available one..."
164+
);
209165

210-
return Some(Launcher(path, args));
211-
}
166+
if let Some(term) = Terminal::find_available() {
167+
tracing::debug!("Found {term:?}");
212168

213-
// try finding one of our supported default terminals
214-
for (name, class_arg, run_arg) in &DEFAULT_TERMINALS {
215-
if let Ok(path) = which(name) {
216-
// only add class on linux
217-
if cfg!(target_os = "linux") {
218-
if class_arg.ends_with('=') {
219-
args.push((*class_arg).to_string() + VAR_CLASSNAME);
220-
} else {
221-
args.push((*class_arg).to_string());
222-
args.push(VAR_CLASSNAME.to_string());
223-
}
224-
}
225-
226-
if run_arg.ends_with('=') {
227-
args.push((*run_arg).to_string() + nvim);
228-
} else {
229-
args.push((*run_arg).to_string());
230-
args.push((*nvim).clone());
231-
}
232-
233-
args.push("--listen".to_string());
234-
args.push(VAR_ADDRESS.to_string());
235-
236-
args.push("--remote".to_string());
237-
args.push(VAR_LINE.to_string());
238-
args.push(VAR_FILE.to_string());
239-
240-
return Some(Launcher(path, args));
241-
}
242-
}
243-
None
244-
})
245-
.context(ERR_TERMINAL_NOT_FOUND)?;
169+
return make_launcher_from_terminal(&term, args, nvim)
170+
.context(ERR_TERMINAL_NOT_FOUND);
171+
}
246172

247-
Ok(executable)
173+
bail!(ERR_TERMINAL_NOT_FOUND);
248174
}
249175
None => {
250176
if let Ok(launcher) = create_launcher(
@@ -272,6 +198,57 @@ fn create_launcher(cfg: &PluginConfig, nvim: &String) -> Result<Launcher> {
272198
}
273199
}
274200

201+
fn make_launcher_from_terminal(
202+
term: &Terminal,
203+
mut args: Vec<String>,
204+
nvim: &String,
205+
) -> Option<Launcher> {
206+
let exe_path = term.find_executable()?;
207+
208+
// prepend our arguments
209+
for arg in term.arguments.iter().rev() {
210+
args.insert(0, arg.clone());
211+
}
212+
213+
// only add class on linux
214+
if cfg!(target_os = "linux")
215+
&& let Some(class_arg) = &term.class_arg
216+
{
217+
if class_arg.ends_with('=') {
218+
args.push((*class_arg).clone() + VAR_CLASSNAME);
219+
} else {
220+
args.push((*class_arg).clone());
221+
args.push(VAR_CLASSNAME.to_string());
222+
}
223+
}
224+
225+
if let Some(run_arg) = &term.run_arg {
226+
match run_arg {
227+
RunArg::Arg(run_arg) => {
228+
if run_arg.ends_with('=') {
229+
args.push((*run_arg).clone() + nvim);
230+
} else {
231+
args.push((*run_arg).clone());
232+
args.push((*nvim).clone());
233+
}
234+
}
235+
RunArg::End => {
236+
args.push("--".to_string());
237+
args.push(nvim.clone());
238+
}
239+
}
240+
}
241+
242+
args.push("--listen".to_string());
243+
args.push(VAR_ADDRESS.to_string());
244+
245+
args.push("--remote".to_string());
246+
args.push(VAR_LINE.to_string());
247+
args.push(VAR_FILE.to_string());
248+
249+
Some(Launcher(exe_path, args))
250+
}
251+
275252
fn nvim_open_file_remote(nvim: &str, server: &str, file: &str, line: Option<usize>) -> Result<()> {
276253
let remote_cmd = if let Some(line) = line {
277254
format!("+{line} {file}")
@@ -421,7 +398,9 @@ pub fn run(
421398
launcher.filter_params(|s| s != VAR_LINE)
422399
};
423400

424-
let launcher = launcher.apply_var(VAR_FILE, file_str);
401+
let launcher = launcher
402+
.apply_var(VAR_FILE, file_str)
403+
.apply_var(VAR_NVIM, &nvim);
425404

426405
match plugin_config.socket_type {
427406
Some(SocketType::Fsock) => run_fsock(launcher, &nvim, &root_dir, file_str, line)?,

0 commit comments

Comments
 (0)