mirror of
https://github.com/mawww/kakoune.git
synced 2024-11-27 12:16:22 +03:00
Separate events between normal and urgent ones
Run urgent ones while executing %sh blocks. Fixes #236
This commit is contained in:
parent
0272da65c0
commit
49931fbf05
@ -105,7 +105,10 @@ Buffer* create_fifo_buffer(String name, int fd, bool scroll)
|
||||
ValueId fifo_watcher_id = s_fifo_watcher_id;
|
||||
|
||||
std::unique_ptr<FDWatcher, decltype(watcher_deleter)> watcher(
|
||||
new FDWatcher(fd, [buffer, scroll, fifo_watcher_id](FDWatcher& watcher) {
|
||||
new FDWatcher(fd, [buffer, scroll, fifo_watcher_id](FDWatcher& watcher, EventMode mode) {
|
||||
if (mode != EventMode::Normal)
|
||||
return;
|
||||
|
||||
constexpr size_t buffer_size = 2048;
|
||||
// if we read data slower than it arrives in the fifo, limiting the
|
||||
// iteration number allows us to go back go back to the event loop and
|
||||
|
@ -7,8 +7,12 @@
|
||||
#include "file.hh"
|
||||
#include "remote.hh"
|
||||
#include "client_manager.hh"
|
||||
#include "event_manager.hh"
|
||||
#include "window.hh"
|
||||
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
@ -34,14 +38,44 @@ Client::~Client()
|
||||
m_window->options().unregister_watcher(*this);
|
||||
}
|
||||
|
||||
void Client::handle_available_input()
|
||||
void Client::handle_available_input(EventMode mode)
|
||||
{
|
||||
while (m_ui->is_key_available())
|
||||
if (mode == EventMode::Normal)
|
||||
{
|
||||
m_input_handler.handle_key(m_ui->get_key());
|
||||
m_input_handler.clear_mode_trash();
|
||||
try
|
||||
{
|
||||
for (auto& key : m_pending_keys)
|
||||
{
|
||||
m_input_handler.handle_key(key);
|
||||
m_input_handler.clear_mode_trash();
|
||||
}
|
||||
m_pending_keys.clear();
|
||||
|
||||
while (m_ui->is_key_available())
|
||||
{
|
||||
m_input_handler.handle_key(m_ui->get_key());
|
||||
m_input_handler.clear_mode_trash();
|
||||
}
|
||||
context().window().forget_timestamp();
|
||||
}
|
||||
catch (Kakoune::runtime_error& error)
|
||||
{
|
||||
context().print_status({ error.what(), get_face("Error") });
|
||||
context().hooks().run_hook("RuntimeError", error.what(), context());
|
||||
}
|
||||
catch (Kakoune::client_removed&)
|
||||
{
|
||||
ClientManager::instance().remove_client(*this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Key key = m_ui->get_key();
|
||||
if (key == ctrl('c'))
|
||||
killpg(getpgrp(), SIGINT);
|
||||
else
|
||||
m_pending_keys.push_back(key);
|
||||
}
|
||||
context().window().forget_timestamp();
|
||||
}
|
||||
|
||||
void Client::print_status(DisplayLine status_line)
|
||||
|
@ -14,6 +14,9 @@ namespace Kakoune
|
||||
class UserInterface;
|
||||
class Window;
|
||||
class String;
|
||||
struct Key;
|
||||
|
||||
enum class EventMode;
|
||||
|
||||
class Client : public SafeCountable, public OptionManagerWatcher
|
||||
{
|
||||
@ -28,7 +31,7 @@ public:
|
||||
Client(Client&&) = delete;
|
||||
|
||||
// handle all the keys currently available in the user interface
|
||||
void handle_available_input();
|
||||
void handle_available_input(EventMode mode);
|
||||
|
||||
void print_status(DisplayLine status_line);
|
||||
|
||||
@ -64,6 +67,8 @@ private:
|
||||
DisplayLine m_status_line;
|
||||
DisplayLine m_pending_status_line;
|
||||
DisplayLine m_mode_line;
|
||||
|
||||
std::vector<Key> m_pending_keys;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -50,26 +50,19 @@ Client* ClientManager::create_client(std::unique_ptr<UserInterface>&& ui,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
client->ui().set_input_callback([client, this]() {
|
||||
try
|
||||
{
|
||||
client->handle_available_input();
|
||||
}
|
||||
catch (Kakoune::runtime_error& error)
|
||||
{
|
||||
client->context().print_status({ error.what(), get_face("Error") });
|
||||
client->context().hooks().run_hook("RuntimeError", error.what(),
|
||||
client->context());
|
||||
}
|
||||
catch (Kakoune::client_removed&)
|
||||
{
|
||||
ClientManager::instance().remove_client(*client);
|
||||
}
|
||||
client->ui().set_input_callback([client](EventMode mode) {
|
||||
client->handle_available_input(mode);
|
||||
});
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
void ClientManager::handle_available_inputs() const
|
||||
{
|
||||
for (auto& client : m_clients)
|
||||
client->handle_available_input(EventMode::Normal);
|
||||
}
|
||||
|
||||
void ClientManager::remove_client(Client& client)
|
||||
{
|
||||
for (auto it = m_clients.begin(); it != m_clients.end(); ++it)
|
||||
|
@ -35,6 +35,7 @@ public:
|
||||
|
||||
void redraw_clients() const;
|
||||
void clear_mode_trashes() const;
|
||||
void handle_available_inputs() const;
|
||||
|
||||
Client* get_client_ifp(StringView name);
|
||||
Client& get_client(StringView name);
|
||||
|
@ -16,8 +16,13 @@ FDWatcher::~FDWatcher()
|
||||
EventManager::instance().m_fd_watchers.erase(this);
|
||||
}
|
||||
|
||||
Timer::Timer(TimePoint date, Callback callback)
|
||||
: m_date{date}, m_callback{std::move(callback)}
|
||||
void FDWatcher::run(EventMode mode)
|
||||
{
|
||||
m_callback(*this, mode);
|
||||
}
|
||||
|
||||
Timer::Timer(TimePoint date, Callback callback, EventMode mode)
|
||||
: m_date{date}, m_callback{std::move(callback)}, m_mode(mode)
|
||||
{
|
||||
if (EventManager::has_instance())
|
||||
EventManager::instance().m_timers.insert(this);
|
||||
@ -29,10 +34,15 @@ Timer::~Timer()
|
||||
EventManager::instance().m_timers.erase(this);
|
||||
}
|
||||
|
||||
void Timer::run()
|
||||
void Timer::run(EventMode mode)
|
||||
{
|
||||
m_date = TimePoint::max();
|
||||
m_callback(*this);
|
||||
if (mode & m_mode)
|
||||
{
|
||||
m_date = TimePoint::max();
|
||||
m_callback(*this);
|
||||
}
|
||||
else // try again a little later
|
||||
m_date = Clock::now() + std::chrono::milliseconds{10};
|
||||
}
|
||||
|
||||
EventManager::EventManager()
|
||||
@ -46,7 +56,7 @@ EventManager::~EventManager()
|
||||
kak_assert(m_timers.empty());
|
||||
}
|
||||
|
||||
void EventManager::handle_next_events()
|
||||
void EventManager::handle_next_events(EventMode mode)
|
||||
{
|
||||
std::vector<pollfd> events;
|
||||
events.reserve(m_fd_watchers.size());
|
||||
@ -76,7 +86,7 @@ void EventManager::handle_next_events()
|
||||
auto it = find_if(m_fd_watchers,
|
||||
[fd](FDWatcher* w) { return w->fd() == fd; });
|
||||
if (it != m_fd_watchers.end())
|
||||
(*it)->run();
|
||||
(*it)->run(mode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +94,7 @@ void EventManager::handle_next_events()
|
||||
for (auto& timer : m_timers)
|
||||
{
|
||||
if (timer->next_date() <= now)
|
||||
timer->run();
|
||||
timer->run(mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define event_manager_hh_INCLUDED
|
||||
|
||||
#include "utils.hh"
|
||||
#include "flags.hh"
|
||||
|
||||
#include <chrono>
|
||||
#include <unordered_set>
|
||||
@ -9,20 +10,28 @@
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
enum class EventMode
|
||||
{
|
||||
Normal = 1 << 0,
|
||||
Urgent = 1 << 1
|
||||
};
|
||||
|
||||
template<> struct WithBitOps<EventMode> : std::true_type {};
|
||||
|
||||
class FDWatcher
|
||||
{
|
||||
public:
|
||||
using Callback = std::function<void (FDWatcher& watcher)>;
|
||||
using Callback = std::function<void (FDWatcher& watcher, EventMode mode)>;
|
||||
FDWatcher(int fd, Callback callback);
|
||||
~FDWatcher();
|
||||
|
||||
int fd() const { return m_fd; }
|
||||
void run() { m_callback(*this); }
|
||||
void run(EventMode mode);
|
||||
private:
|
||||
FDWatcher(const FDWatcher&) = delete;
|
||||
|
||||
int m_fd;
|
||||
Callback m_callback;
|
||||
int m_fd;
|
||||
Callback m_callback;
|
||||
};
|
||||
|
||||
using Clock = std::chrono::steady_clock;
|
||||
@ -33,15 +42,17 @@ class Timer
|
||||
public:
|
||||
using Callback = std::function<void (Timer& timer)>;
|
||||
|
||||
Timer(TimePoint date, Callback callback);
|
||||
Timer(TimePoint date, Callback callback,
|
||||
EventMode mode = EventMode::Normal);
|
||||
~Timer();
|
||||
|
||||
TimePoint next_date() const { return m_date; }
|
||||
void set_next_date(TimePoint date) { m_date = date; }
|
||||
void run();
|
||||
void run(EventMode mode);
|
||||
|
||||
private:
|
||||
TimePoint m_date;
|
||||
EventMode m_mode;
|
||||
Callback m_callback;
|
||||
};
|
||||
|
||||
@ -56,7 +67,7 @@ public:
|
||||
EventManager();
|
||||
~EventManager();
|
||||
|
||||
void handle_next_events();
|
||||
void handle_next_events(EventMode mode);
|
||||
|
||||
// force the watchers associated with fd to be executed
|
||||
// on next handle_next_events call.
|
||||
|
@ -305,7 +305,7 @@ int run_client(StringView session, StringView init_command)
|
||||
RemoteClient client{session, make_unique<NCursesUI>(),
|
||||
get_env_vars(), init_command};
|
||||
while (true)
|
||||
event_manager.handle_next_events();
|
||||
event_manager.handle_next_events(EventMode::Normal);
|
||||
}
|
||||
catch (peer_disconnected&)
|
||||
{
|
||||
@ -407,7 +407,8 @@ int run_server(StringView session, StringView init_command,
|
||||
|
||||
while (not terminate and (not client_manager.empty() or daemon))
|
||||
{
|
||||
event_manager.handle_next_events();
|
||||
event_manager.handle_next_events(EventMode::Normal);
|
||||
client_manager.handle_available_inputs();
|
||||
client_manager.clear_mode_trashes();
|
||||
buffer_manager.clear_buffer_trash();
|
||||
client_manager.redraw_clients();
|
||||
|
@ -219,8 +219,10 @@ void on_sigint(int)
|
||||
}
|
||||
|
||||
NCursesUI::NCursesUI()
|
||||
: m_stdin_watcher{0, [this](FDWatcher&){ if (m_input_callback)
|
||||
m_input_callback(); }}
|
||||
: m_stdin_watcher{0, [this](FDWatcher&, EventMode mode) {
|
||||
if (m_input_callback)
|
||||
m_input_callback(mode);
|
||||
}}
|
||||
{
|
||||
initscr();
|
||||
raw();
|
||||
|
@ -18,9 +18,6 @@
|
||||
#include "user_interface.hh"
|
||||
#include "window.hh"
|
||||
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
@ -1400,8 +1397,6 @@ KeyMap keymap =
|
||||
|
||||
{ Key::PageUp, { "scroll one page up", scroll<Key::PageUp> } },
|
||||
{ Key::PageDown, { "scroll one page down", scroll<Key::PageDown> } },
|
||||
|
||||
{ ctrl('c'), { "interupt", [](Context&, int) { killpg(getpgrp(), SIGINT); } } },
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -282,9 +282,9 @@ private:
|
||||
|
||||
|
||||
RemoteUI::RemoteUI(int socket)
|
||||
: m_socket_watcher(socket, [this](FDWatcher&) {
|
||||
: m_socket_watcher(socket, [this](FDWatcher&, EventMode mode) {
|
||||
if (m_input_callback)
|
||||
m_input_callback();
|
||||
m_input_callback(mode);
|
||||
})
|
||||
{
|
||||
write_debug("remote client connected: " +
|
||||
@ -453,9 +453,9 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr<UserInterface>&&
|
||||
msg.write(key);
|
||||
}
|
||||
|
||||
m_ui->set_input_callback([this]{ write_next_key(); });
|
||||
m_ui->set_input_callback([this](EventMode){ write_next_key(); });
|
||||
|
||||
m_socket_watcher.reset(new FDWatcher{sock, [this](FDWatcher&){ process_available_messages(); }});
|
||||
m_socket_watcher.reset(new FDWatcher{sock, [this](FDWatcher&, EventMode){ process_available_messages(); }});
|
||||
}
|
||||
|
||||
void RemoteClient::process_available_messages()
|
||||
@ -560,7 +560,10 @@ class Server::Accepter
|
||||
public:
|
||||
Accepter(int socket)
|
||||
: m_socket_watcher(socket,
|
||||
[this](FDWatcher&) { handle_available_input(); })
|
||||
[this](FDWatcher&, EventMode mode) {
|
||||
if (mode == EventMode::Normal)
|
||||
handle_available_input();
|
||||
})
|
||||
{}
|
||||
|
||||
private:
|
||||
@ -626,7 +629,7 @@ Server::Server(String session_name)
|
||||
if (listen(listen_sock, 4) == -1)
|
||||
throw runtime_error("unable to listen on socket "_str + addr.sun_path);
|
||||
|
||||
auto accepter = [this](FDWatcher& watcher) {
|
||||
auto accepter = [this](FDWatcher& watcher, EventMode mode) {
|
||||
sockaddr_un client_addr;
|
||||
socklen_t client_addr_len = sizeof(sockaddr_un);
|
||||
int sock = accept(watcher.fd(), (sockaddr*) &client_addr,
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "context.hh"
|
||||
#include "debug.hh"
|
||||
#include "event_manager.hh"
|
||||
#include "file.hh"
|
||||
|
||||
#include <cstring>
|
||||
@ -59,25 +60,34 @@ String ShellManager::pipe(StringView input,
|
||||
write(write_pipe[1], input.data(), (int)input.length());
|
||||
close(write_pipe[1]);
|
||||
|
||||
char buffer[1024];
|
||||
while (size_t size = read(read_pipe[0], buffer, 1024))
|
||||
String error;
|
||||
{
|
||||
if (size == -1)
|
||||
break;
|
||||
output += String(buffer, buffer+size);
|
||||
}
|
||||
close(read_pipe[0]);
|
||||
auto pipe_reader = [](String& output, bool& closed) {
|
||||
return [&output, &closed](FDWatcher& watcher, EventMode) {
|
||||
if (closed)
|
||||
return;
|
||||
const int fd = watcher.fd();
|
||||
char buffer[1024];
|
||||
size_t size = read(fd, buffer, 1024);
|
||||
if (size <= 0)
|
||||
{
|
||||
close(fd);
|
||||
closed = true;
|
||||
}
|
||||
output += String(buffer, buffer+size);
|
||||
};
|
||||
};
|
||||
|
||||
String errorout;
|
||||
while (size_t size = read(error_pipe[0], buffer, 1024))
|
||||
{
|
||||
if (size == -1)
|
||||
break;
|
||||
errorout += String(buffer, buffer+size);
|
||||
bool stdout_closed = false, stderr_closed = false;
|
||||
FDWatcher stdout_watcher{read_pipe[0], pipe_reader(output, stdout_closed)};
|
||||
FDWatcher stderr_watcher{error_pipe[0], pipe_reader(error, stderr_closed)};
|
||||
|
||||
while (not stdout_closed or not stderr_closed)
|
||||
EventManager::instance().handle_next_events(EventMode::Urgent);
|
||||
}
|
||||
close(error_pipe[0]);
|
||||
if (not errorout.empty())
|
||||
write_debug("shell stderr: <<<\n" + errorout + ">>>");
|
||||
|
||||
if (not error.empty())
|
||||
write_debug("shell stderr: <<<\n" + error + ">>>");
|
||||
|
||||
waitpid(pid, exit_status, 0);
|
||||
if (exit_status)
|
||||
@ -105,13 +115,7 @@ String ShellManager::pipe(StringView input,
|
||||
{
|
||||
auto& match = *it;
|
||||
|
||||
StringView name;
|
||||
if (match[1].matched)
|
||||
name = StringView(match[1].first, match[1].second);
|
||||
else if (match[2].matched)
|
||||
name = StringView(match[2].first, match[2].second);
|
||||
else
|
||||
kak_assert(false);
|
||||
StringView name = StringView(match[1].first, match[1].second);
|
||||
kak_assert(name.length() > 0);
|
||||
|
||||
auto local_var = env_vars.find(name);
|
||||
|
@ -32,7 +32,9 @@ enum class InfoStyle
|
||||
MenuDoc
|
||||
};
|
||||
|
||||
using InputCallback = std::function<void()>;
|
||||
enum class EventMode;
|
||||
|
||||
using InputCallback = std::function<void(EventMode mode)>;
|
||||
|
||||
class UserInterface : public SafeCountable
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user