diff --git a/src/command_manager.cc b/src/command_manager.cc index 606c25135..800b3a04f 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -3,11 +3,9 @@ #include "utils.hh" #include "assert.hh" #include "context.hh" +#include "shell_manager.hh" #include -#include -#include -#include namespace Kakoune { @@ -101,29 +99,7 @@ static void shell_eval(std::vector& 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& 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, diff --git a/src/highlighters.cc b/src/highlighters.cc index 7becf1d0d..45cc95e51 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -12,6 +12,8 @@ namespace Kakoune using namespace std::placeholders; +typedef boost::regex_iterator RegexIterator; + void colorize_regex_range(DisplayBuffer& display_buffer, const BufferIterator& range_begin, const BufferIterator& range_end, diff --git a/src/main.cc b/src/main.cc index 0fa6d8795..0af2824ee 100644 --- a/src/main.cc +++ b/src/main.cc @@ -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, CommandManager::None, PerArgumentCommandCompleter({ complete_filename })); diff --git a/src/regex.hh b/src/regex.hh index 0ad93a1b2..6099a57c8 100644 --- a/src/regex.hh +++ b/src/regex.hh @@ -8,7 +8,6 @@ namespace Kakoune { -typedef boost::regex_iterator RegexIterator; typedef boost::basic_regex Regex; } diff --git a/src/selectors.cc b/src/selectors.cc index c327edfd7..044f7bb90 100644 --- a/src/selectors.cc +++ b/src/selectors.cc @@ -87,6 +87,8 @@ bool skip_while_reverse(BufferIterator& it, T condition) } +typedef boost::regex_iterator RegexIterator; + template SelectionAndCaptures select_to_next_word(const Selection& selection) { diff --git a/src/shell_manager.cc b/src/shell_manager.cc new file mode 100644 index 000000000..f750ab05a --- /dev/null +++ b/src/shell_manager.cc @@ -0,0 +1,85 @@ +#include "shell_manager.hh" + +#include +#include +#include + +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 it(cmdline.begin(), cmdline.end(), m_regex); + boost::regex_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); +} + +} diff --git a/src/shell_manager.hh b/src/shell_manager.hh new file mode 100644 index 000000000..b67136aa7 --- /dev/null +++ b/src/shell_manager.hh @@ -0,0 +1,32 @@ +#ifndef shell_manager_hh_INCLUDED +#define shell_manager_hh_INCLUDED + +#include "utils.hh" +#include "regex.hh" + +#include + +namespace Kakoune +{ + +class Context; +typedef std::function EnvVarRetriever; + +class ShellManager : public Singleton +{ +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 m_env_vars; +}; + +} + +#endif // shell_manager_hh_INCLUDED +