summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2015-06-08 13:34:08 +0100
committerMaxime Coste <frrrwww@gmail.com>2015-06-08 13:45:20 +0100
commit942fc224af403de0a73511a4e6a5dfe4bfa53b91 (patch)
tree43b9482e2e150c6513f4f230bed667e97fd04a91 /src
parent7acf3da3ca6b012d603e4cf7360abb4a3235daca (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/command_manager.cc1
-rw-r--r--src/commands.cc5
-rw-r--r--src/normal.cc16
-rw-r--r--src/shell_manager.cc20
-rw-r--r--src/shell_manager.hh10
5 files changed, 41 insertions, 11 deletions
diff --git a/src/command_manager.cc b/src/command_manager.cc
index 074b736b..e57ab196 100644
--- a/src/command_manager.cc
+++ b/src/command_manager.cc
@@ -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();
diff --git a/src/commands.cc b/src/commands.cc
index 821a42e9..6d6a55fc 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -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) };
};
}
diff --git a/src/normal.cc b/src/normal.cc
index 20c2ce5a..c584baac 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -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,
- {}, EnvVarMap{}).first;
+ 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);
}
diff --git a/src/shell_manager.cc b/src/shell_manager.cc
index ce926ecb..ff483d89 100644
--- a/src/shell_manager.cc
+++ b/src/shell_manager.cc
@@ -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
diff --git a/src/shell_manager.hh b/src/shell_manager.hh
index fde507b6..36c74a3a 100644
--- a/src/shell_manager.hh
+++ b/src/shell_manager.hh
@@ -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