Make subcommands modify $status, and make builtin_set not modify status unless it fails

https://github.com/fish-shell/fish-shell/issues/547
https://github.com/fish-shell/fish-shell/issues/214
This commit is contained in:
ridiculousfish 2013-01-31 15:57:08 -08:00
parent 0db1b6ce44
commit ad8d68dd43
21 changed files with 143 additions and 139 deletions

View File

@ -358,11 +358,9 @@ bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_
/* If we have a script, either built-in or a file source, then run it */ /* If we have a script, either built-in or a file source, then run it */
if (really_load && has_script_source) if (really_load && has_script_source)
{ {
if (exec_subshell(script_source) == -1) if (exec_subshell(script_source, false /* do not apply exit status */) == -1)
{ {
/* /* Do nothing on failure */
Do nothing on failiure
*/
} }
} }

View File

@ -215,7 +215,7 @@ wcstring builtin_help_get(parser_t &parser, const wchar_t *name)
wcstring out; wcstring out;
const wcstring name_esc = escape_string(name, 1); const wcstring name_esc = escape_string(name, 1);
const wcstring cmd = format_string(L"__fish_print_help %ls", name_esc.c_str()); const wcstring cmd = format_string(L"__fish_print_help %ls", name_esc.c_str());
if (exec_subshell(cmd, lst) >= 0) if (exec_subshell(cmd, lst, false /* don't apply exit status */) >= 0)
{ {
for (size_t i=0; i<lst.size(); i++) for (size_t i=0; i<lst.size(); i++)
{ {

View File

@ -379,58 +379,21 @@ static void print_variables(int include_values, int esc, bool shorten_ok, int sc
*/ */
static int builtin_set(parser_t &parser, wchar_t **argv) static int builtin_set(parser_t &parser, wchar_t **argv)
{ {
/** Variables used for parsing the argument list */
/** const struct woption long_options[] =
Variables used for parsing the argument list
*/
static const struct woption
long_options[] =
{ {
{ { L"export", no_argument, 0, 'x' },
L"export", no_argument, 0, 'x' { L"global", no_argument, 0, 'g' },
} { L"local", no_argument, 0, 'l' },
, { L"erase", no_argument, 0, 'e' },
{ { L"names", no_argument, 0, 'n' },
L"global", no_argument, 0, 'g' { L"unexport", no_argument, 0, 'u' },
} { L"universal", no_argument, 0, 'U' },
, { L"long", no_argument, 0, 'L' },
{ { L"query", no_argument, 0, 'q' },
L"local", no_argument, 0, 'l' { L"help", no_argument, 0, 'h' },
} { 0, 0, 0, 0 }
, } ;
{
L"erase", no_argument, 0, 'e'
}
,
{
L"names", no_argument, 0, 'n'
}
,
{
L"unexport", no_argument, 0, 'u'
}
,
{
L"universal", no_argument, 0, 'U'
}
,
{
L"long", no_argument, 0, 'L'
}
,
{
L"query", no_argument, 0, 'q'
}
,
{
L"help", no_argument, 0, 'h'
}
,
{
0, 0, 0, 0
}
}
;
const wchar_t *short_options = L"+xglenuULqh"; const wchar_t *short_options = L"+xglenuULqh";
@ -443,6 +406,8 @@ static int builtin_set(parser_t &parser, wchar_t **argv)
int erase = 0, list = 0, unexport=0; int erase = 0, list = 0, unexport=0;
int universal = 0, query=0; int universal = 0, query=0;
bool shorten_ok = true; bool shorten_ok = true;
bool preserve_incoming_failure_exit_status = true;
const int incoming_exit_status = proc_get_last_status();
/* /*
Variables used for performing the actual work Variables used for performing the actual work
@ -474,10 +439,12 @@ static int builtin_set(parser_t &parser, wchar_t **argv)
case 'e': case 'e':
erase = 1; erase = 1;
preserve_incoming_failure_exit_status = false;
break; break;
case 'n': case 'n':
list = 1; list = 1;
preserve_incoming_failure_exit_status = false;
break; break;
case 'x': case 'x':
@ -506,6 +473,7 @@ static int builtin_set(parser_t &parser, wchar_t **argv)
case 'q': case 'q':
query = 1; query = 1;
preserve_incoming_failure_exit_status = false;
break; break;
case 'h': case 'h':
@ -825,6 +793,8 @@ static int builtin_set(parser_t &parser, wchar_t **argv)
free(dest); free(dest);
if (retcode == STATUS_BUILTIN_OK && preserve_incoming_failure_exit_status)
retcode = incoming_exit_status;
return retcode; return retcode;
} }

View File

@ -135,7 +135,7 @@ public:
/** Returns whether the color is bold */ /** Returns whether the color is bold */
bool is_bold() const bool is_bold() const
{ {
return !! (flags & flag_bold); return !!(flags & flag_bold);
} }
/** Set whether the color is bold */ /** Set whether the color is bold */

View File

@ -150,7 +150,7 @@ extern const wchar_t *program_name;
read( 0, &exit_read_buff, 1 ); \ read( 0, &exit_read_buff, 1 ); \
exit_without_destructors( 1 ); \ exit_without_destructors( 1 ); \
} \ } \
/** /**
Exit program at once, leaving an error message about running out of memory. Exit program at once, leaving an error message about running out of memory.

View File

@ -465,7 +465,7 @@ bool completer_t::condition_test(const wcstring &condition)
if (cached_entry == condition_cache.end()) if (cached_entry == condition_cache.end())
{ {
/* Compute new value and reinsert it */ /* Compute new value and reinsert it */
test_res = (0 == exec_subshell(condition)); test_res = (0 == exec_subshell(condition, false /* don't apply exit status */));
condition_cache[condition] = test_res; condition_cache[condition] = test_res;
} }
else else
@ -1007,7 +1007,7 @@ void completer_t::complete_cmd_desc(const wcstring &str)
since apropos is only called once. since apropos is only called once.
*/ */
wcstring_list_t list; wcstring_list_t list;
if (exec_subshell(lookup_cmd, list) != -1) if (exec_subshell(lookup_cmd, list, false /* don't apply exit status */) != -1)
{ {
/* /*

View File

@ -11,8 +11,7 @@ By defining the \c fish_prompt function, the user can choose a custom
prompt. The \c fish_prompt function is executed when the prompt is to prompt. The \c fish_prompt function is executed when the prompt is to
be shown, and the output is used as a prompt. be shown, and the output is used as a prompt.
Please keep in mind that the function is executed by <a The exit status of commands within \c fish_prompt will not modify the <a href="index.html#variables-status">$status</a> seen outside of fish_prompt.
href='index.html#expand-command-substitution'>command substitution</a>, and so the exit status of commands within fish_prompt will not modify the <a href="index.html#variables-status">$status</a> seen outside of fish_prompt.
\subsection fish_prompt-example Example \subsection fish_prompt-example Example

View File

@ -578,9 +578,8 @@ this list is executed, and substituted by the output. If the output is
more than one line long, each line will be expanded to a new more than one line long, each line will be expanded to a new
parameter. parameter.
A command substitution will not change the value of the <a The exit status of the last run command substitution is available in the <a
href='#variables-status'>status</a> variable outside of the command href='#variables-status'>status</a> variable.
substitution.
Only part of the output can be used, see <a href='#expand-index-range'>index Only part of the output can be used, see <a href='#expand-index-range'>index
range expansion</a> for details. range expansion</a> for details.

View File

@ -68,13 +68,14 @@ non-switch arguments. For example, <code>set flags -l</code> will have
the effect of setting the value of the variable <code>flags</code> to the effect of setting the value of the variable <code>flags</code> to
'-l', not making the variable local. '-l', not making the variable local.
In assignment mode, set exits with an exit status of zero it the In assignment mode, set exits with a non-zero exit status if variable
variable assignments where sucessfully performed, with a non-zero exit assignments could not be successfully performed. If the variable assignments
status otherwise. In query mode, the exit status is the number of were performed, the exit status is unchanged. This allows simultaneous capture
variables that where not found. In erase mode, set exits with a zero of the output and exit status of a subcommand, e.g. <code>if set output
exit status in case of success, with a non-zero exit status if the (command)</code>. In query mode, the exit status is the number of variables that
commandline was invalid, if the variable was write-protected or if the were not found. In erase mode, set exits with a zero exit status in case of
variable did not exist. success, with a non-zero exit status if the commandline was invalid, if the
variable was write-protected or if the variable did not exist.
\subsection set-example Example \subsection set-example Example
@ -85,3 +86,9 @@ variable did not exist.
<code>set -e smurf</code> removes the variable \c smurf. <code>set -e smurf</code> removes the variable \c smurf.
<code>set PATH[4] ~/bin</code> changes the fourth element of the \c PATH array to \c ~/bin <code>set PATH[4] ~/bin</code> changes the fourth element of the \c PATH array to \c ~/bin
<pre>if set python_path (which python)
echo "Python is at $python_path"
end</pre>
The above outputs the path to Python if \c which returns true.

View File

@ -125,7 +125,7 @@ void exec_close(int fd)
int exec_pipe(int fd[2]) int exec_pipe(int fd[2])
{ {
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
int res; int res;
while ((res=pipe(fd))) while ((res=pipe(fd)))
{ {
@ -621,11 +621,11 @@ void exec(parser_t &parser, job_t *j)
} }
} }
// This is a pipe that the "current" process in our loop below reads from // This is a pipe that the "current" process in our loop below reads from
// Only pipe_read->pipe_fd[0] is used // Only pipe_read->pipe_fd[0] is used
shared_ptr<io_pipe_t> pipe_read(new io_pipe_t(0, true)); shared_ptr<io_pipe_t> pipe_read(new io_pipe_t(0, true));
// This is the pipe that the "current" process in our loop below writes to // This is the pipe that the "current" process in our loop below writes to
shared_ptr<io_pipe_t> pipe_write(new io_pipe_t(1, false)); shared_ptr<io_pipe_t> pipe_write(new io_pipe_t(1, false));
@ -687,7 +687,7 @@ void exec(parser_t &parser, job_t *j)
set_child_group(j, &keepalive, 0); set_child_group(j, &keepalive, 0);
} }
} }
/* /*
This loop loops over every process_t in the job, starting it as This loop loops over every process_t in the job, starting it as
appropriate. This turns out to be rather complex, since a appropriate. This turns out to be rather complex, since a
@ -695,17 +695,17 @@ void exec(parser_t &parser, job_t *j)
The loop also has to handle pipelining between the jobs. The loop also has to handle pipelining between the jobs.
*/ */
/* We can have up to three pipes "in flight" at a time: /* We can have up to three pipes "in flight" at a time:
1. The pipe the current process should read from (courtesy of the previous process) 1. The pipe the current process should read from (courtesy of the previous process)
2. The pipe that the current process should write to 2. The pipe that the current process should write to
3. The pipe that the next process should read from (courtesy of us) 3. The pipe that the next process should read from (courtesy of us)
We are careful to set these to -1 when closed, so if we exit the loop abruptly, we can still close them. We are careful to set these to -1 when closed, so if we exit the loop abruptly, we can still close them.
*/ */
int pipe_current_read = -1, pipe_current_write = -1, pipe_next_read = -1; int pipe_current_read = -1, pipe_current_write = -1, pipe_next_read = -1;
for (process_t *p=j->first_process; p; p = p->next) for (process_t *p=j->first_process; p; p = p->next)
{ {
@ -713,10 +713,10 @@ void exec(parser_t &parser, job_t *j)
assert(pipe_current_read == -1); assert(pipe_current_read == -1);
pipe_current_read = pipe_next_read; pipe_current_read = pipe_next_read;
pipe_next_read = -1; pipe_next_read = -1;
/* Record the current read in pipe_read */ /* Record the current read in pipe_read */
pipe_read->pipe_fd[0] = pipe_current_read; pipe_read->pipe_fd[0] = pipe_current_read;
/* See if we need a pipe */ /* See if we need a pipe */
const bool pipes_to_next_command = (p->next != NULL); const bool pipes_to_next_command = (p->next != NULL);
@ -760,15 +760,15 @@ void exec(parser_t &parser, job_t *j)
job_mark_process_as_failed(j, p); job_mark_process_as_failed(j, p);
break; break;
} }
// This tells the redirection about the fds, but the redirection does not close them // This tells the redirection about the fds, but the redirection does not close them
memcpy(pipe_write->pipe_fd, local_pipe, sizeof(int)*2); memcpy(pipe_write->pipe_fd, local_pipe, sizeof(int)*2);
// Record our pipes // Record our pipes
// The fds should be negative to indicate that we aren't overwriting an fd we failed to close // The fds should be negative to indicate that we aren't overwriting an fd we failed to close
assert(pipe_current_write == -1); assert(pipe_current_write == -1);
pipe_current_write = local_pipe[1]; pipe_current_write = local_pipe[1];
assert(pipe_next_read == -1); assert(pipe_next_read == -1);
pipe_next_read = local_pipe[0]; pipe_next_read = local_pipe[0];
} }
@ -838,7 +838,7 @@ void exec(parser_t &parser, job_t *j)
j->io.push_back(io_buffer); j->io.push_back(io_buffer);
} }
} }
if (! exec_error) if (! exec_error)
{ {
internal_exec_helper(parser, def.c_str(), TOP, j->io); internal_exec_helper(parser, def.c_str(), TOP, j->io);
@ -865,7 +865,7 @@ void exec(parser_t &parser, job_t *j)
j->io.push_back(io_buffer); j->io.push_back(io_buffer);
} }
} }
if (! exec_error) if (! exec_error)
{ {
internal_exec_helper(parser, p->argv0(), TOP, j->io); internal_exec_helper(parser, p->argv0(), TOP, j->io);
@ -1389,7 +1389,7 @@ void exec(parser_t &parser, job_t *j)
exec_close(pipe_current_read); exec_close(pipe_current_read);
pipe_current_read = -1; pipe_current_read = -1;
} }
/* Close the write end too, since the curent child subprocess already has a copy of it. */ /* Close the write end too, since the curent child subprocess already has a copy of it. */
if (pipe_current_write >= 0) if (pipe_current_write >= 0)
{ {
@ -1397,7 +1397,7 @@ void exec(parser_t &parser, job_t *j)
pipe_current_write = -1; pipe_current_write = -1;
} }
} }
/* Clean up any file descriptors we left open */ /* Clean up any file descriptors we left open */
if (pipe_current_read >= 0) if (pipe_current_read >= 0)
exec_close(pipe_current_read); exec_close(pipe_current_read);
@ -1405,7 +1405,7 @@ void exec(parser_t &parser, job_t *j)
exec_close(pipe_current_write); exec_close(pipe_current_write);
if (pipe_next_read >= 0) if (pipe_next_read >= 0)
exec_close(pipe_next_read); exec_close(pipe_next_read);
/* The keepalive process is no longer needed, so we terminate it with extreme prejudice */ /* The keepalive process is no longer needed, so we terminate it with extreme prejudice */
if (needs_keepalive) if (needs_keepalive)
{ {
@ -1438,11 +1438,11 @@ void exec(parser_t &parser, job_t *j)
} }
static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst) static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, bool apply_exit_status)
{ {
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
int prev_subshell = is_subshell; int prev_subshell = is_subshell;
int status, prev_status; const int prev_status = proc_get_last_status();
char sep=0; char sep=0;
const env_var_t ifs = env_get_string(L"IFS"); const env_var_t ifs = env_get_string(L"IFS");
@ -1456,38 +1456,33 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst)
else else
{ {
sep = 0; sep = 0;
debug(0, L"Warning - invalid command substitution separator '%lc'. Please change the firsta character of IFS", ifs[0]); debug(0, L"Warning - invalid command substitution separator '%lc'. Please change the first character of IFS", ifs[0]);
} }
} }
is_subshell=1; is_subshell=1;
prev_status = proc_get_last_status();
const shared_ptr<io_buffer_t> io_buffer(io_buffer_t::create(0)); int subcommand_status = -1; //assume the worst
// IO buffer creation may fail (e.g. if we have too many open files to make a pipe), so this may be null // IO buffer creation may fail (e.g. if we have too many open files to make a pipe), so this may be null
if (io_buffer.get() == NULL) const shared_ptr<io_buffer_t> io_buffer(io_buffer_t::create(0));
{ if (io_buffer.get() != NULL)
status = -1;
}
else
{ {
parser_t &parser = parser_t::principal_parser(); parser_t &parser = parser_t::principal_parser();
if (parser.eval(cmd, io_chain_t(io_buffer), SUBST)) if (parser.eval(cmd, io_chain_t(io_buffer), SUBST) == 0)
{ {
status = -1; subcommand_status = proc_get_last_status();
} }
else
{
status = proc_get_last_status();
}
io_buffer->read(); io_buffer->read();
} }
proc_set_last_status(prev_status); // If the caller asked us to preserve the exit status, restore the old status
// Otherwise set the status of the subcommand
proc_set_last_status(apply_exit_status ? subcommand_status : prev_status);
is_subshell = prev_subshell; is_subshell = prev_subshell;
@ -1515,17 +1510,17 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst)
} }
} }
return status; return subcommand_status;
} }
int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs) int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs, bool apply_exit_status)
{ {
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
return exec_subshell_internal(cmd, &outputs); return exec_subshell_internal(cmd, &outputs, apply_exit_status);
} }
__warn_unused int exec_subshell(const wcstring &cmd) __warn_unused int exec_subshell(const wcstring &cmd, bool apply_exit_status)
{ {
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
return exec_subshell_internal(cmd, NULL); return exec_subshell_internal(cmd, NULL, apply_exit_status);
} }

