@@ -5,7 +5,7 @@ use crate::job::Job;
55
66use super::*;
77
8−use helix_core::encoding;
8+use helix_core::{encoding, shellwords::Shellwords};
99use helix_view::document::DEFAULT_LANGUAGE_NAME;
1010use helix_view::editor::{Action, CloseError, ConfigEvent};
1111use serde_json::Value;
@@ -18,7 +18,49 @@ pub struct TypableCommand {
1818 pub doc: &'static str,
1919 // params, flags, helper, completer
2020 pub fun: fn(&mut compositor::Context, &[Cow<str>], PromptEvent) -> anyhow::Result<()>,
21− pub completer: Option<Completer>,
21+ /// What completion methods, if any, does this command have?
22+ pub signature: CommandSignature,
23+}
24+
25+impl TypableCommand {
26+ fn completer_for_argument_number(&self, n: usize) -> &Completer {
27+ match self.signature.positional_args.get(n) {
28+ Some(completer) => completer,
29+ _ => &self.signature.var_args,
30+ }
31+ }
32+}
33+
34+#[derive(Clone)]
35+pub struct CommandSignature {
36+ // Arguments with specific completion methods based on their position.
37+ positional_args: &'static [Completer],
38+
39+ // All remaining arguments will use this completion method, if set.
40+ var_args: Completer,
41+}
42+
43+impl CommandSignature {
44+ const fn none() -> Self {
45+ Self {
46+ positional_args: &[],
47+ var_args: completers::none,
48+ }
49+ }
50+
51+ const fn positional(completers: &'static [Completer]) -> Self {
52+ Self {
53+ positional_args: completers,
54+ var_args: completers::none,
55+ }
56+ }
57+
58+ const fn all(completer: Completer) -> Self {
59+ Self {
60+ positional_args: &[],
61+ var_args: completer,
62+ }
63+ }
2264}
2365
2466fn quit(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> {
@@ -2113,112 +2155,114 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
21132155 aliases: &["q"],
21142156 doc: "Close the current view.",
21152157 fun: quit,
2116− completer: None,
2158+ signature: CommandSignature::none(),
21172159 },
21182160 TypableCommand {
21192161 name: "quit!",
21202162 aliases: &["q!"],
21212163 doc: "Force close the current view, ignoring unsaved changes.",
21222164 fun: force_quit,
2123− completer: None,
2165+ signature: CommandSignature::none(),
21242166 },
21252167 TypableCommand {
21262168 name: "open",
21272169 aliases: &["o"],
21282170 doc: "Open a file from disk into the current view.",
21292171 fun: open,
2130− completer: Some(completers::filename),
2172+ signature: CommandSignature::all(completers::filename),
21312173 },
21322174 TypableCommand {
21332175 name: "buffer-close",
21342176 aliases: &["bc", "bclose"],
21352177 doc: "Close the current buffer.",
21362178 fun: buffer_close,
2137− completer: Some(completers::buffer),
2179+ signature: CommandSignature::all(completers::buffer),
21382180 },
21392181 TypableCommand {
21402182 name: "buffer-close!",
21412183 aliases: &["bc!", "bclose!"],
21422184 doc: "Close the current buffer forcefully, ignoring unsaved changes.",
21432185 fun: force_buffer_close,
2144− completer: Some(completers::buffer),
2186+ signature: CommandSignature::all(completers::buffer)
21452187 },
21462188 TypableCommand {
21472189 name: "buffer-close-others",
21482190 aliases: &["bco", "bcloseother"],
21492191 doc: "Close all buffers but the currently focused one.",
21502192 fun: buffer_close_others,
2151− completer: None,
2193+ signature: CommandSignature::none(),
21522194 },
21532195 TypableCommand {
21542196 name: "buffer-close-others!",
21552197 aliases: &["bco!", "bcloseother!"],
21562198 doc: "Force close all buffers but the currently focused one.",
21572199 fun: force_buffer_close_others,
2158− completer: None,
2200+ signature: CommandSignature::none(),
21592201 },
21602202 TypableCommand {
21612203 name: "buffer-close-all",
21622204 aliases: &["bca", "bcloseall"],
21632205 doc: "Close all buffers without quitting.",
21642206 fun: buffer_close_all,
2165− completer: None,
2207+ signature: CommandSignature::none(),
21662208 },
21672209 TypableCommand {
21682210 name: "buffer-close-all!",
21692211 aliases: &["bca!", "bcloseall!"],
21702212 doc: "Force close all buffers ignoring unsaved changes without quitting.",
21712213 fun: force_buffer_close_all,
2172− completer: None,
2214+ signature: CommandSignature::none(),
21732215 },
21742216 TypableCommand {
21752217 name: "buffer-next",
21762218 aliases: &["bn", "bnext"],
21772219 doc: "Goto next buffer.",
21782220 fun: buffer_next,
2179− completer: None,
2221+ signature: CommandSignature::none(),
21802222 },
21812223 TypableCommand {
21822224 name: "buffer-previous",
21832225 aliases: &["bp", "bprev"],
21842226 doc: "Goto previous buffer.",
21852227 fun: buffer_previous,
2186− completer: None,
2228+ signature: CommandSignature::none(),
21872229 },
21882230 TypableCommand {
21892231 name: "write",
21902232 aliases: &["w"],
21912233 doc: "Write changes to disk. Accepts an optional path (:write some/path.txt)",
21922234 fun: write,
2193− completer: Some(completers::filename),
2235+ signature: CommandSignature::positional(&[completers::filename]),
21942236 },
21952237 TypableCommand {
21962238 name: "write!",
21972239 aliases: &["w!"],
21982240 doc: "Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write some/path.txt)",
21992241 fun: force_write,
2200− completer: Some(completers::filename),
2242+ signature: CommandSignature::positional(&[completers::filename]),
22012243 },
22022244 TypableCommand {
22032245 name: "new",
22042246 aliases: &["n"],
22052247 doc: "Create a new scratch buffer.",
22062248 fun: new_file,
2207− completer: Some(completers::filename),
2249+ // TODO: This seems to complete with a filename, but doesn't use that filename to
2250+ // set the path of the newly created buffer.
2251+ signature: CommandSignature::positional(&[completers::filename]),
22082252 },
22092253 TypableCommand {
22102254 name: "format",
22112255 aliases: &["fmt"],
22122256 doc: "Format the file using the LSP formatter.",
22132257 fun: format,
2214− completer: None,
2258+ signature: CommandSignature::none(),
22152259 },
22162260 TypableCommand {
22172261 name: "indent-style",
22182262 aliases: &[],
22192263 doc: "Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.)",
22202264 fun: set_indent_style,
2221− completer: None,
2265+ signature: CommandSignature::none(),
22222266 },
22232267 TypableCommand {
22242268 name: "line-ending",
@@ -2228,231 +2272,231 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
22282272 #[cfg(feature = "unicode-lines")]
22292273 doc: "Set the document's default line ending. Options: crlf, lf, cr, ff, nel.",
22302274 fun: set_line_ending,
2231− completer: None,
2275+ signature: CommandSignature::none(),
22322276 },
22332277 TypableCommand {
22342278 name: "earlier",
22352279 aliases: &["ear"],
22362280 doc: "Jump back to an earlier point in edit history. Accepts a number of steps or a time span.",
22372281 fun: earlier,
2238− completer: None,
2282+ signature: CommandSignature::none(),
22392283 },
22402284 TypableCommand {
22412285 name: "later",
22422286 aliases: &["lat"],
22432287 doc: "Jump to a later point in edit history. Accepts a number of steps or a time span.",
22442288 fun: later,
2245− completer: None,
2289+ signature: CommandSignature::none(),
22462290 },
22472291 TypableCommand {
22482292 name: "write-quit",
22492293 aliases: &["wq", "x"],
22502294 doc: "Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt)",
22512295 fun: write_quit,
2252− completer: Some(completers::filename),
2296+ signature: CommandSignature::positional(&[completers::filename]),
22532297 },
22542298 TypableCommand {
22552299 name: "write-quit!",
22562300 aliases: &["wq!", "x!"],
22572301 doc: "Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt)",
22582302 fun: force_write_quit,
2259− completer: Some(completers::filename),
2303+ signature: CommandSignature::positional(&[completers::filename]),
22602304 },
22612305 TypableCommand {
22622306 name: "write-all",
22632307 aliases: &["wa"],
22642308 doc: "Write changes from all buffers to disk.",
22652309 fun: write_all,
2266− completer: None,
2310+ signature: CommandSignature::none(),
22672311 },
22682312 TypableCommand {
22692313 name: "write-quit-all",
22702314 aliases: &["wqa", "xa"],
22712315 doc: "Write changes from all buffers to disk and close all views.",
22722316 fun: write_all_quit,
2273− completer: None,
2317+ signature: CommandSignature::none(),
22742318 },
22752319 TypableCommand {
22762320 name: "write-quit-all!",
22772321 aliases: &["wqa!", "xa!"],
22782322 doc: "Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes).",
22792323 fun: force_write_all_quit,
2280− completer: None,
2324+ signature: CommandSignature::none(),
22812325 },
22822326 TypableCommand {
22832327 name: "quit-all",
22842328 aliases: &["qa"],
22852329 doc: "Close all views.",
22862330 fun: quit_all,
2287− completer: None,
2331+ signature: CommandSignature::none(),
22882332 },
22892333 TypableCommand {
22902334 name: "quit-all!",
22912335 aliases: &["qa!"],
22922336 doc: "Force close all views ignoring unsaved changes.",
22932337 fun: force_quit_all,
2294− completer: None,
2338+ signature: CommandSignature::none(),
22952339 },
22962340 TypableCommand {
22972341 name: "cquit",
22982342 aliases: &["cq"],
22992343 doc: "Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2).",
23002344 fun: cquit,
2301− completer: None,
2345+ signature: CommandSignature::none(),
23022346 },
23032347 TypableCommand {
23042348 name: "cquit!",
23052349 aliases: &["cq!"],
23062350 doc: "Force quit with exit code (default 1) ignoring unsaved changes. Accepts an optional integer exit code (:cq! 2).",
23072351 fun: force_cquit,
2308− completer: None,
2352+ signature: CommandSignature::none(),
23092353 },
23102354 TypableCommand {
23112355 name: "theme",
23122356 aliases: &[],
23132357 doc: "Change the editor theme (show current theme if no name specified).",
23142358 fun: theme,
2315− completer: Some(completers::theme),
2359+ signature: CommandSignature::positional(&[completers::theme]),
23162360 },
23172361 TypableCommand {
23182362 name: "clipboard-yank",
23192363 aliases: &[],
23202364 doc: "Yank main selection into system clipboard.",
23212365 fun: yank_main_selection_to_clipboard,
2322− completer: None,
2366+ signature: CommandSignature::none(),
23232367 },
23242368 TypableCommand {
23252369 name: "clipboard-yank-join",
23262370 aliases: &[],
23272371 doc: "Yank joined selections into system clipboard. A separator can be provided as first argument. Default value is newline.", // FIXME: current UI can't display long doc.
23282372 fun: yank_joined_to_clipboard,
2329− completer: None,
2373+ signature: CommandSignature::none(),
23302374 },
23312375 TypableCommand {
23322376 name: "primary-clipboard-yank",
23332377 aliases: &[],
23342378 doc: "Yank main selection into system primary clipboard.",
23352379 fun: yank_main_selection_to_primary_clipboard,
2336− completer: None,
2380+ signature: CommandSignature::none(),
23372381 },
23382382 TypableCommand {
23392383 name: "primary-clipboard-yank-join",
23402384 aliases: &[],
23412385 doc: "Yank joined selections into system primary clipboard. A separator can be provided as first argument. Default value is newline.", // FIXME: current UI can't display long doc.
23422386 fun: yank_joined_to_primary_clipboard,
2343− completer: None,
2387+ signature: CommandSignature::none(),
23442388 },
23452389 TypableCommand {
23462390 name: "clipboard-paste-after",
23472391 aliases: &[],
23482392 doc: "Paste system clipboard after selections.",
23492393 fun: paste_clipboard_after,
2350− completer: None,
2394+ signature: CommandSignature::none(),
23512395 },
23522396 TypableCommand {
23532397 name: "clipboard-paste-before",
23542398 aliases: &[],
23552399 doc: "Paste system clipboard before selections.",
23562400 fun: paste_clipboard_before,
2357− completer: None,
2401+ signature: CommandSignature::none(),
23582402 },
23592403 TypableCommand {
23602404 name: "clipboard-paste-replace",
23612405 aliases: &[],
23622406 doc: "Replace selections with content of system clipboard.",
23632407 fun: replace_selections_with_clipboard,
2364− completer: None,
2408+ signature: CommandSignature::none(),
23652409 },
23662410 TypableCommand {
23672411 name: "primary-clipboard-paste-after",
23682412 aliases: &[],
23692413 doc: "Paste primary clipboard after selections.",
23702414 fun: paste_primary_clipboard_after,
2371− completer: None,
2415+ signature: CommandSignature::none(),
23722416 },
23732417 TypableCommand {
23742418 name: "primary-clipboard-paste-before",
23752419 aliases: &[],
23762420 doc: "Paste primary clipboard before selections.",
23772421 fun: paste_primary_clipboard_before,
2378− completer: None,
2422+ signature: CommandSignature::none(),
23792423 },
23802424 TypableCommand {
23812425 name: "primary-clipboard-paste-replace",
23822426 aliases: &[],
23832427 doc: "Replace selections with content of system primary clipboard.",
23842428 fun: replace_selections_with_primary_clipboard,
2385− completer: None,
2429+ signature: CommandSignature::none(),
23862430 },
23872431 TypableCommand {
23882432 name: "show-clipboard-provider",
23892433 aliases: &[],
23902434 doc: "Show clipboard provider name in status bar.",
23912435 fun: show_clipboard_provider,
2392− completer: None,
2436+ signature: CommandSignature::none(),
23932437 },
23942438 TypableCommand {
23952439 name: "change-current-directory",
23962440 aliases: &["cd"],
23972441 doc: "Change the current working directory.",
23982442 fun: change_current_directory,
2399− completer: Some(completers::directory),
2443+ signature: CommandSignature::positional(&[completers::directory]),
24002444 },
24012445 TypableCommand {
24022446 name: "show-directory",
24032447 aliases: &["pwd"],
24042448 doc: "Show the current working directory.",
24052449 fun: show_current_directory,
2406− completer: None,
2450+ signature: CommandSignature::none(),
24072451 },
24082452 TypableCommand {
24092453 name: "encoding",
24102454 aliases: &[],
24112455 doc: "Set encoding. Based on `https://encoding.spec.whatwg.org`.",
24122456 fun: set_encoding,
2413− completer: None,
2457+ signature: CommandSignature::none(),
24142458 },
24152459 TypableCommand {
24162460 name: "character-info",
24172461 aliases: &["char"],
24182462 doc: "Get info about the character under the primary cursor.",
24192463 fun: get_character_info,
2420− completer: None,
2464+ signature: CommandSignature::none(),
24212465 },
24222466 TypableCommand {
24232467 name: "reload",
24242468 aliases: &[],
24252469 doc: "Discard changes and reload from the source file.",
24262470 fun: reload,
2427− completer: None,
2471+ signature: CommandSignature::none(),
24282472 },
24292473 TypableCommand {
24302474 name: "reload-all",
24312475 aliases: &[],
24322476 doc: "Discard changes and reload all documents from the source files.",
24332477 fun: reload_all,
2434− completer: None,
2478+ signature: CommandSignature::none(),
24352479 },
24362480 TypableCommand {
24372481 name: "update",
24382482 aliases: &[],
24392483 doc: "Write changes only if the file has been modified.",
24402484 fun: update,
2441− completer: None,
2485+ signature: CommandSignature::none(),
24422486 },
24432487 TypableCommand {
24442488 name: "lsp-workspace-command",
24452489 aliases: &[],
24462490 doc: "Open workspace command picker",
24472491 fun: lsp_workspace_command,
2448− completer: Some(completers::lsp_workspace_command),
2492+ signature: CommandSignature::positional(&[completers::lsp_workspace_command]),
24492493 },
24502494 TypableCommand {
24512495 name: "lsp-restart",
24522496 aliases: &[],
24532497 doc: "Restarts the Language Server that is in use by the current doc",
24542498 fun: lsp_restart,
2455− completer: None,
2499+ signature: CommandSignature::none(),
24562500 },
24572501 TypableCommand {
24582502 name: "lsp-stop",
@@ -2466,182 +2510,183 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
24662510 aliases: &[],
24672511 doc: "Display tree sitter scopes, primarily for theming and development.",
24682512 fun: tree_sitter_scopes,
2469− completer: None,
2470− },
2513+ signature: CommandSignature::none(),
2514+ },
24712515 TypableCommand {
24722516 name: "debug-start",
24732517 aliases: &["dbg"],
24742518 doc: "Start a debug session from a given template with given parameters.",
24752519 fun: debug_start,
2476− completer: None,
2520+ signature: CommandSignature::none(),
24772521 },
24782522 TypableCommand {
24792523 name: "debug-remote",
24802524 aliases: &["dbg-tcp"],
24812525 doc: "Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters.",
24822526 fun: debug_remote,
2483− completer: None,
2527+ signature: CommandSignature::none(),
24842528 },
24852529 TypableCommand {
24862530 name: "debug-eval",
24872531 aliases: &[],
24882532 doc: "Evaluate expression in current debug context.",
24892533 fun: debug_eval,
2490− completer: None,
2534+ signature: CommandSignature::none(),
24912535 },
24922536 TypableCommand {
24932537 name: "vsplit",
24942538 aliases: &["vs"],
24952539 doc: "Open the file in a vertical split.",
24962540 fun: vsplit,
2497− completer: Some(completers::filename),
2541+ signature: CommandSignature::all(completers::filename)
24982542 },
24992543 TypableCommand {
25002544 name: "vsplit-new",
25012545 aliases: &["vnew"],
25022546 doc: "Open a scratch buffer in a vertical split.",
25032547 fun: vsplit_new,
2504− completer: None,
2548+ signature: CommandSignature::none(),
25052549 },
25062550 TypableCommand {
25072551 name: "hsplit",
25082552 aliases: &["hs", "sp"],
25092553 doc: "Open the file in a horizontal split.",
25102554 fun: hsplit,
2511− completer: Some(completers::filename),
2555+ signature: CommandSignature::all(completers::filename)
25122556 },
25132557 TypableCommand {
25142558 name: "hsplit-new",
25152559 aliases: &["hnew"],
25162560 doc: "Open a scratch buffer in a horizontal split.",
25172561 fun: hsplit_new,
2518− completer: None,
2562+ signature: CommandSignature::none(),
25192563 },
25202564 TypableCommand {
25212565 name: "tutor",
25222566 aliases: &[],
25232567 doc: "Open the tutorial.",
25242568 fun: tutor,
2525− completer: None,
2569+ signature: CommandSignature::none(),
25262570 },
25272571 TypableCommand {
25282572 name: "goto",
25292573 aliases: &["g"],
25302574 doc: "Goto line number.",
25312575 fun: goto_line_number,
2532− completer: None,
2576+ signature: CommandSignature::none(),
25332577 },
25342578 TypableCommand {
25352579 name: "set-language",
25362580 aliases: &["lang"],
25372581 doc: "Set the language of current buffer (show current language if no value specified).",
25382582 fun: language,
2539− completer: Some(completers::language),
2583+ signature: CommandSignature::positional(&[completers::language]),
25402584 },
25412585 TypableCommand {
25422586 name: "set-option",
25432587 aliases: &["set"],
25442588 doc: "Set a config option at runtime.\nFor example to disable smart case search, use `:set search.smart-case false`.",
25452589 fun: set_option,
2546− completer: Some(completers::setting),
2590+ // TODO: Add support for completion of the options value(s), when appropriate.
2591+ signature: CommandSignature::positional(&[completers::setting]),
25472592 },
25482593 TypableCommand {
25492594 name: "toggle-option",
25502595 aliases: &["toggle"],
25512596 doc: "Toggle a boolean config option at runtime.\nFor example to toggle smart case search, use `:toggle search.smart-case`.",
25522597 fun: toggle_option,
2553− completer: Some(completers::setting),
2598+ signature: CommandSignature::positional(&[completers::setting]),
25542599 },
25552600 TypableCommand {
25562601 name: "get-option",
25572602 aliases: &["get"],
25582603 doc: "Get the current value of a config option.",
25592604 fun: get_option,
2560− completer: Some(completers::setting),
2605+ signature: CommandSignature::positional(&[completers::setting]),
25612606 },
25622607 TypableCommand {
25632608 name: "sort",
25642609 aliases: &[],
25652610 doc: "Sort ranges in selection.",
25662611 fun: sort,
2567− completer: None,
2612+ signature: CommandSignature::none(),
25682613 },
25692614 TypableCommand {
25702615 name: "rsort",
25712616 aliases: &[],
25722617 doc: "Sort ranges in selection in reverse order.",
25732618 fun: sort_reverse,
2574− completer: None,
2619+ signature: CommandSignature::none(),
25752620 },
25762621 TypableCommand {
25772622 name: "reflow",
25782623 aliases: &[],
25792624 doc: "Hard-wrap the current selection of lines to a given width.",
25802625 fun: reflow,
2581− completer: None,
2626+ signature: CommandSignature::none(),
25822627 },
25832628 TypableCommand {
25842629 name: "tree-sitter-subtree",
25852630 aliases: &["ts-subtree"],
25862631 doc: "Display tree sitter subtree under cursor, primarily for debugging queries.",
25872632 fun: tree_sitter_subtree,
2588− completer: None,
2633+ signature: CommandSignature::none(),
25892634 },
25902635 TypableCommand {
25912636 name: "config-reload",
25922637 aliases: &[],
25932638 doc: "Refresh user config.",
25942639 fun: refresh_config,
2595− completer: None,
2640+ signature: CommandSignature::none(),
25962641 },
25972642 TypableCommand {
25982643 name: "config-open",
25992644 aliases: &[],
26002645 doc: "Open the user config.toml file.",
26012646 fun: open_config,
2602− completer: None,
2647+ signature: CommandSignature::none(),
26032648 },
26042649 TypableCommand {
26052650 name: "log-open",
26062651 aliases: &[],
26072652 doc: "Open the helix log file.",
26082653 fun: open_log,
2609− completer: None,
2654+ signature: CommandSignature::none(),
26102655 },
26112656 TypableCommand {
26122657 name: "insert-output",
26132658 aliases: &[],
26142659 doc: "Run shell command, inserting output before each selection.",
26152660 fun: insert_output,
2616− completer: None,
2661+ signature: CommandSignature::none(),
26172662 },
26182663 TypableCommand {
26192664 name: "append-output",
26202665 aliases: &[],
26212666 doc: "Run shell command, appending output after each selection.",
26222667 fun: append_output,
2623− completer: None,
2668+ signature: CommandSignature::none(),
26242669 },
26252670 TypableCommand {
26262671 name: "pipe",
26272672 aliases: &[],
26282673 doc: "Pipe each selection to the shell command.",
26292674 fun: pipe,
2630− completer: None,
2675+ signature: CommandSignature::none(),
26312676 },
26322677 TypableCommand {
26332678 name: "pipe-to",
26342679 aliases: &[],
26352680 doc: "Pipe each selection to the shell command, ignoring output.",
26362681 fun: pipe_to,
2637− completer: None,
2682+ signature: CommandSignature::none(),
26382683 },
26392684 TypableCommand {
26402685 name: "run-shell-command",
26412686 aliases: &["sh"],
26422687 doc: "Run a shell command",
26432688 fun: run_shell_command,
2644− completer: Some(completers::filename),
2689+ signature: CommandSignature::all(completers::filename)
26452690 },
26462691 TypableCommand {
26472692 name: "reset-diff-change",
@@ -2665,8 +2710,6 @@ pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableComma
26652710
26662711#[allow(clippy::unnecessary_unwrap)]
26672712pub(super) fn command_mode(cx: &mut Context) {
2668− use shellwords::Shellwords;
2669−
26702713 let mut prompt = Prompt::new(
26712714 ":".into(),
26722715 Some(':'),
@@ -2705,10 +2748,11 @@ pub(super) fn command_mode(cx: &mut Context) {
27052748 )
27062749 };
27072750
2708− if let Some(typed::TypableCommand {
2709− completer: Some(completer),
2710− ..
2711− }) = typed::TYPABLE_COMMAND_MAP.get(&words[0] as &str)
2751+ let argument_number = argument_number_of(&shellwords);
2752+
2753+ if let Some(completer) = TYPABLE_COMMAND_MAP
2754+ .get(&words[0] as &str)
2755+ .map(|tc| tc.completer_for_argument_number(argument_number))
27122756 {
27132757 completer(editor, part)
27142758 .into_iter()
@@ -2773,3 +2817,29 @@ pub(super) fn command_mode(cx: &mut Context) {
27732817 prompt.recalculate_completion(cx.editor);
27742818 cx.push_layer(Box::new(prompt));
27752819}
2820+
2821+fn argument_number_of(shellwords: &Shellwords) -> usize {
2822+ if shellwords.ends_with_whitespace() {
2823+ shellwords.words().len().saturating_sub(1)
2824+ } else {
2825+ shellwords.words().len().saturating_sub(2)
2826+ }
2827+}
2828+
2829+#[test]
2830+fn test_argument_number_of() {
2831+ let cases = vec![
2832+ ("set-option", 0),
2833+ ("set-option ", 0),
2834+ ("set-option a", 0),
2835+ ("set-option asdf", 0),
2836+ ("set-option asdf ", 1),
2837+ ("set-option asdf xyz", 1),
2838+ ("set-option asdf xyz abc", 2),
2839+ ("set-option asdf xyz abc ", 3),
2840+ ];
2841+
2842+ for case in cases {
2843+ assert_eq!(case.1, argument_number_of(&Shellwords::from(case.0)));
2844+ }
2845+}