diff --git a/Shell/AST.cpp b/Shell/AST.cpp index db391c26c2..732338737e 100644 --- a/Shell/AST.cpp +++ b/Shell/AST.cpp @@ -658,7 +658,7 @@ RefPtr Execute::run(TheExecutionInputType input_value) auto run_commands = [&](auto& commands) { for (auto& command : commands) { #ifdef EXECUTE_DEBUG - dbg() << "Command " << (m_capture_stdout ? "Capturing stdout " : "") << (command.should_wait ? "" : "In background "); + dbg() << "Command"; for (auto& arg : command.argv) dbg() << "argv: " << arg; for (auto& redir : command.redirections) { @@ -683,7 +683,7 @@ RefPtr Execute::run(TheExecutionInputType input_value) } else { if (command.is_pipe_source) { jobs_to_wait_for.append(job); - } else { + } else if (command.should_notify_if_in_background) { if (job) job->set_running_in_background(true); shell->take_back_stdin(); @@ -699,31 +699,30 @@ RefPtr Execute::run(TheExecutionInputType input_value) dbg() << "Error: cannot pipe(): " << strerror(errno); return create(""); } - auto last_in_commands = commands.take_last(); + auto& last_in_commands = commands.last(); - last_in_commands.redirections.append(*new FdRedirection(STDOUT_FILENO, pipefd[1], Rewiring::Close::Destination)); - last_in_commands.should_wait = false; - last_in_commands.is_pipe_source = true; - - Vector commands; - commands.append(commands); - commands.append(last_in_commands); - - run_commands(commands); + last_in_commands.redirections.prepend(*new FdRedirection(STDOUT_FILENO, pipefd[1], Rewiring::Close::Destination)); + last_in_commands.should_wait = true; + last_in_commands.should_notify_if_in_background = false; + last_in_commands.is_pipe_source = false; auto notifier = Core::Notifier::construct(pipefd[0], Core::Notifier::Read); StringBuilder builder; - notifier->on_ready_to_read = [&] { + auto try_read = [&] { u8 buffer[4096]; size_t remaining_size = 4096; for (;;) { if (remaining_size == 0) - return; + break; auto read_size = read(pipefd[0], buffer, remaining_size); if (read_size < 0) { + if (errno == EINTR) + continue; + if (errno == 0) + break; dbg() << "read() failed: " << strerror(errno); - return; + break; } if (read_size == 0) break; @@ -733,12 +732,20 @@ RefPtr Execute::run(TheExecutionInputType input_value) builder.append(StringView { buffer, 4096 - remaining_size }); }; + notifier->on_ready_to_read = [&] { + try_read(); + }; + + run_commands(commands); + for (auto job : jobs_to_wait_for) { shell->block_on_job(job); } notifier->on_ready_to_read = nullptr; + try_read(); + if (close(pipefd[0]) < 0) { dbg() << "close() failed: " << strerror(errno); } diff --git a/Shell/AST.h b/Shell/AST.h index bfa31dfdbd..25b85c4f3f 100644 --- a/Shell/AST.h +++ b/Shell/AST.h @@ -124,6 +124,7 @@ struct Command { Vector> redirections; bool should_wait { true }; bool is_pipe_source { false }; + bool should_notify_if_in_background { true }; }; struct HitTestResult { @@ -155,7 +156,7 @@ public: } CommandValue(Vector argv) - : m_command({ move(argv), {}, true, false }) + : m_command({ move(argv), {}, true, false, true }) { } @@ -245,8 +246,6 @@ class SimpleVariableValue final : public Value { public: virtual Vector resolve_as_list(TheExecutionInputType) override; virtual ~SimpleVariableValue(); - // FIXME: Should override is_list and is_string, - // as it might have different types of values. SimpleVariableValue(String name) : m_name(name) { @@ -260,8 +259,6 @@ class SpecialVariableValue final : public Value { public: virtual Vector resolve_as_list(TheExecutionInputType) override; virtual ~SpecialVariableValue(); - // FIXME: Should override is_list and is_string, - // as it might have different types of values. SpecialVariableValue(char name) : m_name(name) { diff --git a/Shell/Parser.cpp b/Shell/Parser.cpp index caed8a1d61..7e715cf416 100644 --- a/Shell/Parser.cpp +++ b/Shell/Parser.cpp @@ -633,18 +633,24 @@ RefPtr Parser::parse_evaluate() return nullptr; consume(); + if (peek() == '(') { + consume(); + auto inner = parse_pipe_sequence(); + if (!inner || !expect(')')) + inner = create(); + else + inner = create(move(inner), true); + return inner; + } auto inner = parse_expression(); if (!inner) { inner = create(); } else { if (inner->is_list()) { - auto execute_inner = create(move(inner)); - execute_inner->capture_stdout(); + auto execute_inner = create(move(inner), true); inner = execute_inner; } else { - // Trying to evaluate something other than a list - // FIXME: This bit be dynamic, what do? auto dyn_inner = create(move(inner)); inner = dyn_inner; } diff --git a/Shell/Parser.h b/Shell/Parser.h index f27364f9e1..54b2d410ae 100644 --- a/Shell/Parser.h +++ b/Shell/Parser.h @@ -125,7 +125,8 @@ expression :: evaluate expression? | comment expession? | '(' list_expression ')' expression? -evaluate :: '$' expression {eval / dynamic resolve} +evaluate :: '$' '(' pipe_sequence ')' + | '$' expression {eval / dynamic resolve} string_composite :: string string_composite? | variable string_composite?