Only complete appropriate arguments for typed commands. (#5966)

pull/6311/head
Kyle Smith 1 year ago committed by GitHub
parent d479adfdc6
commit 27aa919f1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,7 +5,7 @@ use crate::job::Job;
use super::*; use super::*;
use helix_core::encoding; use helix_core::{encoding, shellwords::Shellwords};
use helix_view::document::DEFAULT_LANGUAGE_NAME; use helix_view::document::DEFAULT_LANGUAGE_NAME;
use helix_view::editor::{Action, CloseError, ConfigEvent}; use helix_view::editor::{Action, CloseError, ConfigEvent};
use serde_json::Value; use serde_json::Value;
@ -18,7 +18,49 @@ pub struct TypableCommand {
pub doc: &'static str, pub doc: &'static str,
// params, flags, helper, completer // params, flags, helper, completer
pub fun: fn(&mut compositor::Context, &[Cow<str>], PromptEvent) -> anyhow::Result<()>, pub fun: fn(&mut compositor::Context, &[Cow<str>], PromptEvent) -> anyhow::Result<()>,
pub completer: Option<Completer>, /// What completion methods, if any, does this command have?
pub signature: CommandSignature,
}
impl TypableCommand {
fn completer_for_argument_number(&self, n: usize) -> &Completer {
match self.signature.positional_args.get(n) {
Some(completer) => completer,
_ => &self.signature.var_args,
}
}
}
#[derive(Clone)]
pub struct CommandSignature {
// Arguments with specific completion methods based on their position.
positional_args: &'static [Completer],
// All remaining arguments will use this completion method, if set.
var_args: Completer,
}
impl CommandSignature {
const fn none() -> Self {
Self {
positional_args: &[],
var_args: completers::none,
}
}
const fn positional(completers: &'static [Completer]) -> Self {
Self {
positional_args: completers,
var_args: completers::none,
}
}
const fn all(completer: Completer) -> Self {
Self {
positional_args: &[],
var_args: completer,
}
}
} }
fn quit(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> { fn quit(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> {
@ -2113,112 +2155,114 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
aliases: &["q"], aliases: &["q"],
doc: "Close the current view.", doc: "Close the current view.",
fun: quit, fun: quit,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "quit!", name: "quit!",
aliases: &["q!"], aliases: &["q!"],
doc: "Force close the current view, ignoring unsaved changes.", doc: "Force close the current view, ignoring unsaved changes.",
fun: force_quit, fun: force_quit,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "open", name: "open",
aliases: &["o"], aliases: &["o"],
doc: "Open a file from disk into the current view.", doc: "Open a file from disk into the current view.",
fun: open, fun: open,
completer: Some(completers::filename), signature: CommandSignature::all(completers::filename),
}, },
TypableCommand { TypableCommand {
name: "buffer-close", name: "buffer-close",
aliases: &["bc", "bclose"], aliases: &["bc", "bclose"],
doc: "Close the current buffer.", doc: "Close the current buffer.",
fun: buffer_close, fun: buffer_close,
completer: Some(completers::buffer), signature: CommandSignature::all(completers::buffer),
}, },
TypableCommand { TypableCommand {
name: "buffer-close!", name: "buffer-close!",
aliases: &["bc!", "bclose!"], aliases: &["bc!", "bclose!"],
doc: "Close the current buffer forcefully, ignoring unsaved changes.", doc: "Close the current buffer forcefully, ignoring unsaved changes.",
fun: force_buffer_close, fun: force_buffer_close,
completer: Some(completers::buffer), signature: CommandSignature::all(completers::buffer)
}, },
TypableCommand { TypableCommand {
name: "buffer-close-others", name: "buffer-close-others",
aliases: &["bco", "bcloseother"], aliases: &["bco", "bcloseother"],
doc: "Close all buffers but the currently focused one.", doc: "Close all buffers but the currently focused one.",
fun: buffer_close_others, fun: buffer_close_others,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "buffer-close-others!", name: "buffer-close-others!",
aliases: &["bco!", "bcloseother!"], aliases: &["bco!", "bcloseother!"],
doc: "Force close all buffers but the currently focused one.", doc: "Force close all buffers but the currently focused one.",
fun: force_buffer_close_others, fun: force_buffer_close_others,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "buffer-close-all", name: "buffer-close-all",
aliases: &["bca", "bcloseall"], aliases: &["bca", "bcloseall"],
doc: "Close all buffers without quitting.", doc: "Close all buffers without quitting.",
fun: buffer_close_all, fun: buffer_close_all,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "buffer-close-all!", name: "buffer-close-all!",
aliases: &["bca!", "bcloseall!"], aliases: &["bca!", "bcloseall!"],
doc: "Force close all buffers ignoring unsaved changes without quitting.", doc: "Force close all buffers ignoring unsaved changes without quitting.",
fun: force_buffer_close_all, fun: force_buffer_close_all,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "buffer-next", name: "buffer-next",
aliases: &["bn", "bnext"], aliases: &["bn", "bnext"],
doc: "Goto next buffer.", doc: "Goto next buffer.",
fun: buffer_next, fun: buffer_next,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "buffer-previous", name: "buffer-previous",
aliases: &["bp", "bprev"], aliases: &["bp", "bprev"],
doc: "Goto previous buffer.", doc: "Goto previous buffer.",
fun: buffer_previous, fun: buffer_previous,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "write", name: "write",
aliases: &["w"], aliases: &["w"],
doc: "Write changes to disk. Accepts an optional path (:write some/path.txt)", doc: "Write changes to disk. Accepts an optional path (:write some/path.txt)",
fun: write, fun: write,
completer: Some(completers::filename), signature: CommandSignature::positional(&[completers::filename]),
}, },
TypableCommand { TypableCommand {
name: "write!", name: "write!",
aliases: &["w!"], aliases: &["w!"],
doc: "Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write some/path.txt)", doc: "Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write some/path.txt)",
fun: force_write, fun: force_write,
completer: Some(completers::filename), signature: CommandSignature::positional(&[completers::filename]),
}, },
TypableCommand { TypableCommand {
name: "new", name: "new",
aliases: &["n"], aliases: &["n"],
doc: "Create a new scratch buffer.", doc: "Create a new scratch buffer.",
fun: new_file, fun: new_file,
completer: Some(completers::filename), // TODO: This seems to complete with a filename, but doesn't use that filename to
// set the path of the newly created buffer.
signature: CommandSignature::positional(&[completers::filename]),
}, },
TypableCommand { TypableCommand {
name: "format", name: "format",
aliases: &["fmt"], aliases: &["fmt"],
doc: "Format the file using the LSP formatter.", doc: "Format the file using the LSP formatter.",
fun: format, fun: format,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "indent-style", name: "indent-style",
aliases: &[], aliases: &[],
doc: "Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.)", doc: "Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.)",
fun: set_indent_style, fun: set_indent_style,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "line-ending", name: "line-ending",
@ -2228,231 +2272,231 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
#[cfg(feature = "unicode-lines")] #[cfg(feature = "unicode-lines")]
doc: "Set the document's default line ending. Options: crlf, lf, cr, ff, nel.", doc: "Set the document's default line ending. Options: crlf, lf, cr, ff, nel.",
fun: set_line_ending, fun: set_line_ending,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "earlier", name: "earlier",
aliases: &["ear"], aliases: &["ear"],
doc: "Jump back to an earlier point in edit history. Accepts a number of steps or a time span.", doc: "Jump back to an earlier point in edit history. Accepts a number of steps or a time span.",
fun: earlier, fun: earlier,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "later", name: "later",
aliases: &["lat"], aliases: &["lat"],
doc: "Jump to a later point in edit history. Accepts a number of steps or a time span.", doc: "Jump to a later point in edit history. Accepts a number of steps or a time span.",
fun: later, fun: later,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "write-quit", name: "write-quit",
aliases: &["wq", "x"], aliases: &["wq", "x"],
doc: "Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt)", doc: "Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt)",
fun: write_quit, fun: write_quit,
completer: Some(completers::filename), signature: CommandSignature::positional(&[completers::filename]),
}, },
TypableCommand { TypableCommand {
name: "write-quit!", name: "write-quit!",
aliases: &["wq!", "x!"], aliases: &["wq!", "x!"],
doc: "Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt)", doc: "Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt)",
fun: force_write_quit, fun: force_write_quit,
completer: Some(completers::filename), signature: CommandSignature::positional(&[completers::filename]),
}, },
TypableCommand { TypableCommand {
name: "write-all", name: "write-all",
aliases: &["wa"], aliases: &["wa"],
doc: "Write changes from all buffers to disk.", doc: "Write changes from all buffers to disk.",
fun: write_all, fun: write_all,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "write-quit-all", name: "write-quit-all",
aliases: &["wqa", "xa"], aliases: &["wqa", "xa"],
doc: "Write changes from all buffers to disk and close all views.", doc: "Write changes from all buffers to disk and close all views.",
fun: write_all_quit, fun: write_all_quit,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "write-quit-all!", name: "write-quit-all!",
aliases: &["wqa!", "xa!"], aliases: &["wqa!", "xa!"],
doc: "Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes).", doc: "Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes).",
fun: force_write_all_quit, fun: force_write_all_quit,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "quit-all", name: "quit-all",
aliases: &["qa"], aliases: &["qa"],
doc: "Close all views.", doc: "Close all views.",
fun: quit_all, fun: quit_all,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "quit-all!", name: "quit-all!",
aliases: &["qa!"], aliases: &["qa!"],
doc: "Force close all views ignoring unsaved changes.", doc: "Force close all views ignoring unsaved changes.",
fun: force_quit_all, fun: force_quit_all,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "cquit", name: "cquit",
aliases: &["cq"], aliases: &["cq"],
doc: "Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2).", doc: "Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2).",
fun: cquit, fun: cquit,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "cquit!", name: "cquit!",
aliases: &["cq!"], aliases: &["cq!"],
doc: "Force quit with exit code (default 1) ignoring unsaved changes. Accepts an optional integer exit code (:cq! 2).", doc: "Force quit with exit code (default 1) ignoring unsaved changes. Accepts an optional integer exit code (:cq! 2).",
fun: force_cquit, fun: force_cquit,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "theme", name: "theme",
aliases: &[], aliases: &[],
doc: "Change the editor theme (show current theme if no name specified).", doc: "Change the editor theme (show current theme if no name specified).",
fun: theme, fun: theme,
completer: Some(completers::theme), signature: CommandSignature::positional(&[completers::theme]),
}, },
TypableCommand { TypableCommand {
name: "clipboard-yank", name: "clipboard-yank",
aliases: &[], aliases: &[],
doc: "Yank main selection into system clipboard.", doc: "Yank main selection into system clipboard.",
fun: yank_main_selection_to_clipboard, fun: yank_main_selection_to_clipboard,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "clipboard-yank-join", name: "clipboard-yank-join",
aliases: &[], aliases: &[],
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. 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.
fun: yank_joined_to_clipboard, fun: yank_joined_to_clipboard,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "primary-clipboard-yank", name: "primary-clipboard-yank",
aliases: &[], aliases: &[],
doc: "Yank main selection into system primary clipboard.", doc: "Yank main selection into system primary clipboard.",
fun: yank_main_selection_to_primary_clipboard, fun: yank_main_selection_to_primary_clipboard,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "primary-clipboard-yank-join", name: "primary-clipboard-yank-join",
aliases: &[], aliases: &[],
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. 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.
fun: yank_joined_to_primary_clipboard, fun: yank_joined_to_primary_clipboard,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "clipboard-paste-after", name: "clipboard-paste-after",
aliases: &[], aliases: &[],
doc: "Paste system clipboard after selections.", doc: "Paste system clipboard after selections.",
fun: paste_clipboard_after, fun: paste_clipboard_after,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "clipboard-paste-before", name: "clipboard-paste-before",
aliases: &[], aliases: &[],
doc: "Paste system clipboard before selections.", doc: "Paste system clipboard before selections.",
fun: paste_clipboard_before, fun: paste_clipboard_before,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "clipboard-paste-replace", name: "clipboard-paste-replace",
aliases: &[], aliases: &[],
doc: "Replace selections with content of system clipboard.", doc: "Replace selections with content of system clipboard.",
fun: replace_selections_with_clipboard, fun: replace_selections_with_clipboard,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "primary-clipboard-paste-after", name: "primary-clipboard-paste-after",
aliases: &[], aliases: &[],
doc: "Paste primary clipboard after selections.", doc: "Paste primary clipboard after selections.",
fun: paste_primary_clipboard_after, fun: paste_primary_clipboard_after,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "primary-clipboard-paste-before", name: "primary-clipboard-paste-before",
aliases: &[], aliases: &[],
doc: "Paste primary clipboard before selections.", doc: "Paste primary clipboard before selections.",
fun: paste_primary_clipboard_before, fun: paste_primary_clipboard_before,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "primary-clipboard-paste-replace", name: "primary-clipboard-paste-replace",
aliases: &[], aliases: &[],
doc: "Replace selections with content of system primary clipboard.", doc: "Replace selections with content of system primary clipboard.",
fun: replace_selections_with_primary_clipboard, fun: replace_selections_with_primary_clipboard,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "show-clipboard-provider", name: "show-clipboard-provider",
aliases: &[], aliases: &[],
doc: "Show clipboard provider name in status bar.", doc: "Show clipboard provider name in status bar.",
fun: show_clipboard_provider, fun: show_clipboard_provider,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "change-current-directory", name: "change-current-directory",
aliases: &["cd"], aliases: &["cd"],
doc: "Change the current working directory.", doc: "Change the current working directory.",
fun: change_current_directory, fun: change_current_directory,
completer: Some(completers::directory), signature: CommandSignature::positional(&[completers::directory]),
}, },
TypableCommand { TypableCommand {
name: "show-directory", name: "show-directory",
aliases: &["pwd"], aliases: &["pwd"],
doc: "Show the current working directory.", doc: "Show the current working directory.",
fun: show_current_directory, fun: show_current_directory,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "encoding", name: "encoding",
aliases: &[], aliases: &[],
doc: "Set encoding. Based on `https://encoding.spec.whatwg.org`.", doc: "Set encoding. Based on `https://encoding.spec.whatwg.org`.",
fun: set_encoding, fun: set_encoding,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "character-info", name: "character-info",
aliases: &["char"], aliases: &["char"],
doc: "Get info about the character under the primary cursor.", doc: "Get info about the character under the primary cursor.",
fun: get_character_info, fun: get_character_info,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "reload", name: "reload",
aliases: &[], aliases: &[],
doc: "Discard changes and reload from the source file.", doc: "Discard changes and reload from the source file.",
fun: reload, fun: reload,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "reload-all", name: "reload-all",
aliases: &[], aliases: &[],
doc: "Discard changes and reload all documents from the source files.", doc: "Discard changes and reload all documents from the source files.",
fun: reload_all, fun: reload_all,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "update", name: "update",
aliases: &[], aliases: &[],
doc: "Write changes only if the file has been modified.", doc: "Write changes only if the file has been modified.",
fun: update, fun: update,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "lsp-workspace-command", name: "lsp-workspace-command",
aliases: &[], aliases: &[],
doc: "Open workspace command picker", doc: "Open workspace command picker",
fun: lsp_workspace_command, fun: lsp_workspace_command,
completer: Some(completers::lsp_workspace_command), signature: CommandSignature::positional(&[completers::lsp_workspace_command]),
}, },
TypableCommand { TypableCommand {
name: "lsp-restart", name: "lsp-restart",
aliases: &[], aliases: &[],
doc: "Restarts the Language Server that is in use by the current doc", doc: "Restarts the Language Server that is in use by the current doc",
fun: lsp_restart, fun: lsp_restart,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "lsp-stop", name: "lsp-stop",
@ -2466,182 +2510,183 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
aliases: &[], aliases: &[],
doc: "Display tree sitter scopes, primarily for theming and development.", doc: "Display tree sitter scopes, primarily for theming and development.",
fun: tree_sitter_scopes, fun: tree_sitter_scopes,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "debug-start", name: "debug-start",
aliases: &["dbg"], aliases: &["dbg"],
doc: "Start a debug session from a given template with given parameters.", doc: "Start a debug session from a given template with given parameters.",
fun: debug_start, fun: debug_start,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "debug-remote", name: "debug-remote",
aliases: &["dbg-tcp"], aliases: &["dbg-tcp"],
doc: "Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters.", doc: "Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters.",
fun: debug_remote, fun: debug_remote,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "debug-eval", name: "debug-eval",
aliases: &[], aliases: &[],
doc: "Evaluate expression in current debug context.", doc: "Evaluate expression in current debug context.",
fun: debug_eval, fun: debug_eval,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "vsplit", name: "vsplit",
aliases: &["vs"], aliases: &["vs"],
doc: "Open the file in a vertical split.", doc: "Open the file in a vertical split.",
fun: vsplit, fun: vsplit,
completer: Some(completers::filename), signature: CommandSignature::all(completers::filename)
}, },
TypableCommand { TypableCommand {
name: "vsplit-new", name: "vsplit-new",
aliases: &["vnew"], aliases: &["vnew"],
doc: "Open a scratch buffer in a vertical split.", doc: "Open a scratch buffer in a vertical split.",
fun: vsplit_new, fun: vsplit_new,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "hsplit", name: "hsplit",
aliases: &["hs", "sp"], aliases: &["hs", "sp"],
doc: "Open the file in a horizontal split.", doc: "Open the file in a horizontal split.",
fun: hsplit, fun: hsplit,
completer: Some(completers::filename), signature: CommandSignature::all(completers::filename)
}, },
TypableCommand { TypableCommand {
name: "hsplit-new", name: "hsplit-new",
aliases: &["hnew"], aliases: &["hnew"],
doc: "Open a scratch buffer in a horizontal split.", doc: "Open a scratch buffer in a horizontal split.",
fun: hsplit_new, fun: hsplit_new,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "tutor", name: "tutor",
aliases: &[], aliases: &[],
doc: "Open the tutorial.", doc: "Open the tutorial.",
fun: tutor, fun: tutor,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "goto", name: "goto",
aliases: &["g"], aliases: &["g"],
doc: "Goto line number.", doc: "Goto line number.",
fun: goto_line_number, fun: goto_line_number,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "set-language", name: "set-language",
aliases: &["lang"], aliases: &["lang"],
doc: "Set the language of current buffer (show current language if no value specified).", doc: "Set the language of current buffer (show current language if no value specified).",
fun: language, fun: language,
completer: Some(completers::language), signature: CommandSignature::positional(&[completers::language]),
}, },
TypableCommand { TypableCommand {
name: "set-option", name: "set-option",
aliases: &["set"], aliases: &["set"],
doc: "Set a config option at runtime.\nFor example to disable smart case search, use `:set search.smart-case false`.", doc: "Set a config option at runtime.\nFor example to disable smart case search, use `:set search.smart-case false`.",
fun: set_option, fun: set_option,
completer: Some(completers::setting), // TODO: Add support for completion of the options value(s), when appropriate.
signature: CommandSignature::positional(&[completers::setting]),
}, },
TypableCommand { TypableCommand {
name: "toggle-option", name: "toggle-option",
aliases: &["toggle"], aliases: &["toggle"],
doc: "Toggle a boolean config option at runtime.\nFor example to toggle smart case search, use `:toggle search.smart-case`.", doc: "Toggle a boolean config option at runtime.\nFor example to toggle smart case search, use `:toggle search.smart-case`.",
fun: toggle_option, fun: toggle_option,
completer: Some(completers::setting), signature: CommandSignature::positional(&[completers::setting]),
}, },
TypableCommand { TypableCommand {
name: "get-option", name: "get-option",
aliases: &["get"], aliases: &["get"],
doc: "Get the current value of a config option.", doc: "Get the current value of a config option.",
fun: get_option, fun: get_option,
completer: Some(completers::setting), signature: CommandSignature::positional(&[completers::setting]),
}, },
TypableCommand { TypableCommand {
name: "sort", name: "sort",
aliases: &[], aliases: &[],
doc: "Sort ranges in selection.", doc: "Sort ranges in selection.",
fun: sort, fun: sort,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "rsort", name: "rsort",
aliases: &[], aliases: &[],
doc: "Sort ranges in selection in reverse order.", doc: "Sort ranges in selection in reverse order.",
fun: sort_reverse, fun: sort_reverse,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "reflow", name: "reflow",
aliases: &[], aliases: &[],
doc: "Hard-wrap the current selection of lines to a given width.", doc: "Hard-wrap the current selection of lines to a given width.",
fun: reflow, fun: reflow,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "tree-sitter-subtree", name: "tree-sitter-subtree",
aliases: &["ts-subtree"], aliases: &["ts-subtree"],
doc: "Display tree sitter subtree under cursor, primarily for debugging queries.", doc: "Display tree sitter subtree under cursor, primarily for debugging queries.",
fun: tree_sitter_subtree, fun: tree_sitter_subtree,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "config-reload", name: "config-reload",
aliases: &[], aliases: &[],
doc: "Refresh user config.", doc: "Refresh user config.",
fun: refresh_config, fun: refresh_config,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "config-open", name: "config-open",
aliases: &[], aliases: &[],
doc: "Open the user config.toml file.", doc: "Open the user config.toml file.",
fun: open_config, fun: open_config,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "log-open", name: "log-open",
aliases: &[], aliases: &[],
doc: "Open the helix log file.", doc: "Open the helix log file.",
fun: open_log, fun: open_log,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "insert-output", name: "insert-output",
aliases: &[], aliases: &[],
doc: "Run shell command, inserting output before each selection.", doc: "Run shell command, inserting output before each selection.",
fun: insert_output, fun: insert_output,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "append-output", name: "append-output",
aliases: &[], aliases: &[],
doc: "Run shell command, appending output after each selection.", doc: "Run shell command, appending output after each selection.",
fun: append_output, fun: append_output,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "pipe", name: "pipe",
aliases: &[], aliases: &[],
doc: "Pipe each selection to the shell command.", doc: "Pipe each selection to the shell command.",
fun: pipe, fun: pipe,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "pipe-to", name: "pipe-to",
aliases: &[], aliases: &[],
doc: "Pipe each selection to the shell command, ignoring output.", doc: "Pipe each selection to the shell command, ignoring output.",
fun: pipe_to, fun: pipe_to,
completer: None, signature: CommandSignature::none(),
}, },
TypableCommand { TypableCommand {
name: "run-shell-command", name: "run-shell-command",
aliases: &["sh"], aliases: &["sh"],
doc: "Run a shell command", doc: "Run a shell command",
fun: run_shell_command, fun: run_shell_command,
completer: Some(completers::filename), signature: CommandSignature::all(completers::filename)
}, },
TypableCommand { TypableCommand {
name: "reset-diff-change", name: "reset-diff-change",
@ -2665,8 +2710,6 @@ pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableComma
#[allow(clippy::unnecessary_unwrap)] #[allow(clippy::unnecessary_unwrap)]
pub(super) fn command_mode(cx: &mut Context) { pub(super) fn command_mode(cx: &mut Context) {
use shellwords::Shellwords;
let mut prompt = Prompt::new( let mut prompt = Prompt::new(
":".into(), ":".into(),
Some(':'), Some(':'),
@ -2705,10 +2748,11 @@ pub(super) fn command_mode(cx: &mut Context) {
) )
}; };
if let Some(typed::TypableCommand { let argument_number = argument_number_of(&shellwords);
completer: Some(completer),
.. if let Some(completer) = TYPABLE_COMMAND_MAP
}) = typed::TYPABLE_COMMAND_MAP.get(&words[0] as &str) .get(&words[0] as &str)
.map(|tc| tc.completer_for_argument_number(argument_number))
{ {
completer(editor, part) completer(editor, part)
.into_iter() .into_iter()
@ -2773,3 +2817,29 @@ pub(super) fn command_mode(cx: &mut Context) {
prompt.recalculate_completion(cx.editor); prompt.recalculate_completion(cx.editor);
cx.push_layer(Box::new(prompt)); cx.push_layer(Box::new(prompt));
} }
fn argument_number_of(shellwords: &Shellwords) -> usize {
if shellwords.ends_with_whitespace() {
shellwords.words().len().saturating_sub(1)
} else {
shellwords.words().len().saturating_sub(2)
}
}
#[test]
fn test_argument_number_of() {
let cases = vec![
("set-option", 0),
("set-option ", 0),
("set-option a", 0),
("set-option asdf", 0),
("set-option asdf ", 1),
("set-option asdf xyz", 1),
("set-option asdf xyz abc", 2),
("set-option asdf xyz abc ", 3),
];
for case in cases {
assert_eq!(case.1, argument_number_of(&Shellwords::from(case.0)));
}
}

Loading…
Cancel
Save