diff --git a/CMakeLists.txt b/CMakeLists.txt index 13c3d9531..3893af136 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,7 @@ endif() # List of sources for builtin functions. set(FISH_BUILTIN_SRCS src/builtin.cpp src/builtins/argparse.cpp src/builtins/bind.cpp - src/builtins/builtin.cpp src/builtins/cd.cpp + src/builtins/cd.cpp src/builtins/commandline.cpp src/builtins/complete.cpp src/builtins/disown.cpp src/builtins/eval.cpp src/builtins/fg.cpp diff --git a/fish-rust/src/builtins/mod.rs b/fish-rust/src/builtins/mod.rs index bb2ffa444..ef77556bf 100644 --- a/fish-rust/src/builtins/mod.rs +++ b/fish-rust/src/builtins/mod.rs @@ -3,6 +3,7 @@ pub mod shared; pub mod abbr; pub mod bg; pub mod block; +pub mod builtin; pub mod command; pub mod contains; pub mod echo; diff --git a/fish-rust/src/builtins/shared.rs b/fish-rust/src/builtins/shared.rs index ef0c8a5f5..bb566731e 100644 --- a/fish-rust/src/builtins/shared.rs +++ b/fish-rust/src/builtins/shared.rs @@ -39,6 +39,7 @@ pub const BUILTIN_ERR_NOT_NUMBER: &str = "%ls: %ls: invalid integer\n"; pub const BUILTIN_ERR_ARG_COUNT1: &str = "%ls: expected %d arguments; got %d\n"; pub const BUILTIN_ERR_COMBO: &str = "%ls: invalid option combination\n"; +pub const BUILTIN_ERR_COMBO2: &str = "%ls: invalid option combination, %ls\n"; // Return values (`$status` values for fish scripts) for various situations. @@ -147,6 +148,7 @@ pub fn run_builtin( RustBuiltin::Abbr => super::abbr::abbr(parser, streams, args), RustBuiltin::Bg => super::bg::bg(parser, streams, args), RustBuiltin::Block => super::block::block(parser, streams, args), + RustBuiltin::Builtin => super::builtin::builtin(parser, streams, args), RustBuiltin::Contains => super::contains::contains(parser, streams, args), RustBuiltin::Command => super::command::command(parser, streams, args), RustBuiltin::Echo => super::echo::echo(parser, streams, args), diff --git a/fish-rust/src/ffi.rs b/fish-rust/src/ffi.rs index 7ee0eefe5..7e2558939 100644 --- a/fish-rust/src/ffi.rs +++ b/fish-rust/src/ffi.rs @@ -87,6 +87,7 @@ include_cpp! { generate!("builtin_unknown_option") generate!("builtin_print_help") generate!("builtin_print_error_trailer") + generate!("builtin_get_names_ffi") generate!("escape_string") generate!("sig2wcs") diff --git a/src/builtin.cpp b/src/builtin.cpp index db0019652..ef49ccd5e 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -31,7 +31,6 @@ #include "builtins/argparse.h" #include "builtins/bind.h" -#include "builtins/builtin.h" #include "builtins/cd.h" #include "builtins/commandline.h" #include "builtins/complete.h" @@ -361,7 +360,7 @@ static constexpr builtin_data_t builtin_datas[] = { {L"block", &implemented_in_rust, N_(L"Temporarily block delivery of events")}, {L"break", &builtin_break_continue, N_(L"Stop the innermost loop")}, {L"breakpoint", &builtin_breakpoint, N_(L"Halt execution and start debug prompt")}, - {L"builtin", &builtin_builtin, N_(L"Run a builtin specifically")}, + {L"builtin", &implemented_in_rust, N_(L"Run a builtin specifically")}, {L"case", &builtin_generic, N_(L"Block of code to run conditionally")}, {L"cd", &builtin_cd, N_(L"Change working directory")}, {L"command", &implemented_in_rust, N_(L"Run a command specifically")}, @@ -502,6 +501,10 @@ wcstring_list_t builtin_get_names() { return result; } +wcstring_list_ffi_t builtin_get_names_ffi() { + return builtin_get_names(); +} + /// Insert all builtin names into list. void builtin_get_names(completion_list_t *list) { assert(list != nullptr); @@ -531,6 +534,9 @@ static maybe_t try_get_rust_builtin(const wcstring &cmd) { if (cmd == L"block") { return RustBuiltin::Block; } + if (cmd == L"builtin") { + return RustBuiltin::Builtin; + } if (cmd == L"contains") { return RustBuiltin::Contains; } diff --git a/src/builtin.h b/src/builtin.h index 5894fd2c8..53c00ad9d 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -7,6 +7,7 @@ #include "common.h" #include "complete.h" #include "maybe.h" +#include "wutil.h" class parser_t; class proc_status_t; @@ -82,6 +83,7 @@ bool builtin_exists(const wcstring &cmd); proc_status_t builtin_run(parser_t &parser, const wcstring_list_t &argv, io_streams_t &streams); wcstring_list_t builtin_get_names(); +wcstring_list_ffi_t builtin_get_names_ffi(); void builtin_get_names(completion_list_t *list); const wchar_t *builtin_get_desc(const wcstring &name); @@ -112,6 +114,7 @@ enum RustBuiltin : int32_t { Abbr, Bg, Block, + Builtin, Contains, Command, Echo, diff --git a/src/builtins/builtin.cpp b/src/builtins/builtin.cpp deleted file mode 100644 index 54ff76a47..000000000 --- a/src/builtins/builtin.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Implementation of the builtin builtin. -#include "config.h" // IWYU pragma: keep - -#include "builtin.h" - -#include -#include - -#include "../builtin.h" -#include "../common.h" -#include "../fallback.h" // IWYU pragma: keep -#include "../io.h" -#include "../maybe.h" -#include "../wgetopt.h" -#include "../wutil.h" // IWYU pragma: keep - -struct builtin_cmd_opts_t { - bool print_help = false; - bool list_names = false; - bool query = false; -}; -static const wchar_t *const short_options = L":hnq"; -static const struct woption long_options[] = { - {L"help", no_argument, 'h'}, {L"names", no_argument, 'n'}, {L"query", no_argument, 'q'}, {}}; - -static int parse_cmd_opts(builtin_cmd_opts_t &opts, int *optind, int argc, const wchar_t **argv, - parser_t &parser, io_streams_t &streams) { - const wchar_t *cmd = argv[0]; - int opt; - wgetopter_t w; - while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, nullptr)) != -1) { - switch (opt) { - case 'h': { - opts.print_help = true; - break; - } - case 'n': { - opts.list_names = true; - break; - } - case 'q': { - opts.query = true; - break; - } - case ':': { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]); - return STATUS_INVALID_ARGS; - } - case '?': { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]); - return STATUS_INVALID_ARGS; - } - default: { - DIE("unexpected retval from wgetopt_long"); - } - } - } - - *optind = w.woptind; - return STATUS_CMD_OK; -} - -/// The builtin builtin, used for giving builtins precedence over functions. Mostly handled by the -/// parser. All this code does is some additional operational modes, such as printing a list of all -/// builtins, printing help, etc. -maybe_t builtin_builtin(parser_t &parser, io_streams_t &streams, const wchar_t **argv) { - const wchar_t *cmd = argv[0]; - int argc = builtin_count_args(argv); - builtin_cmd_opts_t opts; - - int optind; - int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams); - if (retval != STATUS_CMD_OK) return retval; - - if (opts.print_help) { - builtin_print_help(parser, streams, cmd); - return STATUS_CMD_OK; - } - - if (opts.query && opts.list_names) { - streams.err.append_format(BUILTIN_ERR_COMBO2, cmd, - _(L"--query and --names are mutually exclusive")); - return STATUS_INVALID_ARGS; - } - - if (opts.query) { - wcstring_list_t names = builtin_get_names(); - retval = STATUS_CMD_ERROR; - for (int i = optind; i < argc; i++) { - if (contains(names, argv[i])) { - retval = STATUS_CMD_OK; - break; - } - } - return retval; - } - - if (opts.list_names) { - wcstring_list_t names = builtin_get_names(); - std::sort(names.begin(), names.end()); - - for (auto &name : names) { - streams.out.append(name + L"\n"); - } - } - - return STATUS_CMD_OK; -} diff --git a/src/builtins/builtin.h b/src/builtins/builtin.h deleted file mode 100644 index 355320cb2..000000000 --- a/src/builtins/builtin.h +++ /dev/null @@ -1,11 +0,0 @@ -// Prototypes for executing builtin_builtin function. -#ifndef FISH_BUILTIN_BUILTIN_H -#define FISH_BUILTIN_BUILTIN_H - -#include "../maybe.h" - -class parser_t; -struct io_streams_t; - -maybe_t builtin_builtin(parser_t &parser, io_streams_t &streams, const wchar_t **argv); -#endif