4
exec.h
View File

@ -54,8 +54,8 @@ void exec(parser_t &parser, job_t *j);
\return the status of the last job to exit, or -1 if en error was encountered. \return the status of the last job to exit, or -1 if en error was encountered.
*/ */
__warn_unused int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs); __warn_unused int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs, bool preserve_exit_status);
__warn_unused int exec_subshell(const wcstring &cmd); __warn_unused int exec_subshell(const wcstring &cmd, bool preserve_exit_status);
/** /**

View File

@ -1352,7 +1352,7 @@ static int expand_cmdsubst(parser_t &parser, const wcstring &input, std::vector<
const wcstring subcmd(paran_begin + 1, paran_end-paran_begin - 1); const wcstring subcmd(paran_begin + 1, paran_end-paran_begin - 1);
if (exec_subshell(subcmd, sub_res) == -1) if (exec_subshell(subcmd, sub_res, true /* do apply exit status */) == -1)
{ {
parser.error(CMDSUBST_ERROR, -1, L"Unknown error while evaulating command substitution"); parser.error(CMDSUBST_ERROR, -1, L"Unknown error while evaulating command substitution");
return 0; return 0;

View File

@ -112,7 +112,7 @@ void kill_add(const wcstring &str)
if (! cmd.empty()) if (! cmd.empty())
{ {
if (exec_subshell(cmd) == -1) if (exec_subshell(cmd, false /* do not apply exit status */) == -1)
{ {
/* /*
Do nothing on failiure Do nothing on failiure
@ -175,7 +175,7 @@ static void kill_check_x_buffer()
wcstring cmd = L"xsel -t 500 -b"; wcstring cmd = L"xsel -t 500 -b";
wcstring new_cut_buffer=L""; wcstring new_cut_buffer=L"";
wcstring_list_t list; wcstring_list_t list;
if (exec_subshell(cmd, list) != -1) if (exec_subshell(cmd, list, false /* do not apply exit status */) != -1)
{ {
for (i=0; i<list.size(); i++) for (i=0; i<list.size(); i++)

View File

@ -1203,7 +1203,7 @@ bool parser_t::job_remove(job_t *j)
void parser_t::job_promote(job_t *job) void parser_t::job_promote(job_t *job)
{ {
signal_block(); signal_block();
job_list_t::iterator loc = std::find(my_job_list.begin(), my_job_list.end(), job); job_list_t::iterator loc = std::find(my_job_list.begin(), my_job_list.end(), job);
assert(loc != my_job_list.end()); assert(loc != my_job_list.end());
@ -2900,11 +2900,12 @@ int parser_t::test_args(const wchar_t * buff, wcstring *out, const wchar_t *pre
} }
// helper type used in parser::test below // helper type used in parser::test below
struct block_info_t { struct block_info_t
{
int position; //tokenizer position int position; //tokenizer position
block_type_t type; //type of the block block_type_t type; //type of the block
int indentation; //indentation associated with the block int indentation; //indentation associated with the block
bool has_had_case; //if we are a switch, whether we've encountered a case bool has_had_case; //if we are a switch, whether we've encountered a case
}; };
@ -2922,7 +2923,7 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w
tokenizer_t * const previous_tokenizer=current_tokenizer; tokenizer_t * const previous_tokenizer=current_tokenizer;
const int previous_pos=current_tokenizer_pos; const int previous_pos=current_tokenizer_pos;
// These are very nearly stacks, but sometimes we have to inspect non-top elements (e.g. return) // These are very nearly stacks, but sometimes we have to inspect non-top elements (e.g. return)
std::vector<struct block_info_t> block_infos; std::vector<struct block_info_t> block_infos;
int indentation_sum = 0; //sum of indentation in block_infos int indentation_sum = 0; //sum of indentation in block_infos
@ -3040,7 +3041,7 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w
{ {
tok_next(&tok); tok_next(&tok);
tok_set_pos(&tok, mark); tok_set_pos(&tok, mark);
/* Test that end is not used when not inside any block */ /* Test that end is not used when not inside any block */
if (block_infos.empty()) if (block_infos.empty())
{ {
@ -3060,7 +3061,7 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w
{ {
indentation_sum -= block_infos.back().indentation; indentation_sum -= block_infos.back().indentation;
block_infos.pop_back(); block_infos.pop_back();
} }
} }

View File

@ -10,7 +10,7 @@
#include "exec.h" #include "exec.h"
#ifndef JOIN_THREADS_BEFORE_FORK #ifndef JOIN_THREADS_BEFORE_FORK
#define JOIN_THREADS_BEFORE_FORK 0 #define JOIN_THREADS_BEFORE_FORK 0
#endif #endif
/** The number of times to try to call fork() before giving up */ /** The number of times to try to call fork() before giving up */

View File

@ -328,7 +328,7 @@ void job_set_flag(job_t *j, unsigned int flag, int set)
int job_get_flag(const job_t *j, unsigned int flag) int job_get_flag(const job_t *j, unsigned int flag)
{ {
return !! (j->flags & flag); return !!(j->flags & flag);
} }
int job_signal(job_t *j, int signal) int job_signal(job_t *j, int signal)

View File

@ -692,7 +692,7 @@ void reader_write_title()
wcstring_list_t lst; wcstring_list_t lst;
proc_push_interactive(0); proc_push_interactive(0);
if (exec_subshell(title, lst) != -1) if (exec_subshell(title, lst, false /* do not apply exit status */) != -1)
{ {
size_t i; size_t i;
if (lst.size() > 0) if (lst.size() > 0)
@ -718,6 +718,9 @@ static void exec_prompt()
data->left_prompt_buff.clear(); data->left_prompt_buff.clear();
data->right_prompt_buff.clear(); data->right_prompt_buff.clear();
/* Do not allow the exit status of the prompts to leak through */
const bool apply_exit_status = false;
/* If we have any prompts, they must be run non-interactively */ /* If we have any prompts, they must be run non-interactively */
if (data->left_prompt.size() || data->right_prompt.size()) if (data->left_prompt.size() || data->right_prompt.size())
{ {
@ -726,9 +729,9 @@ static void exec_prompt()
if (! data->left_prompt.empty()) if (! data->left_prompt.empty())
{ {
wcstring_list_t prompt_list; wcstring_list_t prompt_list;
// status is ignored if (exec_subshell(data->left_prompt, prompt_list, apply_exit_status))
if (exec_subshell(data->left_prompt, prompt_list))
{ {
// returned status value is ignored
} }
for (size_t i = 0; i < prompt_list.size(); i++) for (size_t i = 0; i < prompt_list.size(); i++)
{ {
@ -741,8 +744,9 @@ static void exec_prompt()
{ {
wcstring_list_t prompt_list; wcstring_list_t prompt_list;
// status is ignored // status is ignored
if (exec_subshell(data->right_prompt, prompt_list)) if (exec_subshell(data->right_prompt, prompt_list, apply_exit_status))
{ {
// returned status value is ignored
} }
for (size_t i = 0; i < prompt_list.size(); i++) for (size_t i = 0; i < prompt_list.size(); i++)
{ {
@ -1048,10 +1052,10 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
wcstring msg; wcstring msg;
wcstring prefix_esc; wcstring prefix_esc;
char *foo; char *foo;
shared_ptr<io_buffer_t> in(io_buffer_t::create(true)); shared_ptr<io_buffer_t> in(io_buffer_t::create(true));
shared_ptr<io_buffer_t> out(io_buffer_t::create(false)); shared_ptr<io_buffer_t> out(io_buffer_t::create(false));
// The above may fail e.g. if we have too many open fds // The above may fail e.g. if we have too many open fds
if (in.get() == NULL || out.get() == NULL) if (in.get() == NULL || out.get() == NULL)
return; return;
@ -1140,7 +1144,7 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
free(foo); free(foo);
out->fd = 4; out->fd = 4;
term_donate(); term_donate();
parser_t &parser = parser_t::principal_parser(); parser_t &parser = parser_t::principal_parser();
io_chain_t io_chain; io_chain_t io_chain;

View File

@ -1373,20 +1373,20 @@ void s_reset(screen_t *s, screen_reset_mode_t mode)
} }
else else
{ {
// draw in "bright black" (gray) // draw in "bright black" (gray)
abandon_line_string.append(L"\x1b[0m" //bright abandon_line_string.append(L"\x1b[0m" //bright
L"\x1b[30;1m"); //black L"\x1b[30;1m"); //black
} }
abandon_line_string.push_back(omitted_newline_char); abandon_line_string.push_back(omitted_newline_char);
abandon_line_string.append(L"\x1b[0m"); //normal text ANSI escape sequence abandon_line_string.append(L"\x1b[0m"); //normal text ANSI escape sequence
abandon_line_string.append(screen_width - non_space_width, L' '); abandon_line_string.append(screen_width - non_space_width, L' ');
} }
abandon_line_string.push_back(L'\r'); abandon_line_string.push_back(L'\r');
// now we are certainly on a new line. But we may have dropped the omitted newline char on it. So append enough spaces to overwrite the omitted newline char, and then // now we are certainly on a new line. But we may have dropped the omitted newline char on it. So append enough spaces to overwrite the omitted newline char, and then
abandon_line_string.append(non_space_width, L' '); abandon_line_string.append(non_space_width, L' ');
abandon_line_string.push_back(L'\r'); abandon_line_string.push_back(L'\r');
const std::string narrow_abandon_line_string = wcs2string(abandon_line_string); const std::string narrow_abandon_line_string = wcs2string(abandon_line_string);
write_loop(STDOUT_FILENO, narrow_abandon_line_string.c_str(), narrow_abandon_line_string.size()); write_loop(STDOUT_FILENO, narrow_abandon_line_string.c_str(), narrow_abandon_line_string.size());
s->actual.cursor.x = 0; s->actual.cursor.x = 0;

View File

@ -160,3 +160,20 @@ else
end; end;
set -U -e baz set -U -e baz
echo "Verify subcommand statuses"
echo (false) $status (true) $status (false) $status
echo "Verify that set passes through exit status, except when passed -n or -q or -e"
false ; set foo bar ; echo 1 $status # passthrough
true ; set foo bar ; echo 2 $status # passthrough
false ; set -q foo ; echo 3 $status # no passthrough
true ; set -q foo ; echo 4 $status # no passthrough
false ; set -n > /dev/null ; echo 5 $status # no passthrough
false ; set -e foo ; echo 6 $status # no passthrough
true ; set -e foo ; echo 7 $status # no passthrough
false ; set -h > /dev/null ; echo 8 $status # no passthrough
true ; set -NOT_AN_OPTION 2> /dev/null ; echo 9 $status # no passthrough
false ; set foo (echo A; true) ; echo 10 $status $foo
true ; set foo (echo B; false) ; echo 11 $status $foo
true

View File

@ -20,3 +20,17 @@ Test 19 pass
Test 20 pass Test 20 pass
Test 21 pass Test 21 pass
Test 22 pass Test 22 pass
Verify subcommand statuses
1 0 1
Verify that set passes through exit status, except when passed -n or -q or -e
1 1
2 0
3 0
4 0
5 0
6 0
7 1
8 0
9 1
10 0 A
11 1 B

View File

@ -336,7 +336,7 @@ static wcstring complete_get_desc_suffix_internal(const wcstring &suff)
wcstring_list_t lst; wcstring_list_t lst;
wcstring desc; wcstring desc;
if (exec_subshell(cmd, lst) != -1) if (exec_subshell(cmd, lst, false /* do not apply exit status */) != -1)
{ {
if (lst.size()>0) if (lst.size()>0)
{ {