Add <c-g> to cancel current operation
The current implementation only does this during regex operations, but should be extensible to other operations that might take a long time by regularly calling EventManager::handle_urgent_events().
This commit is contained in:
parent
e140df8f08
commit
cfa658b899
|
@ -53,6 +53,12 @@ Client::Client(std::unique_ptr<UserInterface>&& ui,
|
||||||
killpg(getpgrp(), SIGINT);
|
killpg(getpgrp(), SIGINT);
|
||||||
set_signal_handler(SIGINT, prev_handler);
|
set_signal_handler(SIGINT, prev_handler);
|
||||||
}
|
}
|
||||||
|
else if (key == ctrl('g'))
|
||||||
|
{
|
||||||
|
m_pending_keys.clear();
|
||||||
|
print_status({"operation cancelled", context().faces()["Error"]});
|
||||||
|
throw cancel{};
|
||||||
|
}
|
||||||
else if (key.modifiers & Key::Modifiers::Resize)
|
else if (key.modifiers & Key::Modifiers::Resize)
|
||||||
{
|
{
|
||||||
m_window->set_dimensions(key.coord());
|
m_window->set_dimensions(key.coord());
|
||||||
|
|
|
@ -161,6 +161,13 @@ void EventManager::force_signal(int fd)
|
||||||
m_has_forced_fd = true;
|
m_has_forced_fd = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EventManager::handle_urgent_events()
|
||||||
|
{
|
||||||
|
if (has_instance())
|
||||||
|
instance().handle_next_events(EventMode::Urgent, nullptr, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SignalHandler set_signal_handler(int signum, SignalHandler handler)
|
SignalHandler set_signal_handler(int signum, SignalHandler handler)
|
||||||
{
|
{
|
||||||
struct sigaction new_action, old_action;
|
struct sigaction new_action, old_action;
|
||||||
|
@ -171,4 +178,5 @@ SignalHandler set_signal_handler(int signum, SignalHandler handler)
|
||||||
sigaction(signum, &new_action, &old_action);
|
sigaction(signum, &new_action, &old_action);
|
||||||
return old_action.sa_handler;
|
return old_action.sa_handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,8 @@ public:
|
||||||
// on next handle_next_events call.
|
// on next handle_next_events call.
|
||||||
void force_signal(int fd);
|
void force_signal(int fd);
|
||||||
|
|
||||||
|
static void handle_urgent_events();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class FDWatcher;
|
friend class FDWatcher;
|
||||||
friend class Timer;
|
friend class Timer;
|
||||||
|
|
|
@ -29,6 +29,11 @@ struct failure : runtime_error
|
||||||
using runtime_error::runtime_error;
|
using runtime_error::runtime_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cancel : runtime_error
|
||||||
|
{
|
||||||
|
cancel() : runtime_error("cancellation requested") {}
|
||||||
|
};
|
||||||
|
|
||||||
struct logic_error : exception
|
struct logic_error : exception
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
|
@ -894,12 +894,17 @@ int run_server(StringView session, StringView server_init,
|
||||||
// Loop so that eventual inputs happening during the processing are handled as
|
// Loop so that eventual inputs happening during the processing are handled as
|
||||||
// well, avoiding unneeded redraws.
|
// well, avoiding unneeded redraws.
|
||||||
bool allow_blocking = not client_manager.has_pending_inputs();
|
bool allow_blocking = not client_manager.has_pending_inputs();
|
||||||
|
try
|
||||||
|
{
|
||||||
while (event_manager.handle_next_events(EventMode::Normal, nullptr, allow_blocking))
|
while (event_manager.handle_next_events(EventMode::Normal, nullptr, allow_blocking))
|
||||||
{
|
{
|
||||||
if (client_manager.process_pending_inputs())
|
if (client_manager.process_pending_inputs())
|
||||||
break;
|
break;
|
||||||
allow_blocking = false;
|
allow_blocking = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (const cancel&) {}
|
||||||
|
|
||||||
client_manager.process_pending_inputs();
|
client_manager.process_pending_inputs();
|
||||||
|
|
||||||
client_manager.clear_client_trash();
|
client_manager.clear_client_trash();
|
||||||
|
|
|
@ -1159,7 +1159,7 @@ void keep(Context& context, NormalParams params)
|
||||||
const auto flags = match_flags(is_bol(begin.coord()), false,
|
const auto flags = match_flags(is_bol(begin.coord()), false,
|
||||||
is_bow(buffer, begin.coord()),
|
is_bow(buffer, begin.coord()),
|
||||||
is_eow(buffer, end.coord()));
|
is_eow(buffer, end.coord()));
|
||||||
if (regex_search(begin, end, begin, end, regex, flags) == matching)
|
if (regex_search(begin, end, begin, end, regex, flags, EventManager::handle_urgent_events) == matching)
|
||||||
keep.push_back(sel);
|
keep.push_back(sel);
|
||||||
}
|
}
|
||||||
if (keep.empty())
|
if (keep.empty())
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "buffer_utils.hh"
|
#include "buffer_utils.hh"
|
||||||
#include "context.hh"
|
#include "context.hh"
|
||||||
|
#include "event_manager.hh"
|
||||||
#include "flags.hh"
|
#include "flags.hh"
|
||||||
#include "option_types.hh"
|
#include "option_types.hh"
|
||||||
#include "regex.hh"
|
#include "regex.hh"
|
||||||
|
@ -287,16 +288,19 @@ find_opening(Iterator pos, const Container& container,
|
||||||
// When on the token of a non-nestable block, we want to consider it opening
|
// When on the token of a non-nestable block, we want to consider it opening
|
||||||
if (nestable and
|
if (nestable and
|
||||||
backward_regex_search(container.begin(), pos,
|
backward_regex_search(container.begin(), pos,
|
||||||
container.begin(), container.end(), res, closing) and
|
container.begin(), container.end(), res, closing,
|
||||||
|
RegexExecFlags::None, EventManager::handle_urgent_events) and
|
||||||
res[0].second == pos)
|
res[0].second == pos)
|
||||||
pos = res[0].first;
|
pos = res[0].first;
|
||||||
|
|
||||||
using RegexIt = RegexIterator<Iterator, RegexMode::Backward>;
|
using RegexIt = RegexIterator<Iterator, RegexMode::Backward, const Regex, void (*)()>;
|
||||||
for (auto&& match : RegexIt{container.begin(), pos, container.begin(), container.end(), opening})
|
for (auto&& match : RegexIt{container.begin(), pos, container.begin(), container.end(), opening,
|
||||||
|
RegexExecFlags::None, EventManager::handle_urgent_events})
|
||||||
{
|
{
|
||||||
if (nestable)
|
if (nestable)
|
||||||
{
|
{
|
||||||
for (auto m [[maybe_unused]] : RegexIt{match[0].second, pos, container.begin(), container.end(), closing})
|
for (auto m [[maybe_unused]] : RegexIt{match[0].second, pos, container.begin(), container.end(), closing,
|
||||||
|
RegexExecFlags::None, EventManager::handle_urgent_events})
|
||||||
++level;
|
++level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,12 +318,13 @@ find_closing(Iterator pos, const Container& container,
|
||||||
const Regex& opening, const Regex& closing,
|
const Regex& opening, const Regex& closing,
|
||||||
int level, bool nestable)
|
int level, bool nestable)
|
||||||
{
|
{
|
||||||
using RegexIt = RegexIterator<Iterator, RegexMode::Forward>;
|
for (auto match : RegexIterator{pos, container.end(), container.begin(), container.end(), closing,
|
||||||
for (auto match : RegexIt{pos, container.end(), container.begin(), container.end(), closing})
|
RegexExecFlags::None, EventManager::handle_urgent_events})
|
||||||
{
|
{
|
||||||
if (nestable)
|
if (nestable)
|
||||||
{
|
{
|
||||||
for (auto m [[maybe_unused]] : RegexIt{pos, match[0].first, container.begin(), container.end(), opening})
|
for (auto m [[maybe_unused]] : RegexIterator{pos, match[0].first, container.begin(), container.end(), opening,
|
||||||
|
RegexExecFlags::None, EventManager::handle_urgent_events})
|
||||||
++level;
|
++level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +361,8 @@ find_surrounding(const Container& container, Iterator pos,
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
else if (MatchResults<Iterator> res;
|
else if (MatchResults<Iterator> res;
|
||||||
regex_search(pos, container.end(), container.begin(), container.end(), res, opening) and
|
regex_search(pos, container.end(), container.begin(), container.end(), res, opening,
|
||||||
|
RegexExecFlags::None, EventManager::handle_urgent_events) and
|
||||||
res[0].first == pos) // Skip opening match if pos lies on it
|
res[0].first == pos) // Skip opening match if pos lies on it
|
||||||
last = empty(res[0]) ? std::next(res[0].second) : res[0].second;
|
last = empty(res[0]) ? std::next(res[0].second) : res[0].second;
|
||||||
|
|
||||||
|
@ -868,11 +874,13 @@ static bool find_next(const Buffer& buffer, const BufferIterator& pos,
|
||||||
{
|
{
|
||||||
if (pos != buffer.end() and
|
if (pos != buffer.end() and
|
||||||
regex_search(pos, buffer.end(), buffer.begin(), buffer.end(),
|
regex_search(pos, buffer.end(), buffer.begin(), buffer.end(),
|
||||||
matches, ex, match_flags(buffer, pos, buffer.end())))
|
matches, ex, match_flags(buffer, pos, buffer.end()),
|
||||||
|
EventManager::handle_urgent_events))
|
||||||
return true;
|
return true;
|
||||||
wrapped = true;
|
wrapped = true;
|
||||||
return regex_search(buffer.begin(), buffer.end(), buffer.begin(), buffer.end(),
|
return regex_search(buffer.begin(), buffer.end(), buffer.begin(), buffer.end(),
|
||||||
matches, ex, match_flags(buffer, buffer.begin(), buffer.end()));
|
matches, ex, match_flags(buffer, buffer.begin(), buffer.end()),
|
||||||
|
EventManager::handle_urgent_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool find_prev(const Buffer& buffer, const BufferIterator& pos,
|
static bool find_prev(const Buffer& buffer, const BufferIterator& pos,
|
||||||
|
@ -883,13 +891,15 @@ static bool find_prev(const Buffer& buffer, const BufferIterator& pos,
|
||||||
backward_regex_search(buffer.begin(), pos, buffer.begin(), buffer.end(),
|
backward_regex_search(buffer.begin(), pos, buffer.begin(), buffer.end(),
|
||||||
matches, ex,
|
matches, ex,
|
||||||
match_flags(buffer, buffer.begin(), pos) |
|
match_flags(buffer, buffer.begin(), pos) |
|
||||||
RegexExecFlags::NotInitialNull))
|
RegexExecFlags::NotInitialNull,
|
||||||
|
EventManager::handle_urgent_events))
|
||||||
return true;
|
return true;
|
||||||
wrapped = true;
|
wrapped = true;
|
||||||
return backward_regex_search(buffer.begin(), buffer.end(), buffer.begin(), buffer.end(),
|
return backward_regex_search(buffer.begin(), buffer.end(), buffer.begin(), buffer.end(),
|
||||||
matches, ex,
|
matches, ex,
|
||||||
match_flags(buffer, buffer.begin(), buffer.end()) |
|
match_flags(buffer, buffer.begin(), buffer.end()) |
|
||||||
RegexExecFlags::NotInitialNull);
|
RegexExecFlags::NotInitialNull,
|
||||||
|
EventManager::handle_urgent_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<RegexMode mode>
|
template<RegexMode mode>
|
||||||
|
@ -935,7 +945,8 @@ Vector<Selection> select_matches(const Buffer& buffer, ConstArrayView<Selection>
|
||||||
auto sel_beg = buffer.iterator_at(sel.min());
|
auto sel_beg = buffer.iterator_at(sel.min());
|
||||||
auto sel_end = utf8::next(buffer.iterator_at(sel.max()), buffer.end());
|
auto sel_end = utf8::next(buffer.iterator_at(sel.max()), buffer.end());
|
||||||
|
|
||||||
for (auto&& match : RegexIterator{sel_beg, sel_end, vm, match_flags(buffer, sel_beg, sel_end)})
|
for (auto&& match : RegexIterator{sel_beg, sel_end, vm, match_flags(buffer, sel_beg, sel_end),
|
||||||
|
EventManager::handle_urgent_events})
|
||||||
{
|
{
|
||||||
auto capture = match[capture_idx];
|
auto capture = match[capture_idx];
|
||||||
if (not capture.matched or capture.first == sel_end)
|
if (not capture.matched or capture.first == sel_end)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user