summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/command_manager.cc3
-rw-r--r--src/commands.cc2
-rw-r--r--src/normal.cc35
-rw-r--r--src/shell_manager.cc14
-rw-r--r--src/shell_manager.hh12
5 files changed, 46 insertions, 20 deletions
diff --git a/src/command_manager.cc b/src/command_manager.cc
index 3e44ab1e..fd32f93c 100644
--- a/src/command_manager.cc
+++ b/src/command_manager.cc
@@ -350,7 +350,8 @@ void expand_token(Token&& token, const Context& context, const ShellContext& she
case Token::Type::ShellExpand:
{
auto str = ShellManager::instance().eval(
- content, context, {}, ShellManager::Flags::WaitForStdout,
+ content, context, StringView{},
+ ShellManager::Flags::WaitForStdout,
shell_context).first;
if (not str.empty() and str.back() == '\n')
diff --git a/src/commands.cc b/src/commands.cc
index 1d3f5a50..78193e57 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -277,7 +277,7 @@ struct ShellScriptCompleter
{ { "token_to_complete", to_string(token_to_complete) },
{ "pos_in_token", to_string(pos_in_token) } }
};
- String output = ShellManager::instance().eval(m_shell_script, context, {},
+ String output = ShellManager::instance().eval(m_shell_script, context, StringView{},
ShellManager::Flags::WaitForStdout,
shell_context).first;
CandidateList candidates;
diff --git a/src/normal.cc b/src/normal.cc
index 689137ef..056f11de 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -535,9 +535,8 @@ void command(Context& context, NormalParams params)
command(context, std::move(env_vars), params.reg);
}
-BufferCoord apply_diff(Buffer& buffer, BufferCoord pos, StringView before, StringView after)
+BufferCoord apply_diff(Buffer& buffer, BufferCoord pos, ArrayView<StringView> lines_before, StringView after)
{
- const auto lines_before = before | split_after<StringView>('\n') | gather<Vector<StringView>>();
const auto lines_after = after | split_after<StringView>('\n') | gather<Vector<StringView>>();
auto byte_count = [](auto&& lines, int first, int count) {
@@ -601,26 +600,38 @@ void pipe(Context& context, NormalParams params)
SelectionList selections = context.selections();
for (auto& sel : selections)
{
- const auto beg = changes_tracker.get_new_coord_tolerant(sel.min());
- const auto end = changes_tracker.get_new_coord_tolerant(sel.max());
+ const auto first = changes_tracker.get_new_coord_tolerant(sel.min());
+ const auto last = changes_tracker.get_new_coord_tolerant(sel.max());
+
+ Vector<StringView> in_lines;
+ for (auto line = first.line; line <= last.line; ++line)
+ {
+ auto content = buffer[line];
+ if (line == last.line)
+ content = content.substr(0, last.column + utf8::codepoint_size(content[last.column]));
+ if (line == first.line)
+ content = content.substr(first.column);
+ in_lines.push_back(content);
+ }
- String in = buffer.string(beg, buffer.char_next(end));
// Needed in case we read selections inside the cmdline
- context.selections_write_only().set({keep_direction(Selection{beg, end}, sel)}, 0);
+ context.selections_write_only().set({keep_direction(Selection{first, last}, sel)}, 0);
String out = ShellManager::instance().eval(
- cmdline, context, in,
- ShellManager::Flags::WaitForStdout).first;
+ cmdline, context,
+ [it = in_lines.begin(), end = in_lines.end()]() mutable {
+ return (it != end) ? *it++ : StringView{};
+ }, ShellManager::Flags::WaitForStdout).first;
- if (in.back() != '\n' and not out.empty() and out.back() == '\n')
+ if (in_lines.back().back() != '\n' and not out.empty() and out.back() == '\n')
out.resize(out.length()-1, 0);
- auto new_end = apply_diff(buffer, beg, in, out);
- if (new_end != beg)
+ auto new_end = apply_diff(buffer, first, in_lines, out);
+ if (new_end != first)
{
auto& min = sel.min();
auto& max = sel.max();
- min = beg;
+ min = first;
max = buffer.char_prev(new_end);
}
else
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.
diff --git a/src/shell_manager.hh b/src/shell_manager.hh
index f6ef38a4..3dc62e0a 100644
--- a/src/shell_manager.hh
+++ b/src/shell_manager.hh
@@ -58,10 +58,20 @@ public:
friend constexpr bool with_bit_ops(Meta::Type<Flags>) { return true; }
std::pair<String, int> eval(StringView cmdline, const Context& context,
- StringView input = {},
+ FunctionRef<StringView ()> stdin_generator,
Flags flags = Flags::WaitForStdout,
const ShellContext& shell_context = {});
+ std::pair<String, int> eval(StringView cmdline, const Context& context,
+ StringView stdin,
+ Flags flags = Flags::WaitForStdout,
+ const ShellContext& shell_context = {})
+ {
+ return eval(cmdline, context,
+ [stdin]() mutable { return std::exchange(stdin, StringView{}); },
+ flags, shell_context);
+ }
+
Shell spawn(StringView cmdline,
const Context& context,
bool open_stdin,