Add a ShellManager which handles executing shell commands

ShellManager provides shell commands with environement variable
to retrieve some internal values in the shell parameters.
This commit is contained in:
Maxime Coste 2012-05-03 07:25:13 +00:00
parent 2a291e6868
commit 0c596a9d64
7 changed files with 130 additions and 40 deletions

View File

@ -3,11 +3,9 @@
#include "utils.hh"
#include "assert.hh"
#include "context.hh"
#include "shell_manager.hh"
#include <algorithm>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
namespace Kakoune
{
@ -101,29 +99,7 @@ static void shell_eval(std::vector<String>& params,
const String& cmdline,
const Context& context)
{
int write_pipe[2];
int read_pipe[2];
pipe(write_pipe);
pipe(read_pipe);
if (pid_t pid = fork())
{
close(write_pipe[0]);
close(read_pipe[1]);
close(write_pipe[1]);
String output;
char buffer[1024];
while (size_t size = read(read_pipe[0], buffer, 1024))
{
if (size == -1)
break;
output += String(buffer, buffer+size);
}
close(read_pipe[0]);
waitpid(pid, NULL, 0);
String output = ShellManager::instance().eval(cmdline, context);
TokenList tokens = split(output);
for (auto it = tokens.begin(); it != tokens.end(); ++it)
@ -131,19 +107,6 @@ static void shell_eval(std::vector<String>& params,
params.push_back(output.substr(it->first,
it->second - it->first));
}
}
else
{
close(write_pipe[1]);
close(read_pipe[0]);
dup2(read_pipe[1], 1);
dup2(write_pipe[0], 0);
if (context.has_buffer())
setenv("kak_bufname", context.buffer().name().c_str(), 1);
execlp("sh", "sh", "-c", cmdline.c_str(), NULL);
}
}
void CommandManager::execute(const CommandParameters& params,

View File

@ -12,6 +12,8 @@ namespace Kakoune
using namespace std::placeholders;
typedef boost::regex_iterator<BufferIterator> RegexIterator;
void colorize_regex_range(DisplayBuffer& display_buffer,
const BufferIterator& range_begin,
const BufferIterator& range_end,

View File

@ -1,6 +1,7 @@
#include "window.hh"
#include "buffer.hh"
#include "file.hh"
#include "shell_manager.hh"
#include "command_manager.hh"
#include "buffer_manager.hh"
#include "register_manager.hh"
@ -929,6 +930,7 @@ int main(int argc, char* argv[])
{
NCurses::init(prompt_func, get_key_func);
ShellManager shell_manager;
CommandManager command_manager;
BufferManager buffer_manager;
RegisterManager register_manager;
@ -939,6 +941,11 @@ int main(int argc, char* argv[])
run_unit_tests();
shell_manager.register_env_var("bufname",
[](const Context& context)
{ return context.buffer().name(); });
command_manager.register_commands({ "e", "edit" }, edit<false>,
CommandManager::None,
PerArgumentCommandCompleter({ complete_filename }));

View File

@ -8,7 +8,6 @@
namespace Kakoune
{
typedef boost::regex_iterator<BufferIterator> RegexIterator;
typedef boost::basic_regex<Character> Regex;
}

View File

@ -87,6 +87,8 @@ bool skip_while_reverse(BufferIterator& it, T condition)
}
typedef boost::regex_iterator<BufferIterator> RegexIterator;
template<bool punctuation_is_word>
SelectionAndCaptures select_to_next_word(const Selection& selection)
{

85
src/shell_manager.cc Normal file
View File

@ -0,0 +1,85 @@
#include "shell_manager.hh"
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
namespace Kakoune
{
ShellManager::ShellManager()
: m_regex(LR"(\$\{kak_([a-z0-9_]+)[^}]*\}|\$kak_([a-z0-9_]+))")
{
}
String ShellManager::eval(const String& cmdline, const Context& context)
{
int write_pipe[2];
int read_pipe[2];
pipe(write_pipe);
pipe(read_pipe);
String output;
if (pid_t pid = fork())
{
close(write_pipe[0]);
close(read_pipe[1]);
close(write_pipe[1]);
char buffer[1024];
while (size_t size = read(read_pipe[0], buffer, 1024))
{
if (size == -1)
break;
output += String(buffer, buffer+size);
}
close(read_pipe[0]);
waitpid(pid, NULL, 0);
}
else
{
close(write_pipe[1]);
close(read_pipe[0]);
dup2(read_pipe[1], 1);
dup2(write_pipe[0], 0);
boost::regex_iterator<String::iterator> it(cmdline.begin(), cmdline.end(), m_regex);
boost::regex_iterator<String::iterator> end;
while (it != end)
{
auto& match = *it;
String name;
if (match[1].matched)
name = String(match[1].first, match[1].second);
else if (match[2].matched)
name = String(match[2].first, match[2].second);
else
assert(false);
assert(name.length() > 0);
auto env_var = m_env_vars.find(name);
if (env_var != m_env_vars.end())
{
String value = env_var->second(context);
setenv(("kak_" + name).c_str(), value.c_str(), 1);
}
++it;
}
execlp("sh", "sh", "-c", cmdline.c_str(), NULL);
}
return output;
}
void ShellManager::register_env_var(const String& name,
EnvVarRetriever retriever)
{
m_env_vars[name] = std::move(retriever);
}
}

32
src/shell_manager.hh Normal file
View File

@ -0,0 +1,32 @@
#ifndef shell_manager_hh_INCLUDED
#define shell_manager_hh_INCLUDED
#include "utils.hh"
#include "regex.hh"
#include <unordered_map>
namespace Kakoune
{
class Context;
typedef std::function<String (const Context&)> EnvVarRetriever;
class ShellManager : public Singleton<ShellManager>
{
public:
ShellManager();
String eval(const String& cmdline, const Context& context);
void register_env_var(const String& name, EnvVarRetriever retriever);
private:
Regex m_regex;
std::unordered_map<String, EnvVarRetriever> m_env_vars;
};
}
#endif // shell_manager_hh_INCLUDED