summaryrefslogtreecommitdiff
path: root/src/shell_manager.cc
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2024-08-26 21:00:08 +1000
committerMaxime Coste <mawww@kakoune.org>2024-08-26 21:00:08 +1000
commit9275d965a6952d44035fd0502ee0d3991352c460 (patch)
treec3a0abf7b582c3bc53a492c1e1d3dbc72d215879 /src/shell_manager.cc
parent202747e68896aebbe38cc160391629e020f0c2a1 (diff)
Do not gather full input data in a single string when piping
Refactor ShellManager and pipe to feed lines from the buffer directly, this should reduce memory use when piping big chunks of buffers. The pipe output is still provided as a single big buffer.
Diffstat (limited to 'src/shell_manager.cc')
-rw-r--r--src/shell_manager.cc14
1 files changed, 9 insertions, 5 deletions
diff --git a/src/shell_manager.cc b/src/shell_manager.cc
index 7346f2c1..6b656191 100644
--- a/src/shell_manager.cc
+++ b/src/shell_manager.cc
@@ -197,18 +197,22 @@ FDWatcher make_reader(int fd, String& contents, OnClose&& on_close)
}};
}
-FDWatcher make_pipe_writer(UniqueFd& fd, StringView contents)
+FDWatcher make_pipe_writer(UniqueFd& fd, const FunctionRef<StringView ()>& generator)
{
int flags = fcntl((int)fd, F_GETFL, 0);
fcntl((int)fd, F_SETFL, flags | O_NONBLOCK);
return {(int)fd, FdEvents::Write, EventMode::Urgent,
- [contents, &fd](FDWatcher& watcher, FdEvents, EventMode) mutable {
+ [&generator, &fd, contents=generator()](FDWatcher& watcher, FdEvents, EventMode) mutable {
while (fd_writable((int)fd))
{
ssize_t size = ::write((int)fd, contents.begin(),
(size_t)contents.length());
if (size > 0)
+ {
contents = contents.substr(ByteCount{(int)size});
+ if (contents.empty())
+ contents = generator();
+ }
if (size == -1 and (errno == EAGAIN or errno == EWOULDBLOCK))
return;
if (size < 0 or contents.empty())
@@ -263,7 +267,7 @@ struct CommandFifos
}
std::pair<String, int> ShellManager::eval(
- StringView cmdline, const Context& context, StringView input,
+ StringView cmdline, const Context& context, FunctionRef<StringView ()> input_generator,
Flags flags, const ShellContext& shell_context)
{
const DebugFlags debug_flags = context.options()["debug"].get<DebugFlags>();
@@ -290,13 +294,13 @@ std::pair<String, int> ShellManager::eval(
});
auto spawn_time = profile ? Clock::now() : Clock::time_point{};
- auto shell = spawn_shell(m_shell.c_str(), cmdline, shell_context.params, kak_env, not input.empty());
+ auto shell = spawn_shell(m_shell.c_str(), cmdline, shell_context.params, kak_env, true);
auto wait_time = Clock::now();
String stdout_contents, stderr_contents;
auto stdout_reader = make_reader((int)shell.out, stdout_contents, [&](bool){ shell.out.close(); });
auto stderr_reader = make_reader((int)shell.err, stderr_contents, [&](bool){ shell.err.close(); });
- auto stdin_writer = make_pipe_writer(shell.in, input);
+ auto stdin_writer = make_pipe_writer(shell.in, input_generator);
// block SIGCHLD to make sure we wont receive it before
// our call to pselect, that will end up blocking indefinitly.