diff options
| -rw-r--r-- | src/command_manager.cc | 3 | ||||
| -rw-r--r-- | src/commands.cc | 2 | ||||
| -rw-r--r-- | src/normal.cc | 35 | ||||
| -rw-r--r-- | src/shell_manager.cc | 14 | ||||
| -rw-r--r-- | src/shell_manager.hh | 12 |
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, |
