diff --git a/src/builtin.cpp b/src/builtin.cpp
index af5388ab4..14641071d 100644
--- a/src/builtin.cpp
+++ b/src/builtin.cpp
@@ -4,7 +4,7 @@
//
// 1). Create a function in builtin.c with the following signature:
//
-// static int builtin_NAME(parser_t &parser, io_streams_t &streams, wchar_t **argv)
+// static maybe_t builtin_NAME(parser_t &parser, io_streams_t &streams, wchar_t **argv)
//
// where NAME is the name of the builtin, and args is a zero-terminated list of arguments.
//
@@ -201,7 +201,7 @@ void builtin_print_error_trailer(parser_t &parser, output_stream_t &b, const wch
/// A generic bultin that only supports showing a help message. This is only a placeholder that
/// prints the help message. Useful for commands that live in the parser.
-static int builtin_generic(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+static maybe_t builtin_generic(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;
@@ -228,7 +228,7 @@ static int builtin_generic(parser_t &parser, io_streams_t &streams, wchar_t **ar
// Since this is just for counting, it can be massive.
#define COUNT_CHUNK_SIZE (512 * 256)
/// Implementation of the builtin count command, used to count the number of arguments sent to it.
-static int builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+static maybe_t builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
int argc = 0;
@@ -256,7 +256,7 @@ static int builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv
/// This function handles both the 'continue' and the 'break' builtins that are used for loop
/// control.
-static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+static maybe_t builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
int is_break = (std::wcscmp(argv[0], L"break") == 0);
int argc = builtin_count_args(argv);
@@ -287,7 +287,7 @@ static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar
}
/// Implementation of the builtin breakpoint command, used to launch the interactive debugger.
-static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+static maybe_t builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
if (argv[1] != nullptr) {
streams.err.append_format(BUILTIN_ERR_ARG_COUNT1, cmd, 0, builtin_count_args(argv) - 1);
@@ -313,21 +313,21 @@ static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t *
return parser.get_last_status();
}
-int builtin_true(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_true(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
UNUSED(streams);
UNUSED(argv);
return STATUS_CMD_OK;
}
-int builtin_false(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_false(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
UNUSED(streams);
UNUSED(argv);
return STATUS_CMD_ERROR;
}
-int builtin_gettext(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_gettext(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
UNUSED(streams);
for (int i = 1; i < builtin_count_args(argv); i++) {
@@ -459,8 +459,11 @@ proc_status_t builtin_run(parser_t &parser, wchar_t **argv, io_streams_t &stream
}
if (const builtin_data_t *data = builtin_lookup(argv[0])) {
- int ret = data->func(parser, streams, argv);
- return proc_status_t::from_exit_code(ret);
+ maybe_t ret = data->func(parser, streams, argv);
+ if (!ret) {
+ return proc_status_t::empty();
+ }
+ return proc_status_t::from_exit_code(ret.value());
}
FLOGF(error, UNKNOWN_BUILTIN_ERR_MSG, argv[0]);
diff --git a/src/builtin.h b/src/builtin.h
index 1629c4a79..88e01769a 100644
--- a/src/builtin.h
+++ b/src/builtin.h
@@ -20,7 +20,7 @@ struct builtin_data_t {
// Name of the builtin.
const wchar_t *name;
// Function pointer to the builtin implementation.
- int (*func)(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+ maybe_t (*func)(parser_t &parser, io_streams_t &streams, wchar_t **argv);
// Description of what the builtin does.
const wchar_t *desc;
diff --git a/src/builtin_argparse.cpp b/src/builtin_argparse.cpp
index bde552ef1..76f73dc3c 100644
--- a/src/builtin_argparse.cpp
+++ b/src/builtin_argparse.cpp
@@ -684,7 +684,7 @@ static void set_argparse_result_vars(env_stack_t &vars, const argparse_cmd_opts_
/// an external command also means its output has to be in a form that can be eval'd. Because our
/// version is a builtin it can directly set variables local to the current scope (e.g., a
/// function). It doesn't need to write anything to stdout that then needs to be eval'd.
-int builtin_argparse(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_argparse(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
argparse_cmd_opts_t opts;
diff --git a/src/builtin_argparse.h b/src/builtin_argparse.h
index b515e0bce..24e4b6079 100644
--- a/src/builtin_argparse.h
+++ b/src/builtin_argparse.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_ARGPARSE_H
#define FISH_BUILTIN_ARGPARSE_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_argparse(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_argparse(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_bg.cpp b/src/builtin_bg.cpp
index 64b0ec5c8..798d72511 100644
--- a/src/builtin_bg.cpp
+++ b/src/builtin_bg.cpp
@@ -37,7 +37,7 @@ static int send_to_bg(parser_t &parser, io_streams_t &streams, job_t *j) {
}
/// Builtin for putting a job in the background.
-int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;
diff --git a/src/builtin_bg.h b/src/builtin_bg.h
index 3fcb3d0c0..bb628a433 100644
--- a/src/builtin_bg.h
+++ b/src/builtin_bg.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_BG_H
#define FISH_BUILTIN_BG_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_bind.cpp b/src/builtin_bind.cpp
index 3c7c088e1..f497f8a68 100644
--- a/src/builtin_bind.cpp
+++ b/src/builtin_bind.cpp
@@ -413,7 +413,7 @@ int parse_cmd_opts(bind_cmd_opts_t &opts, int *optind, //!OCLINT(high ncss meth
}
/// The bind builtin, used for setting character sequences.
-int builtin_bind_t::builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_bind_t::builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
bind_cmd_opts_t opts;
diff --git a/src/builtin_bind.h b/src/builtin_bind.h
index 769fea782..a6050f93e 100644
--- a/src/builtin_bind.h
+++ b/src/builtin_bind.h
@@ -11,7 +11,7 @@ struct bind_cmd_opts_t;
class builtin_bind_t {
public:
- int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+ maybe_t builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv);
builtin_bind_t() : input_mappings_(input_mappings()) {}
@@ -38,7 +38,7 @@ class builtin_bind_t {
io_streams_t &streams);
};
-inline int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+inline maybe_t builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
builtin_bind_t bind;
return bind.builtin_bind(parser, streams, argv);
}
diff --git a/src/builtin_block.cpp b/src/builtin_block.cpp
index fcf2dd3a2..e2e9b78d8 100644
--- a/src/builtin_block.cpp
+++ b/src/builtin_block.cpp
@@ -70,7 +70,7 @@ static int parse_cmd_opts(block_cmd_opts_t &opts, int *optind, //!OCLINT(high n
}
/// The block builtin, used for temporarily blocking events.
-int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
block_cmd_opts_t opts;
diff --git a/src/builtin_block.h b/src/builtin_block.h
index 5399c4fa6..96cf844cf 100644
--- a/src/builtin_block.h
+++ b/src/builtin_block.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_BLOCK_H
#define FISH_BUILTIN_BLOCK_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_builtin.cpp b/src/builtin_builtin.cpp
index 7e94ee2a1..30d291274 100644
--- a/src/builtin_builtin.cpp
+++ b/src/builtin_builtin.cpp
@@ -65,7 +65,7 @@ static int parse_cmd_opts(builtin_cmd_opts_t &opts, int *optind, int argc, wchar
/// 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.
-int builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
builtin_cmd_opts_t opts;
diff --git a/src/builtin_builtin.h b/src/builtin_builtin.h
index ac8493447..75e5ccc4c 100644
--- a/src/builtin_builtin.h
+++ b/src/builtin_builtin.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_BUILTIN_H
#define FISH_BUILTIN_BUILTIN_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_cd.cpp b/src/builtin_cd.cpp
index 93d1bd204..a09c05edb 100644
--- a/src/builtin_cd.cpp
+++ b/src/builtin_cd.cpp
@@ -20,7 +20,7 @@
/// The cd builtin. Changes the current directory to the one specified or to $HOME if none is
/// specified. The directory can be relative to any directory in the CDPATH variable.
-int builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;
diff --git a/src/builtin_cd.h b/src/builtin_cd.h
index 85aa8cb28..a28a85f4c 100644
--- a/src/builtin_cd.h
+++ b/src/builtin_cd.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_CD_H
#define FISH_BUILTIN_CD_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_command.cpp b/src/builtin_command.cpp
index 6de2347ac..462e33a84 100644
--- a/src/builtin_command.cpp
+++ b/src/builtin_command.cpp
@@ -73,7 +73,7 @@ static int parse_cmd_opts(command_cmd_opts_t &opts, int *optind, int argc, wchar
/// Implementation of the builtin 'command'. Actual command running is handled by the parser, this
/// just processes the flags.
-int builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
command_cmd_opts_t opts;
diff --git a/src/builtin_command.h b/src/builtin_command.h
index 75f5fc1e6..8557bc13d 100644
--- a/src/builtin_command.h
+++ b/src/builtin_command.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_COMMAND_H
#define FISH_BUILTIN_COMMAND_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_commandline.cpp b/src/builtin_commandline.cpp
index 1ee6fbc93..a4bcf9768 100644
--- a/src/builtin_commandline.cpp
+++ b/src/builtin_commandline.cpp
@@ -121,7 +121,7 @@ static void write_part(const wchar_t *begin, const wchar_t *end, int cut_at_curs
}
/// The commandline builtin. It is used for specifying a new value for the commandline.
-int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// Pointer to what the commandline builtin considers to be the current contents of the command
// line buffer.
const wchar_t *current_buffer = nullptr;
diff --git a/src/builtin_commandline.h b/src/builtin_commandline.h
index 5237d240f..277056ae5 100644
--- a/src/builtin_commandline.h
+++ b/src/builtin_commandline.h
@@ -7,5 +7,5 @@
class parser_t;
-int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_complete.cpp b/src/builtin_complete.cpp
index 2d6f9552c..9d70ca550 100644
--- a/src/builtin_complete.cpp
+++ b/src/builtin_complete.cpp
@@ -110,7 +110,7 @@ static void builtin_complete_remove(const wcstring_list_t &cmds, const wcstring_
/// The complete builtin. Used for specifying programmable tab-completions. Calls the functions in
// complete.cpp for any heavy lifting.
-int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
ASSERT_IS_MAIN_THREAD();
wchar_t *cmd = argv[0];
diff --git a/src/builtin_complete.h b/src/builtin_complete.h
index f69d98356..c2f3ab31b 100644
--- a/src/builtin_complete.h
+++ b/src/builtin_complete.h
@@ -7,5 +7,5 @@
class parser_t;
-int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_contains.cpp b/src/builtin_contains.cpp
index 91ddb3c14..389ad0916 100644
--- a/src/builtin_contains.cpp
+++ b/src/builtin_contains.cpp
@@ -58,7 +58,7 @@ static int parse_cmd_opts(contains_cmd_opts_t &opts, int *optind, int argc, wcha
/// Implementation of the builtin contains command, used to check if a specified string is part of
/// a list.
-int builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
contains_cmd_opts_t opts;
diff --git a/src/builtin_contains.h b/src/builtin_contains.h
index f331846f1..fca65875c 100644
--- a/src/builtin_contains.h
+++ b/src/builtin_contains.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_CONTAINS_H
#define FISH_BUILTIN_CONTAINS_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_disown.cpp b/src/builtin_disown.cpp
index 510044803..cfccefa7a 100644
--- a/src/builtin_disown.cpp
+++ b/src/builtin_disown.cpp
@@ -42,7 +42,7 @@ static int disown_job(const wchar_t *cmd, parser_t &parser, io_streams_t &stream
}
/// Builtin for removing jobs from the job list.
-int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;
diff --git a/src/builtin_disown.h b/src/builtin_disown.h
index 4469880e1..d6c836928 100644
--- a/src/builtin_disown.h
+++ b/src/builtin_disown.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_DISOWN_H
#define FISH_BUILTIN_DISOWN_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_echo.cpp b/src/builtin_echo.cpp
index bac2adf85..9d2c78e71 100644
--- a/src/builtin_echo.cpp
+++ b/src/builtin_echo.cpp
@@ -180,7 +180,7 @@ static bool builtin_echo_parse_numeric_sequence(const wchar_t *str, size_t *cons
///
/// Bash only respects -n if it's the first argument. We'll do the same. We also support a new,
/// fish specific, option -s to mean "no spaces".
-int builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
UNUSED(cmd);
int argc = builtin_count_args(argv);
diff --git a/src/builtin_echo.h b/src/builtin_echo.h
index ecf133700..612e869a7 100644
--- a/src/builtin_echo.h
+++ b/src/builtin_echo.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_ECHO_H
#define FISH_BUILTIN_ECHO_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_emit.cpp b/src/builtin_emit.cpp
index b837b30ab..161d652a0 100644
--- a/src/builtin_emit.cpp
+++ b/src/builtin_emit.cpp
@@ -11,7 +11,7 @@
#include "wutil.h" // IWYU pragma: keep
/// Implementation of the builtin emit command, used to create events.
-int builtin_emit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_emit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;
diff --git a/src/builtin_emit.h b/src/builtin_emit.h
index 0bf500002..6ca671d88 100644
--- a/src/builtin_emit.h
+++ b/src/builtin_emit.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_EMIT_H
#define FISH_BUILTIN_EMIT_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_emit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_emit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_eval.cpp b/src/builtin_eval.cpp
index e8da6c7c8..d095cf61b 100644
--- a/src/builtin_eval.cpp
+++ b/src/builtin_eval.cpp
@@ -15,7 +15,7 @@
#include "wutil.h" // IWYU pragma: keep
/// Implementation of eval builtin.
-int builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
int argc = builtin_count_args(argv);
if (argc <= 1) {
return STATUS_CMD_OK;
diff --git a/src/builtin_eval.h b/src/builtin_eval.h
index 6cceaacc3..ae67c7da9 100644
--- a/src/builtin_eval.h
+++ b/src/builtin_eval.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_EVAL_H
#define FISH_BUILTIN_EVAL_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_exit.cpp b/src/builtin_exit.cpp
index 8073dee53..51e2dffc4 100644
--- a/src/builtin_exit.cpp
+++ b/src/builtin_exit.cpp
@@ -58,7 +58,7 @@ static int parse_cmd_opts(exit_cmd_opts_t &opts, int *optind, //!OCLINT(high nc
}
/// The exit builtin. Calls reader_exit to exit and returns the value specified.
-int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
exit_cmd_opts_t opts;
diff --git a/src/builtin_exit.h b/src/builtin_exit.h
index 1a279ab5f..f446daddf 100644
--- a/src/builtin_exit.h
+++ b/src/builtin_exit.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_EXIT_H
#define FISH_BUILTIN_EXIT_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_fg.cpp b/src/builtin_fg.cpp
index 7bc05f467..1211c27c1 100644
--- a/src/builtin_fg.cpp
+++ b/src/builtin_fg.cpp
@@ -21,7 +21,7 @@
#include "wutil.h" // IWYU pragma: keep
/// Builtin for putting a job in the foreground.
-int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;
diff --git a/src/builtin_fg.h b/src/builtin_fg.h
index 251ce157b..8503f7286 100644
--- a/src/builtin_fg.h
+++ b/src/builtin_fg.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_FG_H
#define FISH_BUILTIN_FG_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_function.cpp b/src/builtin_function.cpp
index 5300b3e07..ef7c329ae 100644
--- a/src/builtin_function.cpp
+++ b/src/builtin_function.cpp
@@ -199,7 +199,7 @@ static int validate_function_name(int argc, const wchar_t *const *argv, wcstring
/// Define a function. Calls into `function.cpp` to perform the heavy lifting of defining a
/// function.
-int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args,
+maybe_t builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args,
const parsed_source_ref_t &source, const ast::block_statement_t &func_node) {
assert(source && "Missing source in builtin_function");
// The wgetopt function expects 'function' as the first argument. Make a new wcstring_list with
diff --git a/src/builtin_function.h b/src/builtin_function.h
index 4da1a378c..e9aae2183 100644
--- a/src/builtin_function.h
+++ b/src/builtin_function.h
@@ -12,6 +12,6 @@ namespace ast {
struct block_statement_t;
}
-int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args,
+maybe_t builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args,
const parsed_source_ref_t &source, const ast::block_statement_t &func_node);
#endif
diff --git a/src/builtin_functions.cpp b/src/builtin_functions.cpp
index 7cf37d9c1..7e08a5415 100644
--- a/src/builtin_functions.cpp
+++ b/src/builtin_functions.cpp
@@ -282,7 +282,7 @@ static int report_function_metadata(const wchar_t *funcname, bool verbose, io_st
}
/// The functions builtin, used for listing and erasing functions.
-int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
functions_cmd_opts_t opts;
diff --git a/src/builtin_functions.h b/src/builtin_functions.h
index c7d4b3d6f..1746eaac3 100644
--- a/src/builtin_functions.h
+++ b/src/builtin_functions.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_FUNCTIONS_H
#define FISH_BUILTIN_FUNCTIONS_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_history.cpp b/src/builtin_history.cpp
index 0009f58d2..61716a77f 100644
--- a/src/builtin_history.cpp
+++ b/src/builtin_history.cpp
@@ -200,7 +200,7 @@ static int parse_cmd_opts(history_cmd_opts_t &opts, int *optind, //!OCLINT(high
}
/// Manipulate history of interactive commands executed by the user.
-int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
history_cmd_opts_t opts;
diff --git a/src/builtin_history.h b/src/builtin_history.h
index 7c27ed932..3aef6aacd 100644
--- a/src/builtin_history.h
+++ b/src/builtin_history.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_HISTORY_H
#define FISH_BUILTIN_HISTORY_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_jobs.cpp b/src/builtin_jobs.cpp
index 9ac98c1bd..8248c3c5f 100644
--- a/src/builtin_jobs.cpp
+++ b/src/builtin_jobs.cpp
@@ -121,7 +121,7 @@ static void builtin_jobs_print(const job_t *j, int mode, int header, io_streams_
}
/// The jobs builtin. Used for printing running jobs. Defined in builtin_jobs.c.
-int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
bool found = false;
diff --git a/src/builtin_jobs.h b/src/builtin_jobs.h
index adb3cfba0..a92375573 100644
--- a/src/builtin_jobs.h
+++ b/src/builtin_jobs.h
@@ -7,5 +7,5 @@
class parser_t;
-int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_math.cpp b/src/builtin_math.cpp
index ac0caee6b..84111fb39 100644
--- a/src/builtin_math.cpp
+++ b/src/builtin_math.cpp
@@ -232,7 +232,7 @@ static int evaluate_expression(const wchar_t *cmd, const parser_t &parser, io_st
}
/// The math builtin evaluates math expressions.
-int builtin_math(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_math(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
math_cmd_opts_t opts;
diff --git a/src/builtin_math.h b/src/builtin_math.h
index 76d5a5da8..80ef56702 100644
--- a/src/builtin_math.h
+++ b/src/builtin_math.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_MATH_H
#define FISH_BUILTIN_MATH_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_math(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_math(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_printf.cpp b/src/builtin_printf.cpp
index 834fbc178..61cef9fcd 100644
--- a/src/builtin_printf.cpp
+++ b/src/builtin_printf.cpp
@@ -737,7 +737,7 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
}
/// The printf builtin.
-int builtin_printf(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_printf(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;
diff --git a/src/builtin_printf.h b/src/builtin_printf.h
index 4248d9785..08be3e076 100644
--- a/src/builtin_printf.h
+++ b/src/builtin_printf.h
@@ -7,5 +7,5 @@
class parser_t;
-int builtin_printf(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_printf(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_pwd.cpp b/src/builtin_pwd.cpp
index e3619881f..907a04fdf 100644
--- a/src/builtin_pwd.cpp
+++ b/src/builtin_pwd.cpp
@@ -19,7 +19,7 @@ static const struct woption long_options[] = {{L"help", no_argument, nullptr, 'h
{L"logical", no_argument, nullptr, 'L'},
{L"physical", no_argument, nullptr, 'P'},
{nullptr, 0, nullptr, 0}};
-int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
diff --git a/src/builtin_pwd.h b/src/builtin_pwd.h
index 431a52ff5..5e7b392fa 100644
--- a/src/builtin_pwd.h
+++ b/src/builtin_pwd.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_PWD_H
#define FISH_BUILTIN_PWD_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_random.cpp b/src/builtin_random.cpp
index 46771c766..88e4c431a 100644
--- a/src/builtin_random.cpp
+++ b/src/builtin_random.cpp
@@ -27,7 +27,7 @@ static std::minstd_rand get_seeded_engine() {
}
/// The random builtin generates random numbers.
-int builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;
diff --git a/src/builtin_random.h b/src/builtin_random.h
index 878c73f25..80fd5b3f7 100644
--- a/src/builtin_random.h
+++ b/src/builtin_random.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_RANDOM_H
#define FISH_BUILTIN_RANDOM_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_read.cpp b/src/builtin_read.cpp
index b8df208b1..ed6853375 100644
--- a/src/builtin_read.cpp
+++ b/src/builtin_read.cpp
@@ -431,7 +431,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg
}
/// The read builtin. Reads from stdin and stores the values in environment variables.
-int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
wcstring buff;
diff --git a/src/builtin_read.h b/src/builtin_read.h
index c65fe5bfa..f1fdccdee 100644
--- a/src/builtin_read.h
+++ b/src/builtin_read.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_READ_H
#define FISH_BUILTIN_READ_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_realpath.cpp b/src/builtin_realpath.cpp
index 09858ee9d..1264545c8 100644
--- a/src/builtin_realpath.cpp
+++ b/src/builtin_realpath.cpp
@@ -17,7 +17,7 @@
/// An implementation of the external realpath command. Doesn't support any options.
/// In general scripts shouldn't invoke this directly. They should just use `realpath` which
/// will fallback to this builtin if an external command cannot be found.
-int builtin_realpath(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_realpath(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
help_only_cmd_opts_t opts;
int argc = builtin_count_args(argv);
diff --git a/src/builtin_realpath.h b/src/builtin_realpath.h
index 1fa7d16ad..2022e9d29 100644
--- a/src/builtin_realpath.h
+++ b/src/builtin_realpath.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_REALPATH_H
#define FISH_BUILTIN_REALPATH_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_realpath(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_realpath(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_return.cpp b/src/builtin_return.cpp
index 8c0fb302b..2c384b23b 100644
--- a/src/builtin_return.cpp
+++ b/src/builtin_return.cpp
@@ -57,7 +57,7 @@ static int parse_cmd_opts(return_cmd_opts_t &opts, int *optind, //!OCLINT(high
}
/// Function for handling the return builtin.
-int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
return_cmd_opts_t opts;
diff --git a/src/builtin_return.h b/src/builtin_return.h
index 81a3e4736..401ed6ec0 100644
--- a/src/builtin_return.h
+++ b/src/builtin_return.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_RETURN_H
#define FISH_BUILTIN_RETURN_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_set.cpp b/src/builtin_set.cpp
index 5b30cc43a..06d04852e 100644
--- a/src/builtin_set.cpp
+++ b/src/builtin_set.cpp
@@ -804,7 +804,7 @@ static int builtin_set_set(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, w
}
/// The set builtin creates, updates, and erases (removes, deletes) variables.
-int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const int incoming_exit_status = parser.get_last_status();
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
diff --git a/src/builtin_set.h b/src/builtin_set.h
index ffd517da3..04c4877cd 100644
--- a/src/builtin_set.h
+++ b/src/builtin_set.h
@@ -7,5 +7,5 @@
class parser_t;
-int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_set_color.cpp b/src/builtin_set_color.cpp
index 7320dfdcc..5d6ee22d1 100644
--- a/src/builtin_set_color.cpp
+++ b/src/builtin_set_color.cpp
@@ -67,7 +67,7 @@ static char dim_esc[] = "\x1B[2m";
#endif
/// set_color builtin.
-int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// By the time this is called we should have initialized the curses subsystem.
assert(curses_initialized);
diff --git a/src/builtin_set_color.h b/src/builtin_set_color.h
index 87ae3e37f..06be7db91 100644
--- a/src/builtin_set_color.h
+++ b/src/builtin_set_color.h
@@ -7,5 +7,5 @@
class parser_t;
-int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_source.cpp b/src/builtin_source.cpp
index 633487e90..be3ada8e7 100644
--- a/src/builtin_source.cpp
+++ b/src/builtin_source.cpp
@@ -22,7 +22,7 @@
/// The source builtin, sometimes called `.`. Evaluates the contents of a file in the current
/// context.
-int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
ASSERT_IS_MAIN_THREAD();
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
diff --git a/src/builtin_source.h b/src/builtin_source.h
index 4aaf1259e..e292727da 100644
--- a/src/builtin_source.h
+++ b/src/builtin_source.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_SOURCE_H
#define FISH_BUILTIN_SOURCE_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_status.cpp b/src/builtin_status.cpp
index 8b2cee5e3..58fbe9230 100644
--- a/src/builtin_status.cpp
+++ b/src/builtin_status.cpp
@@ -274,7 +274,7 @@ static int parse_cmd_opts(status_cmd_opts_t &opts, int *optind, //!OCLINT(high
}
/// The status builtin. Gives various status information on fish.
-int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
status_cmd_opts_t opts;
diff --git a/src/builtin_status.h b/src/builtin_status.h
index bf5eea440..01855e120 100644
--- a/src/builtin_status.h
+++ b/src/builtin_status.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_STATUS_H
#define FISH_BUILTIN_STATUS_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_string.cpp b/src/builtin_string.cpp
index e4b3c9a44..429676f79 100644
--- a/src/builtin_string.cpp
+++ b/src/builtin_string.cpp
@@ -1451,7 +1451,7 @@ string_subcommands[] = {
{nullptr, nullptr}};
/// The string builtin, for manipulating strings.
-int builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
if (argc <= 1) {
diff --git a/src/builtin_string.h b/src/builtin_string.h
index ce139a6f0..47c5e1227 100644
--- a/src/builtin_string.h
+++ b/src/builtin_string.h
@@ -7,5 +7,5 @@
class parser_t;
-int builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_test.cpp b/src/builtin_test.cpp
index b6851ebf5..717e9817f 100644
--- a/src/builtin_test.cpp
+++ b/src/builtin_test.cpp
@@ -845,7 +845,7 @@ static bool unary_primary_evaluate(test_expressions::token_t token, const wcstri
/// supports a more limited range of functionality.
///
/// Return status is the final shell status, i.e. 0 for true, 1 for false and 2 for error.
-int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
using namespace test_expressions;
diff --git a/src/builtin_test.h b/src/builtin_test.h
index b350cc639..8b8935e86 100644
--- a/src/builtin_test.h
+++ b/src/builtin_test.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_TEST_H
#define FISH_BUILTIN_TEST_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_ulimit.cpp b/src/builtin_ulimit.cpp
index df9621538..72b114cfe 100644
--- a/src/builtin_ulimit.cpp
+++ b/src/builtin_ulimit.cpp
@@ -149,7 +149,7 @@ static int set_limit(int resource, int hard, int soft, rlim_t value, io_streams_
}
/// The ulimit builtin, used for setting resource limits.
-int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
bool report_all = false;
diff --git a/src/builtin_ulimit.h b/src/builtin_ulimit.h
index 19c9348e5..1d64c39e4 100644
--- a/src/builtin_ulimit.h
+++ b/src/builtin_ulimit.h
@@ -7,5 +7,5 @@
class parser_t;
-int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/builtin_wait.cpp b/src/builtin_wait.cpp
index 06dc575d8..0d60c42a4 100644
--- a/src/builtin_wait.cpp
+++ b/src/builtin_wait.cpp
@@ -172,7 +172,7 @@ static bool find_job_by_name(const wchar_t *proc, std::vector &ids,
/// The following function is invoked on the main thread, because the job operation is not thread
/// safe. It waits for child jobs, not for child processes individually.
-int builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
+maybe_t builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
ASSERT_IS_MAIN_THREAD();
int retval = STATUS_CMD_OK;
const wchar_t *cmd = argv[0];
diff --git a/src/builtin_wait.h b/src/builtin_wait.h
index d0444c34b..a9945325b 100644
--- a/src/builtin_wait.h
+++ b/src/builtin_wait.h
@@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_WAIT_H
#define FISH_BUILTIN_WAIT_H
+#include "maybe.h"
+
class parser_t;
struct io_streams_t;
-int builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif
diff --git a/src/exec.cpp b/src/exec.cpp
index be05303d0..0202fa64c 100644
--- a/src/exec.cpp
+++ b/src/exec.cpp
@@ -289,7 +289,11 @@ static void run_internal_process_or_short_circuit(parser_t &parser, const std::s
if (p->is_last_in_job) {
FLOGF(exec_job_status, L"Set status of job %d (%ls) to %d using short circuit",
j->job_id(), j->preview().c_str(), p->status);
- parser.set_last_statuses(j->get_statuses());
+ auto statuses = j->get_statuses();
+ if (statuses) {
+ parser.set_last_statuses(statuses.value());
+ parser.libdata().status_count++;
+ }
}
} else {
run_internal_process(p, std::move(outdata), std::move(errdata), ios);
diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp
index 8ea642865..0f1b58293 100644
--- a/src/fish_tests.cpp
+++ b/src/fish_tests.cpp
@@ -2519,7 +2519,7 @@ static void test_is_potential_path() {
}
/// Test the 'test' builtin.
-int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv);
static bool run_one_test_test(int expected, wcstring_list_t &lst, bool bracket) {
parser_t &parser = parser_t::principal_parser();
size_t i, count = lst.size();
@@ -2535,13 +2535,16 @@ static bool run_one_test_test(int expected, wcstring_list_t &lst, bool bracket)
argv[i + 1] = NULL;
null_output_stream_t null{};
io_streams_t streams(null, null);
- int result = builtin_test(parser, streams, argv);
+ maybe_t result = builtin_test(parser, streams, argv);
- if (expected != result) err(L"expected builtin_test() to return %d, got %d", expected, result);
+ if (result != expected) {
+ std::wstring got = result ? std::to_wstring(result.value()) : L"nothing";
+ err(L"expected builtin_test() to return %d, got %s", expected, got.c_str());
+ }
delete[] argv;
- return expected == result;
+ return result == expected;
}
static bool run_test_test(int expected, const wcstring &str) {
@@ -5098,7 +5101,7 @@ static void test_pcre2_escape() {
}
}
-int builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv);
+maybe_t builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv);
static void run_one_string_test(const wchar_t *const *argv, int expected_rc,
const wchar_t *expected_out) {
parser_t &parser = parser_t::principal_parser();
@@ -5106,15 +5109,16 @@ static void run_one_string_test(const wchar_t *const *argv, int expected_rc,
null_output_stream_t errs{};
io_streams_t streams(outs, errs);
streams.stdin_is_directly_redirected = false; // read from argv instead of stdin
- int rc = builtin_string(parser, streams, const_cast(argv));
+ maybe_t rc = builtin_string(parser, streams, const_cast(argv));
wcstring args;
for (int i = 0; argv[i] != NULL; i++) {
args += escape_string(argv[i], ESCAPE_ALL) + L' ';
}
args.resize(args.size() - 1);
if (rc != expected_rc) {
- err(L"Test failed on line %lu: [%ls]: expected return code %d but got %d", __LINE__,
- args.c_str(), expected_rc, rc);
+ std::wstring got = rc ? std::to_wstring(rc.value()) : L"nothing";
+ err(L"Test failed on line %lu: [%ls]: expected return code %d but got %s", __LINE__,
+ args.c_str(), expected_rc, got.c_str());
} else if (outs.contents() != expected_out) {
err(L"Test failed on line %lu: [%ls]: expected [%ls] but got [%ls]", __LINE__, args.c_str(),
escape_string(expected_out, ESCAPE_ALL).c_str(),
diff --git a/src/maybe.h b/src/maybe.h
index 4f0a78800..42fe8ac3e 100644
--- a/src/maybe.h
+++ b/src/maybe.h
@@ -3,6 +3,7 @@
#include
#include
+#include
namespace maybe_detail {
// Template magic to make maybe_t copyable iff T is copyable.
diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp
index eee1fc14e..ca62ed52d 100644
--- a/src/parse_execution.cpp
+++ b/src/parse_execution.cpp
@@ -392,13 +392,17 @@ end_execution_reason_t parse_execution_context_t::run_function_statement(
buffered_output_stream_t outs(0);
buffered_output_stream_t errs(0);
io_streams_t streams(outs, errs);
- int err = builtin_function(*parser, streams, arguments, pstree, statement);
- parser->libdata().status_count++;
- parser->set_last_statuses(statuses_t::just(err));
+ int err_code = 0;
+ maybe_t err = builtin_function(*parser, streams, arguments, pstree, statement);
+ if (err) {
+ err_code = err.value();
+ parser->libdata().status_count++;
+ parser->set_last_statuses(statuses_t::just(err_code));
+ }
wcstring errtext = errs.contents();
if (!errtext.empty()) {
- return this->report_error(err, header, L"%ls", errtext.c_str());
+ return this->report_error(err_code, header, L"%ls", errtext.c_str());
}
return result;
}
diff --git a/src/proc.cpp b/src/proc.cpp
index 150f0dddd..06e46b511 100644
--- a/src/proc.cpp
+++ b/src/proc.cpp
@@ -167,17 +167,30 @@ bool job_t::signal(int signal) {
return true;
}
-statuses_t job_t::get_statuses() const {
+maybe_t job_t::get_statuses() const {
statuses_t st{};
+ bool has_status = false;
+ int laststatus = 0;
st.pipestatus.reserve(processes.size());
for (const auto &p : processes) {
auto status = p->status;
+ if (status.is_empty()) {
+ // Corner case for if a variable assignment is part of a pipeline.
+ // e.g. `false | set foo bar | true` will push 1 in the second spot,
+ // for a complete pipestatus of `1 1 0`.
+ st.pipestatus.push_back(laststatus);
+ continue;
+ }
if (status.signal_exited()) {
st.kill_signal = status.signal_code();
}
+ laststatus = status.status_value();
+ has_status = true;
st.pipestatus.push_back(status.status_value());
}
- int laststatus = st.pipestatus.back();
+ if (!has_status) {
+ return none();
+ }
st.status = flags().negate ? !laststatus : laststatus;
return st;
}
@@ -997,8 +1010,11 @@ void job_t::continue_job(parser_t &parser, bool in_foreground) {
// finished.
const auto &p = processes.back();
if (p->status.normal_exited() || p->status.signal_exited()) {
- parser.set_last_statuses(get_statuses());
- parser.libdata().status_count++;
+ auto statuses = get_statuses();
+ if (statuses) {
+ parser.set_last_statuses(statuses.value());
+ parser.libdata().status_count++;
+ }
}
}
}
diff --git a/src/proc.h b/src/proc.h
index 2700d4610..deb36a7c7 100644
--- a/src/proc.h
+++ b/src/proc.h
@@ -54,7 +54,12 @@ using job_group_ref_t = std::shared_ptr;
class proc_status_t {
int status_{};
- explicit proc_status_t(int status) : status_(status) {}
+ /// If set, there is no actual status to report, e.g. background or variable assignment.
+ bool empty_{};
+
+ explicit proc_status_t(int status) : status_(status), empty_(false) {}
+
+ proc_status_t(int status, bool empty) : status_(status), empty_(empty) {}
/// Encode a return value \p ret and signal \p sig into a status value like waitpid() does.
static constexpr int w_exitcode(int ret, int sig) {
@@ -84,6 +89,12 @@ class proc_status_t {
return proc_status_t(w_exitcode(0 /* ret */, sig));
}
+ /// Construct an empty status_t (e.g. `set foo bar`).
+ static proc_status_t empty() {
+ bool empty = true;
+ return proc_status_t(0, empty);
+ }
+
/// \return if we are stopped (as in SIGSTOP).
bool stopped() const { return WIFSTOPPED(status_); }
@@ -111,6 +122,9 @@ class proc_status_t {
/// \return if this status represents success.
bool is_success() const { return normal_exited() && exit_code() == EXIT_SUCCESS; }
+ /// \return if this status is empty.
+ bool is_empty() const { return empty_; }
+
/// \return the value appropriate to populate $status.
int status_value() const {
if (signal_exited()) {
@@ -465,7 +479,7 @@ class job_t {
bool signal(int signal);
/// \returns the statuses for this job.
- statuses_t get_statuses() const;
+ maybe_t get_statuses() const;
};
/// Whether this shell is attached to the keyboard at all.