diff --git a/highlight.cpp b/highlight.cpp index c1c24dd89..d03a60873 100644 --- a/highlight.cpp +++ b/highlight.cpp @@ -960,7 +960,7 @@ public: void highlighter_t::color_node(const parse_node_t &node, highlight_spec_t color) { // Can only color nodes with valid source ranges - if (! node.has_source()) + if (! node.has_source() || node.source_length == 0) return; // Fill the color array with our color in the corresponding range @@ -1356,6 +1356,7 @@ const highlighter_t::color_array_t & highlighter_t::highlight() case parse_token_type_background: case parse_token_type_end: + case symbol_optional_background: { this->color_node(node, highlight_spec_statement_terminator); } diff --git a/parse_execution.cpp b/parse_execution.cpp index 649caaa8e..8a2e9d271 100644 --- a/parse_execution.cpp +++ b/parse_execution.cpp @@ -1371,7 +1371,7 @@ parse_execution_result_t parse_execution_context_t::run_1_job(const parse_node_t (job_control_mode==JOB_CONTROL_ALL) || ((job_control_mode == JOB_CONTROL_INTERACTIVE) && (get_is_interactive()))); - job_set_flag(j, JOB_FOREGROUND, 1); + job_set_flag(j, JOB_FOREGROUND, ! tree.job_should_be_backgrounded(job_node)); job_set_flag(j, JOB_TERMINAL, job_get_flag(j, JOB_CONTROL) \ && (!is_subshell && !is_event)); diff --git a/parse_productions.cpp b/parse_productions.cpp index 3d65e6294..0fd754354 100644 --- a/parse_productions.cpp +++ b/parse_productions.cpp @@ -82,7 +82,7 @@ RESOLVE(job_list) PRODUCTIONS(job) = { - {symbol_statement, symbol_job_continuation} + {symbol_statement, symbol_job_continuation, symbol_optional_background} }; RESOLVE_ONLY(job) @@ -402,7 +402,7 @@ RESOLVE(decorated_statement) PRODUCTIONS(plain_statement) = { - {parse_token_type_string, symbol_arguments_or_redirections_list, symbol_optional_background} + {parse_token_type_string, symbol_arguments_or_redirections_list} }; RESOLVE_ONLY(plain_statement) diff --git a/parse_tree.cpp b/parse_tree.cpp index d8aefaff0..4effea20e 100644 --- a/parse_tree.cpp +++ b/parse_tree.cpp @@ -1496,6 +1496,19 @@ parse_node_tree_t::parse_node_list_t parse_node_tree_t::specific_statements_for_ return result; } +bool parse_node_tree_t::job_should_be_backgrounded(const parse_node_t &job) const +{ + assert(job.type == symbol_job); + assert(job.production_idx == 0); + bool result = false; + const parse_node_t *opt_background = get_child(job, 2, symbol_optional_background); + if (opt_background != NULL) { + assert(opt_background->production_idx <= 1); + result = (opt_background->production_idx == 1); + } + return result; +} + const parse_node_t *parse_node_tree_t::next_node_in_node_list(const parse_node_t &node_list, parse_token_type_t entry_type, const parse_node_t **out_list_tail) const { parse_token_type_t list_type = node_list.type; diff --git a/parse_tree.h b/parse_tree.h index f9f27bebb..c0e24a5ca 100644 --- a/parse_tree.h +++ b/parse_tree.h @@ -184,6 +184,9 @@ class parse_node_tree_t : public std::vector /* Given a job, return all of its statements. These are 'specific statements' (e.g. symbol_decorated_statement, not symbol_statement) */ parse_node_list_t specific_statements_for_job(const parse_node_t &job) const; + + /* Given a job, return whether it should be backgrounded, because it has a & specifier */ + bool job_should_be_backgrounded(const parse_node_t &job) const; }; @@ -198,9 +201,9 @@ bool parse_tree_from_string(const wcstring &str, parse_tree_flags_t flags, parse job job_list job_list -# A job is a non-empty list of statements, separated by pipes. (Non-empty is useful for cases like if statements, where we require a command). To represent "non-empty", we require a statement, followed by a possibly empty job_continuation +# A job is a non-empty list of statements, separated by pipes. (Non-empty is useful for cases like if statements, where we require a command). To represent "non-empty", we require a statement, followed by a possibly empty job_continuation, and then optionally a background specifier '&' - job = statement job_continuation + job = statement job_continuation optional_background job_continuation = | statement job_continuation @@ -240,7 +243,7 @@ bool parse_tree_from_string(const wcstring &str, parse_tree_flags_t flags, parse # A decorated_statement is a command with a list of arguments_or_redirections, possibly with "builtin" or "command" or "exec" decorated_statement = plain_statement | COMMAND plain_statement | BUILTIN plain_statement | EXEC plain_statement - plain_statement = arguments_or_redirections_list optional_background + plain_statement = arguments_or_redirections_list argument_list = | argument argument_list @@ -255,7 +258,7 @@ bool parse_tree_from_string(const wcstring &str, parse_tree_flags_t flags, parse end_command = END - # A freestanding_argument_list is equivalent to a normal argument list, except it may contain TOK_END (newlines, and even semicolons, for historical reasons: + # A freestanding_argument_list is equivalent to a normal argument list, except it may contain TOK_END (newlines, and even semicolons, for historical reasons freestanding_argument_list = | argument freestanding_argument_list |