Specify if ShellManager should read output or not using a flag
Some program (xclip), will fork a daemon keeping stdout/stderr open, so waiting for them to be closed make kakoune hang. Commands discarding stdout can then just not wait on it.
This commit is contained in:
parent
7acf3da3ca
commit
942fc224af
|
@ -271,6 +271,7 @@ String expand_token(const Token& token, const Context& context,
|
|||
{
|
||||
case Token::Type::ShellExpand:
|
||||
return ShellManager::instance().eval(content, context, {},
|
||||
ShellManager::Flags::ReadOutput,
|
||||
shell_params, env_vars).first;
|
||||
case Token::Type::RegisterExpand:
|
||||
return context.main_sel_register_value(content).str();
|
||||
|
|
|
@ -786,8 +786,9 @@ void define_command(const ParametersParser& parser, Context& context)
|
|||
{ "token_to_complete", to_string(token_to_complete) },
|
||||
{ "pos_in_token", to_string(pos_in_token) }
|
||||
};
|
||||
String output = ShellManager::instance().eval(shell_cmd, context,
|
||||
{}, params, vars).first;
|
||||
String output = ShellManager::instance().eval(shell_cmd, context, {},
|
||||
ShellManager::Flags::ReadOutput,
|
||||
params, vars).first;
|
||||
return Completions{ 0_byte, pos_in_token, split(output, '\n', 0) };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -394,8 +394,11 @@ void pipe(Context& context, NormalParams)
|
|||
bool insert_eol = str.back() != '\n';
|
||||
if (insert_eol)
|
||||
str += '\n';
|
||||
str = ShellManager::instance().eval(real_cmd, context, str,
|
||||
str = ShellManager::instance().eval(
|
||||
real_cmd, context, str,
|
||||
ShellManager::Flags::ReadOutput,
|
||||
{}, EnvVarMap{}).first;
|
||||
|
||||
if ((insert_eol or sel.max() == buffer.back_coord()) and
|
||||
str.back() == '\n')
|
||||
str = str.substr(0, str.length()-1).str();
|
||||
|
@ -409,7 +412,8 @@ void pipe(Context& context, NormalParams)
|
|||
for (auto& sel : selections)
|
||||
ShellManager::instance().eval(real_cmd, context,
|
||||
content(buffer, sel),
|
||||
{}, EnvVarMap{}).first;
|
||||
ShellManager::Flags::None,
|
||||
{}, EnvVarMap{});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -436,8 +440,9 @@ void insert_output(Context& context, NormalParams)
|
|||
if (real_cmd.empty())
|
||||
return;
|
||||
|
||||
auto str = ShellManager::instance().eval(real_cmd, context, {}, {},
|
||||
EnvVarMap{}).first;
|
||||
auto str = ShellManager::instance().eval(real_cmd, context, {},
|
||||
ShellManager::Flags::ReadOutput,
|
||||
{}, EnvVarMap{}).first;
|
||||
ScopedEdition edition(context);
|
||||
context.selections().insert(str, mode);
|
||||
});
|
||||
|
@ -788,6 +793,7 @@ void keep_pipe(Context& context, NormalParams)
|
|||
for (auto& sel : context.selections())
|
||||
{
|
||||
if (shell_manager.eval(cmdline, context, content(buffer, sel),
|
||||
ShellManager::Flags::None,
|
||||
{}, EnvVarMap{}).second == 0)
|
||||
keep.push_back(sel);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ ShellManager::ShellManager()
|
|||
|
||||
std::pair<String, int> ShellManager::eval(
|
||||
StringView cmdline, const Context& context, StringView input,
|
||||
ConstArrayView<String> params, const EnvVarMap& env_vars)
|
||||
Flags flags, ConstArrayView<String> params, const EnvVarMap& env_vars)
|
||||
{
|
||||
int write_pipe[2]; // child stdin
|
||||
int read_pipe[2]; // child stdout
|
||||
|
@ -44,6 +44,8 @@ std::pair<String, int> ShellManager::eval(
|
|||
close(write_pipe[1]);
|
||||
|
||||
String child_stdout, child_stderr;
|
||||
int status = 0;
|
||||
bool terminated = false;
|
||||
{
|
||||
auto pipe_reader = [](String& output) {
|
||||
return [&output](FDWatcher& watcher, EventMode) {
|
||||
|
@ -58,15 +60,25 @@ std::pair<String, int> ShellManager::eval(
|
|||
FDWatcher stdout_watcher{read_pipe[0], pipe_reader(child_stdout)};
|
||||
FDWatcher stderr_watcher{error_pipe[0], pipe_reader(child_stderr)};
|
||||
|
||||
while (not stdout_watcher.closed() or not stderr_watcher.closed())
|
||||
if (not (flags & Flags::ReadOutput))
|
||||
{
|
||||
stdout_watcher.close_fd();
|
||||
stderr_watcher.close_fd();
|
||||
}
|
||||
|
||||
while (not stdout_watcher.closed() or
|
||||
not stderr_watcher.closed() or
|
||||
not terminated)
|
||||
{
|
||||
EventManager::instance().handle_next_events(EventMode::Urgent);
|
||||
if (not terminated)
|
||||
terminated = waitpid(pid, &status, WNOHANG);
|
||||
}
|
||||
}
|
||||
|
||||
if (not child_stderr.empty())
|
||||
write_to_debug_buffer(format("shell stderr: <<<\n{}>>>", child_stderr));
|
||||
|
||||
int status = 0;
|
||||
waitpid(pid, &status, 0);
|
||||
return { child_stdout, WIFEXITED(status) ? WEXITSTATUS(status) : - 1 };
|
||||
}
|
||||
else try
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "regex.hh"
|
||||
#include "utils.hh"
|
||||
#include "env_vars.hh"
|
||||
#include "flags.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -20,8 +21,15 @@ class ShellManager : public Singleton<ShellManager>
|
|||
public:
|
||||
ShellManager();
|
||||
|
||||
enum class Flags
|
||||
{
|
||||
None = 0,
|
||||
ReadOutput = 1
|
||||
};
|
||||
|
||||
std::pair<String, int> eval(StringView cmdline, const Context& context,
|
||||
StringView input = {},
|
||||
Flags flags = Flags::ReadOutput,
|
||||
ConstArrayView<String> params = {},
|
||||
const EnvVarMap& env_vars = EnvVarMap{});
|
||||
|
||||
|
@ -32,6 +40,8 @@ private:
|
|||
Vector<std::pair<Regex, EnvVarRetriever>> m_env_vars;
|
||||
};
|
||||
|
||||
template<> struct WithBitOps<ShellManager::Flags> : std::true_type {};
|
||||
|
||||
}
|
||||
|
||||
#endif // shell_manager_hh_INCLUDED
|
||||
|
|
Loading…
Reference in New Issue
Block a user