summaryrefslogtreecommitdiff
path: root/src/shell_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/shell_manager.cc')
-rw-r--r--src/shell_manager.cc63
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