@@ -10,7 +10,7 @@ use helix_core::{
10 movement::{self, Direction},
10 movement::{self, Direction},
11 object, pos_at_coords,
11 object, pos_at_coords,
12 regex::{self, Regex, RegexBuilder},
12 regex::{self, Regex, RegexBuilder},
13− search, selection, surround, textobject,
13+ search, selection, shellwords, surround, textobject,
14 unicode::width::UnicodeWidthChar,
14 unicode::width::UnicodeWidthChar,
15 LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril,
15 LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril,
16 Transaction,
16 Transaction,
@@ -173,14 +173,14 @@ impl MappableCommand {
173 pub fn execute(&self, cx: &mut Context) {
173 pub fn execute(&self, cx: &mut Context) {
174 match &self {
174 match &self {
175 MappableCommand::Typable { name, args, doc: _ } => {
175 MappableCommand::Typable { name, args, doc: _ } => {
176− let args: Vec<&str> = args.iter().map(|arg| arg.as_str()).collect();
176+ let args: Vec<Cow<str>> = args.iter().map(Cow::from).collect();
177 if let Some(command) = cmd::TYPABLE_COMMAND_MAP.get(name.as_str()) {
177 if let Some(command) = cmd::TYPABLE_COMMAND_MAP.get(name.as_str()) {
178 let mut cx = compositor::Context {
178 let mut cx = compositor::Context {
179 editor: cx.editor,
179 editor: cx.editor,
180 jobs: cx.jobs,
180 jobs: cx.jobs,
181 scroll: None,
181 scroll: None,
183− if let Err(e) = (command.fun)(&mut cx, &args, PromptEvent::Validate) {
183+ if let Err(e) = (command.fun)(&mut cx, &args[..], PromptEvent::Validate) {
184 cx.editor.set_error(format!("{}", e));
184 cx.editor.set_error(format!("{}", e));
@@ -1963,13 +1963,13 @@ pub mod cmd {
1963 pub aliases: &'static [&'static str],
1963 pub aliases: &'static [&'static str],
1964 pub doc: &'static str,
1964 pub doc: &'static str,
1965 // params, flags, helper, completer
1965 // params, flags, helper, completer
1966− pub fun: fn(&mut compositor::Context, &[&str], PromptEvent) -> anyhow::Result<()>,
1966+ pub fun: fn(&mut compositor::Context, &[Cow<str>], PromptEvent) -> anyhow::Result<()>,
1967 pub completer: Option<Completer>,
1967 pub completer: Option<Completer>,
1970 fn quit(
1970 fn quit(
1971 cx: &mut compositor::Context,
1971 cx: &mut compositor::Context,
1972− _args: &[&str],
1972+ _args: &[Cow<str>],
1973 _event: PromptEvent,
1973 _event: PromptEvent,
1974 ) -> anyhow::Result<()> {
1974 ) -> anyhow::Result<()> {
1975 // last view and we have unsaved changes
1975 // last view and we have unsaved changes
@@ -1984,7 +1984,7 @@ pub mod cmd {
1985 fn force_quit(
1985 fn force_quit(
1986 cx: &mut compositor::Context,
1986 cx: &mut compositor::Context,
1987− _args: &[&str],
1987+ _args: &[Cow<str>],
1988 _event: PromptEvent,
1988 _event: PromptEvent,
1989 ) -> anyhow::Result<()> {
1989 ) -> anyhow::Result<()> {
1990 cx.editor.close(view!(cx.editor).id);
1990 cx.editor.close(view!(cx.editor).id);
@@ -1994,17 +1994,19 @@ pub mod cmd {
1995 fn open(
1995 fn open(
1996 cx: &mut compositor::Context,
1996 cx: &mut compositor::Context,
1997− args: &[&str],
1997+ args: &[Cow<str>],
1998 _event: PromptEvent,
1998 _event: PromptEvent,
1999 ) -> anyhow::Result<()> {
1999 ) -> anyhow::Result<()> {
2000− let path = args.get(0).context("wrong argument count")?;
2000+ ensure!(!args.is_empty(), "wrong argument count");
2001− let _ = cx.editor.open(path.into(), Action::Replace)?;
2002+ let _ = cx.editor.open(arg.as_ref().into(), Action::Replace)?;
2005 fn buffer_close(
2007 fn buffer_close(
2006 cx: &mut compositor::Context,
2008 cx: &mut compositor::Context,
2007− _args: &[&str],
2009+ _args: &[Cow<str>],
2008 _event: PromptEvent,
2010 _event: PromptEvent,
2009 ) -> anyhow::Result<()> {
2011 ) -> anyhow::Result<()> {
2010 let view = view!(cx.editor);
2012 let view = view!(cx.editor);
@@ -2015,7 +2017,7 @@ pub mod cmd {
2016 fn force_buffer_close(
2018 fn force_buffer_close(
2017 cx: &mut compositor::Context,
2019 cx: &mut compositor::Context,
2018− _args: &[&str],
2020+ _args: &[Cow<str>],
2019 _event: PromptEvent,
2021 _event: PromptEvent,
2020 ) -> anyhow::Result<()> {
2022 ) -> anyhow::Result<()> {
2021 let view = view!(cx.editor);
2023 let view = view!(cx.editor);
@@ -2024,15 +2026,12 @@ pub mod cmd {
2027− fn write_impl<P: AsRef<Path>>(
2028− cx: &mut compositor::Context,
2029+ fn write_impl(cx: &mut compositor::Context, path: Option<&Cow<str>>) -> anyhow::Result<()> {
2030− ) -> anyhow::Result<()> {
2031 let jobs = &mut cx.jobs;
2030 let jobs = &mut cx.jobs;
2032 let (_, doc) = current!(cx.editor);
2031 let (_, doc) = current!(cx.editor);
2034 if let Some(ref path) = path {
2033 if let Some(ref path) = path {
2035− doc.set_path(Some(path.as_ref()))
2034+ doc.set_path(Some(path.as_ref().as_ref()))
2036 .context("invalid filepath")?;
2035 .context("invalid filepath")?;
2038 if doc.path().is_none() {
2037 if doc.path().is_none() {
@@ -2061,7 +2060,7 @@ pub mod cmd {
2062 fn write(
2061 fn write(
2063 cx: &mut compositor::Context,
2062 cx: &mut compositor::Context,
2064− args: &[&str],
2063+ args: &[Cow<str>],
2065 _event: PromptEvent,
2064 _event: PromptEvent,
2066 ) -> anyhow::Result<()> {
2065 ) -> anyhow::Result<()> {
2067 write_impl(cx, args.first())
2066 write_impl(cx, args.first())
@@ -2069,7 +2068,7 @@ pub mod cmd {
2070 fn new_file(
2069 fn new_file(
2071 cx: &mut compositor::Context,
2070 cx: &mut compositor::Context,
2072− _args: &[&str],
2071+ _args: &[Cow<str>],
2073 _event: PromptEvent,
2072 _event: PromptEvent,
2074 ) -> anyhow::Result<()> {
2073 ) -> anyhow::Result<()> {
2075 cx.editor.new_file(Action::Replace);
2074 cx.editor.new_file(Action::Replace);
@@ -2079,7 +2078,7 @@ pub mod cmd {
2080 fn format(
2079 fn format(
2081 cx: &mut compositor::Context,
2080 cx: &mut compositor::Context,
2082− _args: &[&str],
2081+ _args: &[Cow<str>],
2083 _event: PromptEvent,
2082 _event: PromptEvent,
2084 ) -> anyhow::Result<()> {
2083 ) -> anyhow::Result<()> {
2085 let (_, doc) = current!(cx.editor);
2084 let (_, doc) = current!(cx.editor);
@@ -2094,7 +2093,7 @@ pub mod cmd {
2095 fn set_indent_style(
2094 fn set_indent_style(
2096 cx: &mut compositor::Context,
2095 cx: &mut compositor::Context,
2097− args: &[&str],
2096+ args: &[Cow<str>],
2098 _event: PromptEvent,
2097 _event: PromptEvent,
2099 ) -> anyhow::Result<()> {
2098 ) -> anyhow::Result<()> {
2100 use IndentStyle::*;
2099 use IndentStyle::*;
@@ -2114,7 +2113,7 @@ pub mod cmd {
2114 // Attempt to parse argument as an indent style.
2113 // Attempt to parse argument as an indent style.
2115 let style = match args.get(0) {
2114 let style = match args.get(0) {
2116 Some(arg) if "tabs".starts_with(&arg.to_lowercase()) => Some(Tabs),
2115 Some(arg) if "tabs".starts_with(&arg.to_lowercase()) => Some(Tabs),
2117− Some(&"0") => Some(Tabs),
2116+ Some(Cow::Borrowed("0")) => Some(Tabs),
2118 Some(arg) => arg
2117 Some(arg) => arg
2119 .parse::<u8>()
2118 .parse::<u8>()
@@ -2133,7 +2132,7 @@ pub mod cmd {
2133 /// Sets or reports the current document's line ending setting.
2132 /// Sets or reports the current document's line ending setting.
2134 fn set_line_ending(
2133 fn set_line_ending(
2135 cx: &mut compositor::Context,
2134 cx: &mut compositor::Context,
2136− args: &[&str],
2135+ args: &[Cow<str>],
2137 _event: PromptEvent,
2136 _event: PromptEvent,
2138 ) -> anyhow::Result<()> {
2137 ) -> anyhow::Result<()> {
2139 use LineEnding::*;
2138 use LineEnding::*;
@@ -2177,7 +2176,7 @@ pub mod cmd {
2178 fn earlier(
2177 fn earlier(
2179 cx: &mut compositor::Context,
2178 cx: &mut compositor::Context,
2180− args: &[&str],
2179+ args: &[Cow<str>],
2181 _event: PromptEvent,
2180 _event: PromptEvent,
2182 ) -> anyhow::Result<()> {
2181 ) -> anyhow::Result<()> {
2183 let uk = args.join(" ").parse::<UndoKind>().map_err(|s| anyhow!(s))?;
2182 let uk = args.join(" ").parse::<UndoKind>().map_err(|s| anyhow!(s))?;
@@ -2193,7 +2192,7 @@ pub mod cmd {
2194 fn later(
2193 fn later(
2195 cx: &mut compositor::Context,
2194 cx: &mut compositor::Context,
2196− args: &[&str],
2195+ args: &[Cow<str>],
2197 _event: PromptEvent,
2196 _event: PromptEvent,
2198 ) -> anyhow::Result<()> {
2197 ) -> anyhow::Result<()> {
2199 let uk = args.join(" ").parse::<UndoKind>().map_err(|s| anyhow!(s))?;
2198 let uk = args.join(" ").parse::<UndoKind>().map_err(|s| anyhow!(s))?;
@@ -2208,7 +2207,7 @@ pub mod cmd {
2209 fn write_quit(
2208 fn write_quit(
2210 cx: &mut compositor::Context,
2209 cx: &mut compositor::Context,
2211− args: &[&str],
2210+ args: &[Cow<str>],
2212 event: PromptEvent,
2211 event: PromptEvent,
2213 ) -> anyhow::Result<()> {
2212 ) -> anyhow::Result<()> {
2214 write_impl(cx, args.first())?;
2213 write_impl(cx, args.first())?;
@@ -2217,7 +2216,7 @@ pub mod cmd {
2218 fn force_write_quit(
2217 fn force_write_quit(
2219 cx: &mut compositor::Context,
2218 cx: &mut compositor::Context,
2220− args: &[&str],
2219+ args: &[Cow<str>],
2221 event: PromptEvent,
2220 event: PromptEvent,
2222 ) -> anyhow::Result<()> {
2221 ) -> anyhow::Result<()> {
2223 write_impl(cx, args.first())?;
2222 write_impl(cx, args.first())?;
@@ -2248,7 +2247,7 @@ pub mod cmd {
2249 fn write_all_impl(
2248 fn write_all_impl(
2250 cx: &mut compositor::Context,
2249 cx: &mut compositor::Context,
2251− _args: &[&str],
2250+ _args: &[Cow<str>],
2252 _event: PromptEvent,
2251 _event: PromptEvent,
2253 quit: bool,
2252 quit: bool,
2254 force: bool,
2253 force: bool,
@@ -2284,7 +2283,7 @@ pub mod cmd {
2285 fn write_all(
2284 fn write_all(
2286 cx: &mut compositor::Context,
2285 cx: &mut compositor::Context,
2287− args: &[&str],
2286+ args: &[Cow<str>],
2288 event: PromptEvent,
2287 event: PromptEvent,
2289 ) -> anyhow::Result<()> {
2288 ) -> anyhow::Result<()> {
2290 write_all_impl(cx, args, event, false, false)
2289 write_all_impl(cx, args, event, false, false)
@@ -2292,7 +2291,7 @@ pub mod cmd {
2293 fn write_all_quit(
2292 fn write_all_quit(
2294 cx: &mut compositor::Context,
2293 cx: &mut compositor::Context,
2295− args: &[&str],
2294+ args: &[Cow<str>],
2296 event: PromptEvent,
2295 event: PromptEvent,
2297 ) -> anyhow::Result<()> {
2296 ) -> anyhow::Result<()> {
2298 write_all_impl(cx, args, event, true, false)
2297 write_all_impl(cx, args, event, true, false)
@@ -2300,7 +2299,7 @@ pub mod cmd {
2301 fn force_write_all_quit(
2300 fn force_write_all_quit(
2302 cx: &mut compositor::Context,
2301 cx: &mut compositor::Context,
2303− args: &[&str],
2302+ args: &[Cow<str>],
2304 event: PromptEvent,
2303 event: PromptEvent,
2305 ) -> anyhow::Result<()> {
2304 ) -> anyhow::Result<()> {
2306 write_all_impl(cx, args, event, true, true)
2305 write_all_impl(cx, args, event, true, true)
@@ -2308,7 +2307,7 @@ pub mod cmd {
2309 fn quit_all_impl(
2308 fn quit_all_impl(
2310 editor: &mut Editor,
2309 editor: &mut Editor,
2311− _args: &[&str],
2310+ _args: &[Cow<str>],
2312 _event: PromptEvent,
2311 _event: PromptEvent,
2313 force: bool,
2312 force: bool,
2314 ) -> anyhow::Result<()> {
2313 ) -> anyhow::Result<()> {
@@ -2327,7 +2326,7 @@ pub mod cmd {
2328 fn quit_all(
2327 fn quit_all(
2329 cx: &mut compositor::Context,
2328 cx: &mut compositor::Context,
2330− args: &[&str],
2329+ args: &[Cow<str>],
2331 event: PromptEvent,
2330 event: PromptEvent,
2332 ) -> anyhow::Result<()> {
2331 ) -> anyhow::Result<()> {
2333 quit_all_impl(cx.editor, args, event, false)
2332 quit_all_impl(cx.editor, args, event, false)
@@ -2335,7 +2334,7 @@ pub mod cmd {
2336 fn force_quit_all(
2335 fn force_quit_all(
2337 cx: &mut compositor::Context,
2336 cx: &mut compositor::Context,
2338− args: &[&str],
2337+ args: &[Cow<str>],
2339 event: PromptEvent,
2338 event: PromptEvent,
2340 ) -> anyhow::Result<()> {
2339 ) -> anyhow::Result<()> {
2341 quit_all_impl(cx.editor, args, event, true)
2340 quit_all_impl(cx.editor, args, event, true)
@@ -2343,7 +2342,7 @@ pub mod cmd {
2344 fn cquit(
2343 fn cquit(
2345 cx: &mut compositor::Context,
2344 cx: &mut compositor::Context,
2346− args: &[&str],
2345+ args: &[Cow<str>],
2347 _event: PromptEvent,
2346 _event: PromptEvent,
2348 ) -> anyhow::Result<()> {
2347 ) -> anyhow::Result<()> {
2349 let exit_code = args
2348 let exit_code = args
@@ -2362,7 +2361,7 @@ pub mod cmd {
2363 fn theme(
2362 fn theme(
2364 cx: &mut compositor::Context,
2363 cx: &mut compositor::Context,
2365− args: &[&str],
2364+ args: &[Cow<str>],
2366 _event: PromptEvent,
2365 _event: PromptEvent,
2367 ) -> anyhow::Result<()> {
2366 ) -> anyhow::Result<()> {
2368 let theme = args.first().context("theme not provided")?;
2367 let theme = args.first().context("theme not provided")?;
@@ -2371,7 +2370,7 @@ pub mod cmd {
2372 fn yank_main_selection_to_clipboard(
2371 fn yank_main_selection_to_clipboard(
2373 cx: &mut compositor::Context,
2372 cx: &mut compositor::Context,
2374− _args: &[&str],
2373+ _args: &[Cow<str>],
2375 _event: PromptEvent,
2374 _event: PromptEvent,
2376 ) -> anyhow::Result<()> {
2375 ) -> anyhow::Result<()> {
2377 yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard)
2376 yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard)
@@ -2379,20 +2378,18 @@ pub mod cmd {
2380 fn yank_joined_to_clipboard(
2379 fn yank_joined_to_clipboard(
2381 cx: &mut compositor::Context,
2380 cx: &mut compositor::Context,
2382− args: &[&str],
2381+ args: &[Cow<str>],
2383 _event: PromptEvent,
2382 _event: PromptEvent,
2384 ) -> anyhow::Result<()> {
2383 ) -> anyhow::Result<()> {
2385 let (_, doc) = current!(cx.editor);
2384 let (_, doc) = current!(cx.editor);
2386− let separator = args
2389− .unwrap_or_else(|| doc.line_ending.as_str());
2385+ let default_sep = Cow::Borrowed(doc.line_ending.as_str());
2386+ let separator = args.first().unwrap_or(&default_sep);
2390 yank_joined_to_clipboard_impl(cx.editor, separator, ClipboardType::Clipboard)
2387 yank_joined_to_clipboard_impl(cx.editor, separator, ClipboardType::Clipboard)
2393 fn yank_main_selection_to_primary_clipboard(
2390 fn yank_main_selection_to_primary_clipboard(
2394 cx: &mut compositor::Context,
2391 cx: &mut compositor::Context,
2395− _args: &[&str],
2392+ _args: &[Cow<str>],
2396 _event: PromptEvent,
2393 _event: PromptEvent,
2397 ) -> anyhow::Result<()> {
2394 ) -> anyhow::Result<()> {
2398 yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Selection)
2395 yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Selection)
@@ -2400,20 +2397,18 @@ pub mod cmd {
2401 fn yank_joined_to_primary_clipboard(
2398 fn yank_joined_to_primary_clipboard(
2402 cx: &mut compositor::Context,
2399 cx: &mut compositor::Context,
2403− args: &[&str],
2400+ args: &[Cow<str>],
2404 _event: PromptEvent,
2401 _event: PromptEvent,
2405 ) -> anyhow::Result<()> {
2402 ) -> anyhow::Result<()> {
2406 let (_, doc) = current!(cx.editor);
2403 let (_, doc) = current!(cx.editor);
2407− let separator = args
2410− .unwrap_or_else(|| doc.line_ending.as_str());
2404+ let default_sep = Cow::Borrowed(doc.line_ending.as_str());
2405+ let separator = args.first().unwrap_or(&default_sep);
2411 yank_joined_to_clipboard_impl(cx.editor, separator, ClipboardType::Selection)
2406 yank_joined_to_clipboard_impl(cx.editor, separator, ClipboardType::Selection)
2414 fn paste_clipboard_after(
2409 fn paste_clipboard_after(
2415 cx: &mut compositor::Context,
2410 cx: &mut compositor::Context,
2416− _args: &[&str],
2411+ _args: &[Cow<str>],
2417 _event: PromptEvent,
2412 _event: PromptEvent,
2418 ) -> anyhow::Result<()> {
2413 ) -> anyhow::Result<()> {
2419 paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard)
2414 paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard)
@@ -2421,7 +2416,7 @@ pub mod cmd {
2422 fn paste_clipboard_before(
2417 fn paste_clipboard_before(
2423 cx: &mut compositor::Context,
2418 cx: &mut compositor::Context,
2424− _args: &[&str],
2419+ _args: &[Cow<str>],
2425 _event: PromptEvent,
2420 _event: PromptEvent,
2426 ) -> anyhow::Result<()> {
2421 ) -> anyhow::Result<()> {
2427 paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard)
2422 paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard)
@@ -2429,7 +2424,7 @@ pub mod cmd {
2430 fn paste_primary_clipboard_after(
2425 fn paste_primary_clipboard_after(
2431 cx: &mut compositor::Context,
2426 cx: &mut compositor::Context,
2432− _args: &[&str],
2427+ _args: &[Cow<str>],
2433 _event: PromptEvent,
2428 _event: PromptEvent,
2434 ) -> anyhow::Result<()> {
2429 ) -> anyhow::Result<()> {
2435 paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection)
2430 paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection)
@@ -2437,7 +2432,7 @@ pub mod cmd {
2438 fn paste_primary_clipboard_before(
2433 fn paste_primary_clipboard_before(
2439 cx: &mut compositor::Context,
2434 cx: &mut compositor::Context,
2440− _args: &[&str],
2435+ _args: &[Cow<str>],
2441 _event: PromptEvent,
2436 _event: PromptEvent,
2442 ) -> anyhow::Result<()> {
2437 ) -> anyhow::Result<()> {
2443 paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection)
2438 paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection)
@@ -2467,7 +2462,7 @@ pub mod cmd {
2468 fn replace_selections_with_clipboard(
2463 fn replace_selections_with_clipboard(
2469 cx: &mut compositor::Context,
2464 cx: &mut compositor::Context,
2470− _args: &[&str],
2465+ _args: &[Cow<str>],
2471 _event: PromptEvent,
2466 _event: PromptEvent,
2472 ) -> anyhow::Result<()> {
2467 ) -> anyhow::Result<()> {
2473 replace_selections_with_clipboard_impl(cx, ClipboardType::Clipboard)
2468 replace_selections_with_clipboard_impl(cx, ClipboardType::Clipboard)
@@ -2475,7 +2470,7 @@ pub mod cmd {
2476 fn replace_selections_with_primary_clipboard(
2471 fn replace_selections_with_primary_clipboard(
2477 cx: &mut compositor::Context,
2472 cx: &mut compositor::Context,
2478− _args: &[&str],
2473+ _args: &[Cow<str>],
2479 _event: PromptEvent,
2474 _event: PromptEvent,
2480 ) -> anyhow::Result<()> {
2475 ) -> anyhow::Result<()> {
2481 replace_selections_with_clipboard_impl(cx, ClipboardType::Selection)
2476 replace_selections_with_clipboard_impl(cx, ClipboardType::Selection)
@@ -2483,7 +2478,7 @@ pub mod cmd {
2484 fn show_clipboard_provider(
2479 fn show_clipboard_provider(
2485 cx: &mut compositor::Context,
2480 cx: &mut compositor::Context,
2486− _args: &[&str],
2481+ _args: &[Cow<str>],
2487 _event: PromptEvent,
2482 _event: PromptEvent,
2488 ) -> anyhow::Result<()> {
2483 ) -> anyhow::Result<()> {
2489 cx.editor
2484 cx.editor
@@ -2493,12 +2488,13 @@ pub mod cmd {
2494 fn change_current_directory(
2489 fn change_current_directory(
2495 cx: &mut compositor::Context,
2490 cx: &mut compositor::Context,
2496− args: &[&str],
2491+ args: &[Cow<str>],
2497 _event: PromptEvent,
2492 _event: PromptEvent,
2498 ) -> anyhow::Result<()> {
2493 ) -> anyhow::Result<()> {
2499 let dir = helix_core::path::expand_tilde(
2494 let dir = helix_core::path::expand_tilde(
2500 args.first()
2495 args.first()
2501 .context("target directory not provided")?
2496 .context("target directory not provided")?
2502 .as_ref(),
2498 .as_ref(),
@@ -2516,7 +2512,7 @@ pub mod cmd {
2517 fn show_current_directory(
2513 fn show_current_directory(
2518 cx: &mut compositor::Context,
2514 cx: &mut compositor::Context,
2519− _args: &[&str],
2515+ _args: &[Cow<str>],
2520 _event: PromptEvent,
2516 _event: PromptEvent,
2521 ) -> anyhow::Result<()> {
2517 ) -> anyhow::Result<()> {
2522 let cwd = std::env::current_dir().context("Couldn't get the new working directory")?;
2518 let cwd = std::env::current_dir().context("Couldn't get the new working directory")?;
@@ -2528,7 +2524,7 @@ pub mod cmd {
2528 /// Sets the [`Document`]'s encoding..
2524 /// Sets the [`Document`]'s encoding..
2529 fn set_encoding(
2525 fn set_encoding(
2530 cx: &mut compositor::Context,
2526 cx: &mut compositor::Context,
2531− args: &[&str],
2527+ args: &[Cow<str>],
2532 _event: PromptEvent,
2528 _event: PromptEvent,
2533 ) -> anyhow::Result<()> {
2529 ) -> anyhow::Result<()> {
2534 let (_, doc) = current!(cx.editor);
2530 let (_, doc) = current!(cx.editor);
@@ -2544,7 +2540,7 @@ pub mod cmd {
2544 /// Reload the [`Document`] from its source file.
2540 /// Reload the [`Document`] from its source file.
2545 fn reload(
2541 fn reload(
2546 cx: &mut compositor::Context,
2542 cx: &mut compositor::Context,
2547− _args: &[&str],
2543+ _args: &[Cow<str>],
2548 _event: PromptEvent,
2544 _event: PromptEvent,
2549 ) -> anyhow::Result<()> {
2545 ) -> anyhow::Result<()> {
2550 let (view, doc) = current!(cx.editor);
2546 let (view, doc) = current!(cx.editor);
@@ -2553,7 +2549,7 @@ pub mod cmd {
2554 fn tree_sitter_scopes(
2550 fn tree_sitter_scopes(
2555 cx: &mut compositor::Context,
2551 cx: &mut compositor::Context,
2556− _args: &[&str],
2552+ _args: &[Cow<str>],
2557 _event: PromptEvent,
2553 _event: PromptEvent,
2558 ) -> anyhow::Result<()> {
2554 ) -> anyhow::Result<()> {
2559 let (view, doc) = current!(cx.editor);
2555 let (view, doc) = current!(cx.editor);
@@ -2567,15 +2563,18 @@ pub mod cmd {
2568 fn vsplit(
2564 fn vsplit(
2569 cx: &mut compositor::Context,
2565 cx: &mut compositor::Context,
2570− args: &[&str],
2566+ args: &[Cow<str>],
2571 _event: PromptEvent,
2567 _event: PromptEvent,
2572 ) -> anyhow::Result<()> {
2568 ) -> anyhow::Result<()> {
2573 let id = view!(cx.editor).doc;
2569 let id = view!(cx.editor).doc;
2575− if let Some(path) = args.get(0) {
2571+ if args.is_empty() {
2576− cx.editor.open(path.into(), Action::VerticalSplit)?;
2578 cx.editor.switch(id, Action::VerticalSplit);
2572 cx.editor.switch(id, Action::VerticalSplit);
2576+ .open(PathBuf::from(arg.as_ref()), Action::VerticalSplit)?;
@@ -2583,15 +2582,18 @@ pub mod cmd {
2584 fn hsplit(
2583 fn hsplit(
2585 cx: &mut compositor::Context,
2584 cx: &mut compositor::Context,
2586− args: &[&str],
2585+ args: &[Cow<str>],
2587 _event: PromptEvent,
2586 _event: PromptEvent,
2588 ) -> anyhow::Result<()> {
2587 ) -> anyhow::Result<()> {
2589 let id = view!(cx.editor).doc;
2588 let id = view!(cx.editor).doc;
2591− if let Some(path) = args.get(0) {
2590+ if args.is_empty() {
2592− cx.editor.open(path.into(), Action::HorizontalSplit)?;
2594 cx.editor.switch(id, Action::HorizontalSplit);
2591 cx.editor.switch(id, Action::HorizontalSplit);
2595+ .open(PathBuf::from(arg.as_ref()), Action::HorizontalSplit)?;
@@ -2599,7 +2601,7 @@ pub mod cmd {
2600 fn tutor(
2602 fn tutor(
2601 cx: &mut compositor::Context,
2603 cx: &mut compositor::Context,
2602− _args: &[&str],
2604+ _args: &[Cow<str>],
2603 _event: PromptEvent,
2605 _event: PromptEvent,
2604 ) -> anyhow::Result<()> {
2606 ) -> anyhow::Result<()> {
2605 let path = helix_core::runtime_dir().join("tutor.txt");
2607 let path = helix_core::runtime_dir().join("tutor.txt");
@@ -2611,7 +2613,7 @@ pub mod cmd {
2612 pub(super) fn goto_line_number(
2614 pub(super) fn goto_line_number(
2613 cx: &mut compositor::Context,
2615 cx: &mut compositor::Context,
2614− args: &[&str],
2616+ args: &[Cow<str>],
2615 _event: PromptEvent,
2617 _event: PromptEvent,
2616 ) -> anyhow::Result<()> {
2618 ) -> anyhow::Result<()> {
2617 ensure!(!args.is_empty(), "Line number required");
2619 ensure!(!args.is_empty(), "Line number required");
@@ -2980,7 +2982,7 @@ fn command_mode(cx: &mut Context) {
2981 // If command is numeric, interpret as line number and go there.
2983 // If command is numeric, interpret as line number and go there.
2982 if parts.len() == 1 && parts[0].parse::<usize>().ok().is_some() {
2984 if parts.len() == 1 && parts[0].parse::<usize>().ok().is_some() {
2983− if let Err(e) = cmd::goto_line_number(cx, &parts[0..], event) {
2985+ if let Err(e) = cmd::goto_line_number(cx, &[Cow::from(parts[0])], event) {
2984 cx.editor.set_error(format!("{}", e));
2986 cx.editor.set_error(format!("{}", e));
@@ -2988,7 +2990,8 @@ fn command_mode(cx: &mut Context) {
2989 // Handle typable commands
2991 // Handle typable commands
2990 if let Some(cmd) = cmd::TYPABLE_COMMAND_MAP.get(parts[0]) {
2992 if let Some(cmd) = cmd::TYPABLE_COMMAND_MAP.get(parts[0]) {
2993+ let args = shellwords::shellwords(input);
2991− if let Err(e) = (cmd.fun)(cx, &parts[1..], event) {
2994+ if let Err(e) = (cmd.fun)(cx, &args[1..], event) {
2992 cx.editor.set_error(format!("{}", e));
2995 cx.editor.set_error(format!("{}", e));
2994 } else {
2997 } else {