diff options
Diffstat (limited to 'src/shell_manager.cc')
| -rw-r--r-- | src/shell_manager.cc | 63 |
1 files changed, 55 insertions, 8 deletions
diff --git a/src/shell_manager.cc b/src/shell_manager.cc index 8e1cefc5..298412b7 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -4,6 +4,7 @@ #include "client.hh" #include "clock.hh" #include "context.hh" +#include "command_manager.hh" #include "display_buffer.hh" #include "event_manager.hh" #include "face_registry.hh" @@ -163,18 +164,19 @@ Vector<String> generate_env(StringView cmdline, const Context& context, GetValue return env; } -FDWatcher make_pipe_reader(Pipe& pipe, String& contents) +template<typename OnClose> +FDWatcher make_reader(int fd, String& contents, OnClose&& on_close) { - return {pipe.read_fd(), FdEvents::Read, EventMode::Urgent, - [&contents, &pipe](FDWatcher& watcher, FdEvents, EventMode) { + return {fd, FdEvents::Read, EventMode::Urgent, + [fd, &contents, on_close](FDWatcher& watcher, FdEvents, EventMode) { char buffer[1024]; - while (fd_readable(pipe.read_fd())) + while (fd_readable(fd)) { - size_t size = ::read(pipe.read_fd(), buffer, sizeof(buffer)); + size_t size = ::read(fd, buffer, sizeof(buffer)); if (size <= 0) { - pipe.close_read_fd(); watcher.disable(); + on_close(); return; } contents += StringView{buffer, buffer+size}; @@ -206,6 +208,41 @@ FDWatcher make_pipe_writer(Pipe& pipe, StringView contents) }}; } +struct CommandFifos +{ + String base_dir; + String command; + FDWatcher command_watcher; + + CommandFifos(Context& context, const ShellContext& shell_context) + : base_dir(format("{}/kak-fifo.XXXXXX", tmpdir())), + command_watcher([&] { + mkdtemp(base_dir.data()), + mkfifo(command_fifo_path().c_str(), 0600); + mkfifo(response_fifo_path().c_str(), 0600); + int fd = open(command_fifo_path().c_str(), O_RDONLY | O_NONBLOCK); + return make_reader(fd, command, [&, fd] { + close(fd); + CommandManager::instance().execute(command, context, shell_context); + command.clear(); + command_watcher.reset_fd(open(command_fifo_path().c_str(), O_RDONLY | O_NONBLOCK)); + }); + }()) + { + } + + ~CommandFifos() + { + command_watcher.close_fd(); + unlink(command_fifo_path().c_str()); + unlink(response_fifo_path().c_str()); + rmdir(base_dir.c_str()); + } + + String command_fifo_path() const { return format("{}/command-fifo", base_dir); } + String response_fifo_path() const { return format("{}/response-fifo", base_dir); } +}; + } std::pair<String, int> ShellManager::eval( @@ -219,7 +256,17 @@ std::pair<String, int> ShellManager::eval( auto start_time = profile ? Clock::now() : Clock::time_point{}; + Optional<CommandFifos> command_fifos; + auto kak_env = generate_env(cmdline, context, [&](StringView name, Quoting quoting) { + if (name == "command_fifo" or name == "response_fifo") + { + if (not command_fifos) + command_fifos.emplace(const_cast<Context&>(context), shell_context); + return name == "command_fifo" ? + command_fifos->command_fifo_path() : command_fifos->response_fifo_path(); + } + if (auto it = shell_context.env_vars.find(name); it != shell_context.env_vars.end()) return it->value; return join(get_val(name, context) | transform(quoter(quoting)), ' ', false); @@ -259,8 +306,8 @@ std::pair<String, int> ShellManager::eval( auto wait_time = Clock::now(); String stdout_contents, stderr_contents; - auto stdout_reader = make_pipe_reader(child_stdout, stdout_contents); - auto stderr_reader = make_pipe_reader(child_stderr, stderr_contents); + auto stdout_reader = make_reader(child_stdout.read_fd(), stdout_contents, [&]{ child_stdout.close_read_fd(); }); + auto stderr_reader = make_reader(child_stderr.read_fd(), stderr_contents, [&]{ child_stderr.close_read_fd(); }); auto stdin_writer = make_pipe_writer(child_stdin, input); // block SIGCHLD to make sure we wont receive it before |
