Support selecting yank/paste register with "
This commit is contained in:
parent
75fe9a76db
commit
77e2e8a31e
|
@ -84,6 +84,13 @@ public:
|
||||||
|
|
||||||
void on_key(Key key) override
|
void on_key(Key key) override
|
||||||
{
|
{
|
||||||
|
if (m_waiting_for_reg)
|
||||||
|
{
|
||||||
|
if (key.modifiers == Key::Modifiers::None)
|
||||||
|
m_params.reg = key.key;
|
||||||
|
m_waiting_for_reg = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
bool do_restore_hooks = false;
|
bool do_restore_hooks = false;
|
||||||
auto restore_hooks = on_scope_end([&, this]{
|
auto restore_hooks = on_scope_end([&, this]{
|
||||||
if (do_restore_hooks)
|
if (do_restore_hooks)
|
||||||
|
@ -98,9 +105,9 @@ public:
|
||||||
context().ui().info_hide();
|
context().ui().info_hide();
|
||||||
|
|
||||||
if (key.modifiers == Key::Modifiers::None and isdigit(key.key))
|
if (key.modifiers == Key::Modifiers::None and isdigit(key.key))
|
||||||
m_count = m_count * 10 + key.key - '0';
|
m_params.count = m_params.count * 10 + key.key - '0';
|
||||||
else if (key == Key::Backspace)
|
else if (key == Key::Backspace)
|
||||||
m_count /= 10;
|
m_params.count /= 10;
|
||||||
else if (key == '\\')
|
else if (key == '\\')
|
||||||
{
|
{
|
||||||
if (not m_hooks_disabled)
|
if (not m_hooks_disabled)
|
||||||
|
@ -109,6 +116,10 @@ public:
|
||||||
context().disable_user_hooks();
|
context().disable_user_hooks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (key == '"')
|
||||||
|
{
|
||||||
|
m_waiting_for_reg = true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_hooks_disabled)
|
if (m_hooks_disabled)
|
||||||
|
@ -119,10 +130,9 @@ public:
|
||||||
if (context().options()["autoinfo"].get<int>() >= 2 and context().has_ui())
|
if (context().options()["autoinfo"].get<int>() >= 2 and context().has_ui())
|
||||||
context().ui().info_show(key_to_str(key), it->second.docstring, CharCoord{},
|
context().ui().info_show(key_to_str(key), it->second.docstring, CharCoord{},
|
||||||
get_face("Information"), InfoStyle::Prompt);
|
get_face("Information"), InfoStyle::Prompt);
|
||||||
it->second.func(context(), m_count);
|
it->second.func(context(), m_params);
|
||||||
}
|
}
|
||||||
m_count = 0;
|
m_params = { 0, '"' };
|
||||||
|
|
||||||
}
|
}
|
||||||
context().hooks().run_hook("NormalKey", key_to_str(key), context());
|
context().hooks().run_hook("NormalKey", key_to_str(key), context());
|
||||||
m_idle_timer.set_next_date(Clock::now() + idle_timeout);
|
m_idle_timer.set_next_date(Clock::now() + idle_timeout);
|
||||||
|
@ -131,10 +141,15 @@ public:
|
||||||
DisplayLine mode_line() const override
|
DisplayLine mode_line() const override
|
||||||
{
|
{
|
||||||
AtomList atoms = { { to_string(context().selections().size()) + " sel", Face(Colors::Blue) } };
|
AtomList atoms = { { to_string(context().selections().size()) + " sel", Face(Colors::Blue) } };
|
||||||
if (m_count != 0)
|
if (m_params.count != 0)
|
||||||
{
|
{
|
||||||
atoms.push_back({ "; param=", Face(Colors::Yellow) });
|
atoms.push_back({ "; param=", Face(Colors::Yellow) });
|
||||||
atoms.push_back({ to_string(m_count), Face(Colors::Green) });
|
atoms.push_back({ to_string(m_params.count), Face(Colors::Green) });
|
||||||
|
}
|
||||||
|
if (m_params.reg != '"')
|
||||||
|
{
|
||||||
|
atoms.push_back({ "; reg=", Face(Colors::Yellow) });
|
||||||
|
atoms.push_back({ StringView(m_params.reg), Face(Colors::Green) });
|
||||||
}
|
}
|
||||||
return atoms;
|
return atoms;
|
||||||
}
|
}
|
||||||
|
@ -142,8 +157,9 @@ public:
|
||||||
KeymapMode keymap_mode() const override { return KeymapMode::Normal; }
|
KeymapMode keymap_mode() const override { return KeymapMode::Normal; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_count = 0;
|
NormalParams m_params = { 0, '"' };
|
||||||
bool m_hooks_disabled = false;
|
bool m_hooks_disabled = false;
|
||||||
|
bool m_waiting_for_reg = false;
|
||||||
Timer m_idle_timer;
|
Timer m_idle_timer;
|
||||||
Timer m_fs_check_timer;
|
Timer m_fs_check_timer;
|
||||||
};
|
};
|
||||||
|
|
152
src/normal.cc
152
src/normal.cc
|
@ -69,7 +69,7 @@ class Select
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
constexpr Select(T t) : m_func(t) {}
|
constexpr Select(T t) : m_func(t) {}
|
||||||
void operator() (Context& context, int) { select<mode>(context, m_func); }
|
void operator() (Context& context, NormalParams) { select<mode>(context, m_func); }
|
||||||
private:
|
private:
|
||||||
T m_func;
|
T m_func;
|
||||||
};
|
};
|
||||||
|
@ -95,12 +95,12 @@ void select_coord(Buffer& buffer, ByteCoord coord, SelectionList& selections)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<InsertMode mode>
|
template<InsertMode mode>
|
||||||
void enter_insert_mode(Context& context, int)
|
void enter_insert_mode(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
context.input_handler().insert(mode);
|
context.input_handler().insert(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void repeat_last_insert(Context& context, int)
|
void repeat_last_insert(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
context.input_handler().repeat_last_insert();
|
context.input_handler().repeat_last_insert();
|
||||||
}
|
}
|
||||||
|
@ -129,14 +129,14 @@ void on_next_key_with_autoinfo(const Context& context, KeymapMode keymap_mode, C
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SelectMode mode>
|
template<SelectMode mode>
|
||||||
void goto_commands(Context& context, int line)
|
void goto_commands(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
if (line != 0)
|
if (params.count != 0)
|
||||||
{
|
{
|
||||||
context.push_jump();
|
context.push_jump();
|
||||||
select_coord<mode>(context.buffer(), LineCount{line - 1}, context.selections());
|
select_coord<mode>(context.buffer(), LineCount{params.count - 1}, context.selections());
|
||||||
if (context.has_window())
|
if (context.has_window())
|
||||||
context.window().center_line(LineCount{line-1});
|
context.window().center_line(LineCount{params.count-1});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -257,10 +257,10 @@ void goto_commands(Context& context, int line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void view_commands(Context& context, int param)
|
void view_commands(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
on_next_key_with_autoinfo(context, KeymapMode::View,
|
on_next_key_with_autoinfo(context, KeymapMode::View,
|
||||||
[param](Key key, Context& context) {
|
[params](Key key, Context& context) {
|
||||||
if (key.modifiers != Key::Modifiers::None or not context.has_window())
|
if (key.modifiers != Key::Modifiers::None or not context.has_window())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -279,16 +279,16 @@ void view_commands(Context& context, int param)
|
||||||
context.window().display_line_at(cursor_line, window.dimensions().line-1);
|
context.window().display_line_at(cursor_line, window.dimensions().line-1);
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
context.window().scroll(-std::max<CharCount>(1, param));
|
context.window().scroll(-std::max<CharCount>(1, params.count));
|
||||||
break;
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
context.window().scroll( std::max<LineCount>(1, param));
|
context.window().scroll( std::max<LineCount>(1, params.count));
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
context.window().scroll(-std::max<LineCount>(1, param));
|
context.window().scroll(-std::max<LineCount>(1, params.count));
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
context.window().scroll( std::max<CharCount>(1, param));
|
context.window().scroll( std::max<CharCount>(1, params.count));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}, "view",
|
}, "view",
|
||||||
|
@ -301,7 +301,7 @@ void view_commands(Context& context, int param)
|
||||||
"l: scroll right \n");
|
"l: scroll right \n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void replace_with_char(Context& context, int)
|
void replace_with_char(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
on_next_key_with_autoinfo(context, KeymapMode::None,
|
on_next_key_with_autoinfo(context, KeymapMode::None,
|
||||||
[](Key key, Context& context) {
|
[](Key key, Context& context) {
|
||||||
|
@ -330,7 +330,7 @@ Codepoint swap_case(Codepoint cp)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Codepoint (*func)(Codepoint)>
|
template<Codepoint (*func)(Codepoint)>
|
||||||
void for_each_char(Context& context, int)
|
void for_each_char(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
ScopedEdition edition(context);
|
ScopedEdition edition(context);
|
||||||
std::vector<String> sels = context.selections_content();
|
std::vector<String> sels = context.selections_content();
|
||||||
|
@ -342,7 +342,7 @@ void for_each_char(Context& context, int)
|
||||||
context.selections().insert(sels, InsertMode::Replace);
|
context.selections().insert(sels, InsertMode::Replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
void command(Context& context, int)
|
void command(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
if (not CommandManager::has_instance())
|
if (not CommandManager::has_instance())
|
||||||
return;
|
return;
|
||||||
|
@ -368,7 +368,7 @@ void command(Context& context, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<InsertMode mode>
|
template<InsertMode mode>
|
||||||
void pipe(Context& context, int)
|
void pipe(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
const char* prompt = mode == InsertMode::Replace ? "pipe:" : "pipe (ins):";
|
const char* prompt = mode == InsertMode::Replace ? "pipe:" : "pipe (ins):";
|
||||||
context.input_handler().prompt(prompt, "", get_face("Prompt"), shell_complete,
|
context.input_handler().prompt(prompt, "", get_face("Prompt"), shell_complete,
|
||||||
|
@ -434,25 +434,25 @@ void select_next_match(const Buffer& buffer, SelectionList& selections,
|
||||||
selections.sort_and_merge_overlapping();
|
selections.sort_and_merge_overlapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
void yank(Context& context, int)
|
void yank(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
RegisterManager::instance()['"'] = context.selections_content();
|
RegisterManager::instance()[params.reg] = context.selections_content();
|
||||||
context.print_status({ "yanked " + to_string(context.selections().size()) +
|
context.print_status({ "yanked " + to_string(context.selections().size()) +
|
||||||
" selections", get_face("Information") });
|
" selections", get_face("Information") });
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase_selections(Context& context, int)
|
void erase_selections(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
RegisterManager::instance()['"'] = context.selections_content();
|
RegisterManager::instance()[params.reg] = context.selections_content();
|
||||||
ScopedEdition edition(context);
|
ScopedEdition edition(context);
|
||||||
context.selections().erase();
|
context.selections().erase();
|
||||||
context.selections().avoid_eol();
|
context.selections().avoid_eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
void change(Context& context, int param)
|
void change(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
RegisterManager::instance()['"'] = context.selections_content();
|
RegisterManager::instance()[params.reg] = context.selections_content();
|
||||||
enter_insert_mode<InsertMode::Replace>(context, param);
|
enter_insert_mode<InsertMode::Replace>(context, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr InsertMode adapt_for_linewise(InsertMode mode)
|
constexpr InsertMode adapt_for_linewise(InsertMode mode)
|
||||||
|
@ -466,9 +466,9 @@ constexpr InsertMode adapt_for_linewise(InsertMode mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<InsertMode mode>
|
template<InsertMode mode>
|
||||||
void paste(Context& context, int)
|
void paste(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
auto strings = RegisterManager::instance()['"'].values(context);
|
auto strings = RegisterManager::instance()[params.reg].values(context);
|
||||||
InsertMode effective_mode = mode;
|
InsertMode effective_mode = mode;
|
||||||
for (auto& str : strings)
|
for (auto& str : strings)
|
||||||
{
|
{
|
||||||
|
@ -483,9 +483,9 @@ void paste(Context& context, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<InsertMode mode>
|
template<InsertMode mode>
|
||||||
void paste_all(Context& context, int)
|
void paste_all(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
auto strings = RegisterManager::instance()['"'].values(context);
|
auto strings = RegisterManager::instance()[params.reg].values(context);
|
||||||
InsertMode effective_mode = mode;
|
InsertMode effective_mode = mode;
|
||||||
String all;
|
String all;
|
||||||
std::vector<ByteCount> offsets;
|
std::vector<ByteCount> offsets;
|
||||||
|
@ -576,7 +576,7 @@ void regex_prompt(Context& context, const String prompt, T func)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SelectMode mode, Direction direction>
|
template<SelectMode mode, Direction direction>
|
||||||
void search(Context& context, int)
|
void search(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
regex_prompt(context, direction == Forward ? "search:" : "reverse search:",
|
regex_prompt(context, direction == Forward ? "search:" : "reverse search:",
|
||||||
[](Regex ex, PromptEvent event, Context& context) {
|
[](Regex ex, PromptEvent event, Context& context) {
|
||||||
|
@ -590,7 +590,7 @@ void search(Context& context, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SelectMode mode, Direction direction>
|
template<SelectMode mode, Direction direction>
|
||||||
void search_next(Context& context, int param)
|
void search_next(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
StringView str = context.main_sel_register_value("/");
|
StringView str = context.main_sel_register_value("/");
|
||||||
if (not str.empty())
|
if (not str.empty())
|
||||||
|
@ -600,7 +600,7 @@ void search_next(Context& context, int param)
|
||||||
Regex ex{str.begin(), str.end()};
|
Regex ex{str.begin(), str.end()};
|
||||||
do {
|
do {
|
||||||
select_next_match<direction, mode>(context.buffer(), context.selections(), ex);
|
select_next_match<direction, mode>(context.buffer(), context.selections(), ex);
|
||||||
} while (--param > 0);
|
} while (--params.count > 0);
|
||||||
}
|
}
|
||||||
catch (RegexError& err)
|
catch (RegexError& err)
|
||||||
{
|
{
|
||||||
|
@ -612,7 +612,7 @@ void search_next(Context& context, int param)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool smart>
|
template<bool smart>
|
||||||
void use_selection_as_search_pattern(Context& context, int)
|
void use_selection_as_search_pattern(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
std::vector<String> patterns;
|
std::vector<String> patterns;
|
||||||
auto& sels = context.selections();
|
auto& sels = context.selections();
|
||||||
|
@ -634,7 +634,7 @@ void use_selection_as_search_pattern(Context& context, int)
|
||||||
RegisterManager::instance()['/'] = patterns;
|
RegisterManager::instance()['/'] = patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
void select_regex(Context& context, int)
|
void select_regex(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
regex_prompt(context, "select:", [](Regex ex, PromptEvent event, Context& context) {
|
regex_prompt(context, "select:", [](Regex ex, PromptEvent event, Context& context) {
|
||||||
if (ex.empty())
|
if (ex.empty())
|
||||||
|
@ -646,7 +646,7 @@ void select_regex(Context& context, int)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void split_regex(Context& context, int)
|
void split_regex(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
regex_prompt(context, "split:", [](Regex ex, PromptEvent event, Context& context) {
|
regex_prompt(context, "split:", [](Regex ex, PromptEvent event, Context& context) {
|
||||||
if (ex.empty())
|
if (ex.empty())
|
||||||
|
@ -658,7 +658,7 @@ void split_regex(Context& context, int)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void split_lines(Context& context, int)
|
void split_lines(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
auto& selections = context.selections();
|
auto& selections = context.selections();
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
|
@ -680,7 +680,7 @@ void split_lines(Context& context, int)
|
||||||
selections = std::move(res);
|
selections = std::move(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
void join_select_spaces(Context& context, int)
|
void join_select_spaces(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
std::vector<Selection> selections;
|
std::vector<Selection> selections;
|
||||||
|
@ -705,7 +705,7 @@ void join_select_spaces(Context& context, int)
|
||||||
context.selections().insert(" "_str, InsertMode::Replace);
|
context.selections().insert(" "_str, InsertMode::Replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
void join(Context& context, int param)
|
void join(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
SelectionList sels{context.selections()};
|
SelectionList sels{context.selections()};
|
||||||
auto restore_sels = on_scope_end([&]{
|
auto restore_sels = on_scope_end([&]{
|
||||||
|
@ -713,11 +713,11 @@ void join(Context& context, int param)
|
||||||
context.selections() = std::move(sels);
|
context.selections() = std::move(sels);
|
||||||
});
|
});
|
||||||
|
|
||||||
join_select_spaces(context, param);
|
join_select_spaces(context, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool matching>
|
template<bool matching>
|
||||||
void keep(Context& context, int)
|
void keep(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
constexpr const char* prompt = matching ? "keep matching:" : "keep not matching:";
|
constexpr const char* prompt = matching ? "keep matching:" : "keep not matching:";
|
||||||
regex_prompt(context, prompt, [](const Regex& ex, PromptEvent, Context& context) {
|
regex_prompt(context, prompt, [](const Regex& ex, PromptEvent, Context& context) {
|
||||||
|
@ -737,7 +737,7 @@ void keep(Context& context, int)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void keep_pipe(Context& context, int)
|
void keep_pipe(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
context.input_handler().prompt(
|
context.input_handler().prompt(
|
||||||
"keep pipe:", "", get_face("Prompt"), shell_complete,
|
"keep pipe:", "", get_face("Prompt"), shell_complete,
|
||||||
|
@ -761,7 +761,7 @@ void keep_pipe(Context& context, int)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
template<bool indent_empty = false>
|
template<bool indent_empty = false>
|
||||||
void indent(Context& context, int)
|
void indent(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
CharCount indent_width = context.options()["indentwidth"].get<int>();
|
CharCount indent_width = context.options()["indentwidth"].get<int>();
|
||||||
String indent = indent_width == 0 ? "\t" : String{' ', indent_width};
|
String indent = indent_width == 0 ? "\t" : String{' ', indent_width};
|
||||||
|
@ -788,7 +788,7 @@ void indent(Context& context, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool deindent_incomplete = true>
|
template<bool deindent_incomplete = true>
|
||||||
void deindent(Context& context, int)
|
void deindent(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
CharCount tabstop = context.options()["tabstop"].get<int>();
|
CharCount tabstop = context.options()["tabstop"].get<int>();
|
||||||
CharCount indent_width = context.options()["indentwidth"].get<int>();
|
CharCount indent_width = context.options()["indentwidth"].get<int>();
|
||||||
|
@ -837,9 +837,9 @@ void deindent(Context& context, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<ObjectFlags flags, SelectMode mode = SelectMode::Replace>
|
template<ObjectFlags flags, SelectMode mode = SelectMode::Replace>
|
||||||
void select_object(Context& context, int param)
|
void select_object(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
int level = param <= 0 ? 0 : param - 1;
|
int level = params.count <= 0 ? 0 : params.count - 1;
|
||||||
on_next_key_with_autoinfo(context, KeymapMode::None,
|
on_next_key_with_autoinfo(context, KeymapMode::None,
|
||||||
[level](Key key, Context& context) {
|
[level](Key key, Context& context) {
|
||||||
if (key.modifiers != Key::Modifiers::None)
|
if (key.modifiers != Key::Modifiers::None)
|
||||||
|
@ -902,7 +902,7 @@ void select_object(Context& context, int param)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Key::NamedKey key>
|
template<Key::NamedKey key>
|
||||||
void scroll(Context& context, int)
|
void scroll(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
static_assert(key == Key::PageUp or key == Key::PageDown,
|
static_assert(key == Key::PageUp or key == Key::PageDown,
|
||||||
"scrool only implements PageUp and PageDown");
|
"scrool only implements PageUp and PageDown");
|
||||||
|
@ -928,13 +928,14 @@ void scroll(Context& context, int)
|
||||||
window.set_position(position);
|
window.set_position(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rotate_selections(Context& context, int count)
|
void rotate_selections(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
context.selections().rotate_main(count != 0 ? count : 1);
|
context.selections().rotate_main(params.count != 0 ? params.count : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rotate_selections_content(Context& context, int group)
|
void rotate_selections_content(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
|
int group = params.count;
|
||||||
int count = 1;
|
int count = 1;
|
||||||
auto strings = context.selections_content();
|
auto strings = context.selections_content();
|
||||||
if (group == 0 or group > (int)strings.size())
|
if (group == 0 or group > (int)strings.size())
|
||||||
|
@ -961,18 +962,18 @@ enum class SelectFlags
|
||||||
template<> struct WithBitOps<SelectFlags> : std::true_type {};
|
template<> struct WithBitOps<SelectFlags> : std::true_type {};
|
||||||
|
|
||||||
template<SelectFlags flags>
|
template<SelectFlags flags>
|
||||||
void select_to_next_char(Context& context, int param)
|
void select_to_next_char(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
on_next_key_with_autoinfo(context, KeymapMode::None,
|
on_next_key_with_autoinfo(context, KeymapMode::None,
|
||||||
[param](Key key, Context& context) {
|
[params](Key key, Context& context) {
|
||||||
select<flags & SelectFlags::Extend ? SelectMode::Extend : SelectMode::Replace>(
|
select<flags & SelectFlags::Extend ? SelectMode::Extend : SelectMode::Replace>(
|
||||||
context,
|
context,
|
||||||
std::bind(flags & SelectFlags::Reverse ? select_to_reverse : select_to,
|
std::bind(flags & SelectFlags::Reverse ? select_to_reverse : select_to,
|
||||||
_1, _2, key.key, param, flags & SelectFlags::Inclusive));
|
_1, _2, key.key, params.count, flags & SelectFlags::Inclusive));
|
||||||
}, "select to next char","enter char to select to");
|
}, "select to next char","enter char to select to");
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_or_end_macro_recording(Context& context, int)
|
void start_or_end_macro_recording(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
if (context.input_handler().is_recording())
|
if (context.input_handler().is_recording())
|
||||||
context.input_handler().stop_recording();
|
context.input_handler().stop_recording();
|
||||||
|
@ -984,16 +985,16 @@ void start_or_end_macro_recording(Context& context, int)
|
||||||
}, "record macro", "enter macro name ");
|
}, "record macro", "enter macro name ");
|
||||||
}
|
}
|
||||||
|
|
||||||
void end_macro_recording(Context& context, int)
|
void end_macro_recording(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
if (context.input_handler().is_recording())
|
if (context.input_handler().is_recording())
|
||||||
context.input_handler().stop_recording();
|
context.input_handler().stop_recording();
|
||||||
}
|
}
|
||||||
|
|
||||||
void replay_macro(Context& context, int count)
|
void replay_macro(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
on_next_key_with_autoinfo(context, KeymapMode::None,
|
on_next_key_with_autoinfo(context, KeymapMode::None,
|
||||||
[count](Key key, Context& context) mutable {
|
[params](Key key, Context& context) mutable {
|
||||||
if (key.modifiers == Key::Modifiers::None and isalpha(key.key))
|
if (key.modifiers == Key::Modifiers::None and isalpha(key.key))
|
||||||
{
|
{
|
||||||
static std::unordered_set<char> running_macros;
|
static std::unordered_set<char> running_macros;
|
||||||
|
@ -1009,14 +1010,14 @@ void replay_macro(Context& context, int count)
|
||||||
|
|
||||||
auto keys = parse_keys(reg_val[0]);
|
auto keys = parse_keys(reg_val[0]);
|
||||||
ScopedEdition edition(context);
|
ScopedEdition edition(context);
|
||||||
do { exec_keys(keys, context); } while (--count > 0);
|
do { exec_keys(keys, context); } while (--params.count > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, "replay macro", "enter macro name");
|
}, "replay macro", "enter macro name");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Direction direction>
|
template<Direction direction>
|
||||||
void jump(Context& context, int)
|
void jump(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
auto jump = (direction == Forward) ?
|
auto jump = (direction == Forward) ?
|
||||||
context.jump_forward() : context.jump_backward();
|
context.jump_forward() : context.jump_backward();
|
||||||
|
@ -1028,14 +1029,14 @@ void jump(Context& context, int)
|
||||||
context.selections() = jump;
|
context.selections() = jump;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_selections(Context& context, int)
|
void save_selections(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
context.push_jump();
|
context.push_jump();
|
||||||
context.print_status({ "saved " + to_string(context.selections().size()) +
|
context.print_status({ "saved " + to_string(context.selections().size()) +
|
||||||
" selections", get_face("Information") });
|
" selections", get_face("Information") });
|
||||||
}
|
}
|
||||||
|
|
||||||
void align(Context& context, int)
|
void align(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
auto& selections = context.selections();
|
auto& selections = context.selections();
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
|
@ -1085,8 +1086,9 @@ void align(Context& context, int)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy_indent(Context& context, int selection)
|
void copy_indent(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
|
int selection = params.count;
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
auto& selections = context.selections();
|
auto& selections = context.selections();
|
||||||
std::vector<LineCount> lines;
|
std::vector<LineCount> lines;
|
||||||
|
@ -1122,11 +1124,11 @@ void copy_indent(Context& context, int selection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tabs_to_spaces(Context& context, int ts)
|
void tabs_to_spaces(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
const CharCount opt_tabstop = context.options()["tabstop"].get<int>();
|
const CharCount opt_tabstop = context.options()["tabstop"].get<int>();
|
||||||
const CharCount tabstop = ts == 0 ? opt_tabstop : ts;
|
const CharCount tabstop = params.count == 0 ? opt_tabstop : params.count;
|
||||||
std::vector<Selection> tabs;
|
std::vector<Selection> tabs;
|
||||||
std::vector<String> spaces;
|
std::vector<String> spaces;
|
||||||
for (auto& sel : context.selections())
|
for (auto& sel : context.selections())
|
||||||
|
@ -1147,11 +1149,11 @@ void tabs_to_spaces(Context& context, int ts)
|
||||||
SelectionList{ buffer, std::move(tabs) }.insert(spaces, InsertMode::Replace);
|
SelectionList{ buffer, std::move(tabs) }.insert(spaces, InsertMode::Replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spaces_to_tabs(Context& context, int ts)
|
void spaces_to_tabs(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
const CharCount opt_tabstop = context.options()["tabstop"].get<int>();
|
const CharCount opt_tabstop = context.options()["tabstop"].get<int>();
|
||||||
const CharCount tabstop = ts == 0 ? opt_tabstop : ts;
|
const CharCount tabstop = params.count == 0 ? opt_tabstop : params.count;
|
||||||
std::vector<Selection> spaces;
|
std::vector<Selection> spaces;
|
||||||
for (auto& sel : context.selections())
|
for (auto& sel : context.selections())
|
||||||
{
|
{
|
||||||
|
@ -1182,7 +1184,7 @@ void spaces_to_tabs(Context& context, int ts)
|
||||||
SelectionList{ buffer, std::move(spaces) }.insert("\t"_str, InsertMode::Replace);
|
SelectionList{ buffer, std::move(spaces) }.insert("\t"_str, InsertMode::Replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
void undo(Context& context, int)
|
void undo(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
Buffer& buffer = context.buffer();
|
Buffer& buffer = context.buffer();
|
||||||
size_t timestamp = buffer.timestamp();
|
size_t timestamp = buffer.timestamp();
|
||||||
|
@ -1197,7 +1199,7 @@ void undo(Context& context, int)
|
||||||
context.print_status({ "nothing left to undo", get_face("Information") });
|
context.print_status({ "nothing left to undo", get_face("Information") });
|
||||||
}
|
}
|
||||||
|
|
||||||
void redo(Context& context, int)
|
void redo(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
Buffer& buffer = context.buffer();
|
Buffer& buffer = context.buffer();
|
||||||
|
@ -1220,10 +1222,10 @@ class Repeated
|
||||||
public:
|
public:
|
||||||
constexpr Repeated(T t) : m_func(t) {}
|
constexpr Repeated(T t) : m_func(t) {}
|
||||||
|
|
||||||
void operator() (Context& context, int count)
|
void operator() (Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
ScopedEdition edition(context);
|
ScopedEdition edition(context);
|
||||||
do { m_func(context, 0); } while(--count > 0);
|
do { m_func(context, {0, params.reg}); } while(--params.count > 0);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
T m_func;
|
T m_func;
|
||||||
|
@ -1233,10 +1235,10 @@ template<typename T>
|
||||||
constexpr Repeated<T> repeated(T func) { return Repeated<T>(func); }
|
constexpr Repeated<T> repeated(T func) { return Repeated<T>(func); }
|
||||||
|
|
||||||
template<typename Type, Direction direction, SelectMode mode = SelectMode::Replace>
|
template<typename Type, Direction direction, SelectMode mode = SelectMode::Replace>
|
||||||
void move(Context& context, int count)
|
void move(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
kak_assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
|
kak_assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
|
||||||
Type offset(std::max(count,1));
|
Type offset(std::max(params.count,1));
|
||||||
if (direction == Backward)
|
if (direction == Backward)
|
||||||
offset = -offset;
|
offset = -offset;
|
||||||
auto& selections = context.selections();
|
auto& selections = context.selections();
|
||||||
|
@ -1301,15 +1303,15 @@ KeyMap keymap =
|
||||||
|
|
||||||
{ '.', { "repeat last insert command", repeat_last_insert } },
|
{ '.', { "repeat last insert command", repeat_last_insert } },
|
||||||
|
|
||||||
{ '%', { "select whole buffer", [](Context& context, int) { select_buffer(context.selections()); } } },
|
{ '%', { "select whole buffer", [](Context& context, NormalParams) { select_buffer(context.selections()); } } },
|
||||||
|
|
||||||
{ ':', { "enter command prompt", command } },
|
{ ':', { "enter command prompt", command } },
|
||||||
{ '|', { "pipe each selection through filter and replace with output", pipe<InsertMode::Replace> } },
|
{ '|', { "pipe each selection through filter and replace with output", pipe<InsertMode::Replace> } },
|
||||||
{ alt('|'), { "pipe each selection through filter and append with output", pipe<InsertMode::Append> } },
|
{ alt('|'), { "pipe each selection through filter and append with output", pipe<InsertMode::Append> } },
|
||||||
{ ' ', { "remove all selection except main", [](Context& context, int count) { keep_selection(context.selections(), count ? count-1 : context.selections().main_index()); } } },
|
{ ' ', { "remove all selection except main", [](Context& context, NormalParams p) { keep_selection(context.selections(), p.count ? p.count-1 : context.selections().main_index()); } } },
|
||||||
{ alt(' '), { "remove main selection", [](Context& context, int count) { remove_selection(context.selections(), count ? count-1 : context.selections().main_index()); } } },
|
{ alt(' '), { "remove main selection", [](Context& context, NormalParams p) { remove_selection(context.selections(), p.count ? p.count-1 : context.selections().main_index()); } } },
|
||||||
{ ';', { "reduce selections to their cursor", [](Context& context, int count) { clear_selections(context.selections()); } } },
|
{ ';', { "reduce selections to their cursor", [](Context& context, NormalParams) { clear_selections(context.selections()); } } },
|
||||||
{ alt(';'), { "swap selections cursor and anchor", [](Context& context, int count) { flip_selections(context.selections()); } } },
|
{ alt(';'), { "swap selections cursor and anchor", [](Context& context, NormalParams) { flip_selections(context.selections()); } } },
|
||||||
|
|
||||||
{ 'w', { "select to next word start", repeated(make_select<SelectMode::Replace>(select_to_next_word<Word>)) } },
|
{ 'w', { "select to next word start", repeated(make_select<SelectMode::Replace>(select_to_next_word<Word>)) } },
|
||||||
{ 'e', { "select to next word end", repeated(make_select<SelectMode::Replace>(select_to_next_word_end<Word>)) } },
|
{ 'e', { "select to next word end", repeated(make_select<SelectMode::Replace>(select_to_next_word_end<Word>)) } },
|
||||||
|
|
|
@ -11,10 +11,16 @@ namespace Kakoune
|
||||||
|
|
||||||
class Context;
|
class Context;
|
||||||
|
|
||||||
|
struct NormalParams
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
char reg;
|
||||||
|
};
|
||||||
|
|
||||||
struct NormalCmdDesc
|
struct NormalCmdDesc
|
||||||
{
|
{
|
||||||
const char* docstring;
|
const char* docstring;
|
||||||
std::function<void (Context& context, int param)> func;
|
std::function<void (Context& context, NormalParams params)> func;
|
||||||
};
|
};
|
||||||
|
|
||||||
using KeyMap = std::unordered_map<Key, NormalCmdDesc>;
|
using KeyMap = std::unordered_map<Key, NormalCmdDesc>;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user