diff --git a/Makefile.in b/Makefile.in index 5889ff5d8..2c565d28c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -98,7 +98,8 @@ HAVE_DOXYGEN=@HAVE_DOXYGEN@ # # All objects that the system needs to build fish, except fish.o # -FISH_OBJS := obj/autoload.o obj/builtin.o obj/builtin_bind.o obj/builtin_commandline.o \ +FISH_OBJS := obj/autoload.o obj/builtin.o obj/builtin_bind.o obj/builtin_block.o \ + obj/builtin_commandline.o \ obj/builtin_complete.o obj/builtin_jobs.o obj/builtin_printf.o \ obj/builtin_set.o obj/builtin_set_color.o obj/builtin_string.o \ obj/builtin_test.o obj/builtin_ulimit.o obj/color.o obj/common.o \ @@ -939,7 +940,7 @@ V0 := @ V1 := v = $(V$(V)) -# DO NOT DELETE THIS LINE -- make depend depends on it. +# DO NOT DELETE THIS LINE -- `make depend` depends on it. obj/autoload.o: config.h src/autoload.h src/common.h src/fallback.h obj/autoload.o: src/signal.h src/lru.h src/env.h src/exec.h src/wutil.h diff --git a/src/builtin.cpp b/src/builtin.cpp index 34bd7febc..aaaf02538 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -39,6 +39,7 @@ #include "builtin.h" #include "builtin_bind.h" +#include "builtin_block.h" #include "builtin_commandline.h" #include "builtin_complete.h" #include "builtin_jobs.h" @@ -244,110 +245,6 @@ void builtin_missing_argument(parser_t &parser, io_streams_t &streams, const wch builtin_print_help(parser, streams, cmd, streams.err); } -/// The block builtin, used for temporarily blocking events. -static int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) { - enum { - UNSET, - GLOBAL, - LOCAL, - }; - - int scope = UNSET; - int erase = 0; - int argc = builtin_count_args(argv); - - static const wchar_t *short_options = L"eghl"; - static const struct woption long_options[] = {{L"erase", no_argument, NULL, 'e'}, - {L"local", no_argument, NULL, 'l'}, - {L"global", no_argument, NULL, 'g'}, - {L"help", no_argument, NULL, 'h'}, - {NULL, 0, NULL, 0}}; - - int opt; - wgetopter_t w; - while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) { - switch (opt) { - case 'h': { - builtin_print_help(parser, streams, argv[0], streams.out); - return STATUS_CMD_OK; - } - case 'g': { - scope = GLOBAL; - break; - } - case 'l': { - scope = LOCAL; - break; - } - case 'e': { - erase = 1; - break; - } - case '?': { - builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]); - return STATUS_INVALID_ARGS; - } - default: { - DIE("unexpected retval from wgetopt_long"); - break; - } - } - } - - if (erase) { - if (scope != UNSET) { - streams.err.append_format(_(L"%ls: Can not specify scope when removing block\n"), - argv[0]); - return STATUS_INVALID_ARGS; - } - - if (parser.global_event_blocks.empty()) { - streams.err.append_format(_(L"%ls: No blocks defined\n"), argv[0]); - return STATUS_CMD_ERROR; - } - parser.global_event_blocks.pop_front(); - } else { - size_t block_idx = 0; - block_t *block = parser.block_at_index(block_idx); - - event_blockage_t eb = {}; - eb.typemask = (1 << EVENT_ANY); - - switch (scope) { - case LOCAL: { - // If this is the outermost block, then we're global - if (block_idx + 1 >= parser.block_count()) { - block = NULL; - } - break; - } - case GLOBAL: { - block = NULL; - break; - } - case UNSET: { - while (block != NULL && block->type() != FUNCTION_CALL && - block->type() != FUNCTION_CALL_NO_SHADOW) { - // Set it in function scope - block = parser.block_at_index(++block_idx); - } - break; - } - default: { - DIE("unexpected scope"); - break; - } - } - if (block) { - block->event_blocks.push_front(eb); - } else { - parser.global_event_blocks.push_front(eb); - } - } - - 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. diff --git a/src/builtin_bind.h b/src/builtin_bind.h index 6a5f6f41a..8145bb60d 100644 --- a/src/builtin_bind.h +++ b/src/builtin_bind.h @@ -1,4 +1,4 @@ -// Prototypes for functions for executing builtin_bind functions. +// Prototypes for executing builtin_bind function. #ifndef FISH_BUILTIN_BIND_H #define FISH_BUILTIN_BIND_H diff --git a/src/builtin_block.cpp b/src/builtin_block.cpp new file mode 100644 index 000000000..b97e33c29 --- /dev/null +++ b/src/builtin_block.cpp @@ -0,0 +1,135 @@ +// Implementation of the bind builtin. +#include "config.h" // IWYU pragma: keep + +#include + +#include "builtin.h" +#include "builtin_block.h" +#include "common.h" +#include "event.h" +#include "fallback.h" // IWYU pragma: keep +#include "io.h" +#include "parser.h" +#include "wgetopt.h" +#include "wutil.h" // IWYU pragma: keep + +enum { UNSET, GLOBAL, LOCAL }; +struct block_opts { + int scope = UNSET; + bool erase = false; + bool print_help = false; +}; + +static int parse_block_opts(struct block_opts *opts, int *optind, //!OCLINT(high ncss method) + int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) { + wchar_t *cmd = argv[0]; + static const wchar_t *short_options = L"eghl"; + static const struct woption long_options[] = {{L"erase", no_argument, NULL, 'e'}, + {L"local", no_argument, NULL, 'l'}, + {L"global", no_argument, NULL, 'g'}, + {L"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0}}; + + int opt; + wgetopter_t w; + while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) { + switch (opt) { + case 'h': { + opts->print_help = true; + return STATUS_CMD_OK; + } + case 'g': { + opts->scope = GLOBAL; + break; + } + case 'l': { + opts->scope = LOCAL; + break; + } + case 'e': { + opts->erase = true; + break; + } + case '?': { + builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]); + return STATUS_INVALID_ARGS; + } + default: { + DIE("unexpected retval from wgetopt_long"); + break; + } + } + } + + *optind = w.woptind; + return STATUS_CMD_OK; +} + +/// The block builtin, used for temporarily blocking events. +int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) { + const wchar_t *cmd = argv[0]; + int argc = builtin_count_args(argv); + struct block_opts opts; + + int optind; + int retval = parse_block_opts(&opts, &optind, argc, argv, parser, streams); + if (retval != STATUS_CMD_OK) return retval; + + if (opts.print_help) { + builtin_print_help(parser, streams, cmd, streams.out); + return STATUS_CMD_OK; + } + + if (opts.erase) { + if (opts.scope != UNSET) { + streams.err.append_format(_(L"%ls: Can not specify scope when removing block\n"), cmd); + return STATUS_INVALID_ARGS; + } + + if (parser.global_event_blocks.empty()) { + streams.err.append_format(_(L"%ls: No blocks defined\n"), cmd); + return STATUS_CMD_ERROR; + } + parser.global_event_blocks.pop_front(); + return STATUS_CMD_OK; + } + + size_t block_idx = 0; + block_t *block = parser.block_at_index(block_idx); + + event_blockage_t eb = {}; + eb.typemask = (1 << EVENT_ANY); + + switch (opts.scope) { + case LOCAL: { + // If this is the outermost block, then we're global + if (block_idx + 1 >= parser.block_count()) { + block = NULL; + } + break; + } + case GLOBAL: { + block = NULL; + break; + } + case UNSET: { + while (block != NULL && block->type() != FUNCTION_CALL && + block->type() != FUNCTION_CALL_NO_SHADOW) { + // Set it in function scope + block = parser.block_at_index(++block_idx); + } + break; + } + default: { + DIE("unexpected scope"); + break; + } + } + if (block) { + block->event_blocks.push_front(eb); + } else { + parser.global_event_blocks.push_front(eb); + } + + return STATUS_CMD_OK; +} diff --git a/src/builtin_block.h b/src/builtin_block.h new file mode 100644 index 000000000..5399c4fa6 --- /dev/null +++ b/src/builtin_block.h @@ -0,0 +1,9 @@ +// Prototypes for executing builtin_block function. +#ifndef FISH_BUILTIN_BLOCK_H +#define FISH_BUILTIN_BLOCK_H + +class parser_t; +struct io_streams_t; + +int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv); +#endif