Use the "<reg> syntax along with a default register for marks and macros
Marks use the '^' register by default, macros the '@' register.
This commit is contained in:
parent
baf0203b9d
commit
7ee027b125
122
src/normal.cc
122
src/normal.cc
|
@ -1049,17 +1049,17 @@ static bool is_basic_alpha(Codepoint c)
|
||||||
return (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z');
|
return (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z');
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_or_end_macro_recording(Context& context, NormalParams)
|
void start_or_end_macro_recording(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
if (context.input_handler().is_recording())
|
if (context.input_handler().is_recording())
|
||||||
context.input_handler().stop_recording();
|
context.input_handler().stop_recording();
|
||||||
else
|
else
|
||||||
on_next_key_with_autoinfo(context, KeymapMode::None,
|
{
|
||||||
[](Key key, Context& context) {
|
const char reg = tolower(params.reg ? params.reg : '@');
|
||||||
auto cp = key.codepoint();
|
if (not is_basic_alpha(reg) and reg != '@')
|
||||||
if (cp and is_basic_alpha(*cp))
|
throw runtime_error("Macros can only use the '@' and alphabetic registers");
|
||||||
context.input_handler().start_recording(tolower(*cp));
|
context.input_handler().start_recording(reg);
|
||||||
}, "record macro", "enter macro name ");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void end_macro_recording(Context& context, NormalParams)
|
void end_macro_recording(Context& context, NormalParams)
|
||||||
|
@ -1070,29 +1070,25 @@ void end_macro_recording(Context& context, NormalParams)
|
||||||
|
|
||||||
void replay_macro(Context& context, NormalParams params)
|
void replay_macro(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
on_next_key_with_autoinfo(context, KeymapMode::None,
|
const char reg = tolower(params.reg ? params.reg : '@');
|
||||||
[params](Key key, Context& context) mutable {
|
if (not is_basic_alpha(reg) and reg != '@')
|
||||||
auto cp = key.codepoint();
|
throw runtime_error("Macros can only use the '@' and alphabetic registers");
|
||||||
if (cp and is_basic_alpha(*cp))
|
|
||||||
{
|
|
||||||
static bool running_macros[26] = {};
|
|
||||||
const char name = tolower(*cp);
|
|
||||||
const size_t idx = (size_t)(name - 'a');
|
|
||||||
if (running_macros[idx])
|
|
||||||
throw runtime_error("recursive macros call detected");
|
|
||||||
|
|
||||||
ConstArrayView<String> reg_val = RegisterManager::instance()[name].values(context);
|
static bool running_macros[27] = {};
|
||||||
if (not reg_val.empty())
|
const size_t idx = reg != '@' ? (size_t)(reg - 'a') : 26;
|
||||||
{
|
if (running_macros[idx])
|
||||||
running_macros[idx] = true;
|
throw runtime_error("recursive macros call detected");
|
||||||
auto stop = on_scope_end([&]{ running_macros[idx] = false; });
|
|
||||||
|
|
||||||
auto keys = parse_keys(reg_val[0]);
|
ConstArrayView<String> reg_val = RegisterManager::instance()[reg].values(context);
|
||||||
ScopedEdition edition(context);
|
if (not reg_val.empty())
|
||||||
do { exec_keys(keys, context); } while (--params.count > 0);
|
{
|
||||||
}
|
running_macros[idx] = true;
|
||||||
}
|
auto stop = on_scope_end([&]{ running_macros[idx] = false; });
|
||||||
}, "replay macro", "enter macro name");
|
|
||||||
|
auto keys = parse_keys(reg_val[0]);
|
||||||
|
ScopedEdition edition(context);
|
||||||
|
do { exec_keys(keys, context); } while (--params.count > 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Direction direction>
|
template<Direction direction>
|
||||||
|
@ -1264,61 +1260,55 @@ void spaces_to_tabs(Context& context, NormalParams params)
|
||||||
SelectionList{ buffer, std::move(spaces) }.insert("\t"_str, InsertMode::Replace);
|
SelectionList{ buffer, std::move(spaces) }.insert("\t"_str, InsertMode::Replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_selections(Context& context, NormalParams)
|
void save_selections(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
on_next_key_with_autoinfo(context, KeymapMode::None,
|
const char reg = tolower(params.reg ? params.reg : '^');
|
||||||
[](Key key, Context& context) {
|
if (not is_basic_alpha(reg) and reg != '^')
|
||||||
auto cp = key.codepoint();
|
throw runtime_error("selections can only be saved to the '^' and alphabetic registers");
|
||||||
if (not cp or not is_basic_alpha(*cp))
|
|
||||||
return;
|
|
||||||
|
|
||||||
String desc = format("{}@{}%{}",
|
String desc = format("{}@{}%{}",
|
||||||
selection_list_to_string(context.selections()),
|
selection_list_to_string(context.selections()),
|
||||||
context.buffer().name(),
|
context.buffer().name(),
|
||||||
context.buffer().timestamp());
|
context.buffer().timestamp());
|
||||||
|
|
||||||
RegisterManager::instance()[*cp] = desc;
|
RegisterManager::instance()[reg] = desc;
|
||||||
|
|
||||||
context.print_status({format("Saved selections in register '{}'", *cp), get_face("Information")});
|
context.print_status({format("Saved selections in register '{}'", reg), get_face("Information")});
|
||||||
}, "Save selections", "Enter register to save selections into");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore_selections(Context& context, NormalParams)
|
void restore_selections(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
on_next_key_with_autoinfo(context, KeymapMode::None,
|
const char reg = tolower(params.reg ? params.reg : '^');
|
||||||
[](Key key, Context& context) {
|
if (not is_basic_alpha(reg) and reg != '^')
|
||||||
auto cp = key.codepoint();
|
throw runtime_error("selections can only be saved to the '^' and alphabetic registers");
|
||||||
if (not cp or not is_basic_alpha(*cp))
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto content = RegisterManager::instance()[*cp].values(context);
|
auto content = RegisterManager::instance()[reg].values(context);
|
||||||
|
|
||||||
if (content.size() != 1)
|
if (content.size() != 1)
|
||||||
throw runtime_error(format("Register {} does not contain a selections desc", *cp));
|
throw runtime_error(format("Register {} does not contain a selections desc", reg));
|
||||||
|
|
||||||
StringView desc = content[0];
|
StringView desc = content[0];
|
||||||
auto arobase = find(desc, '@');
|
auto arobase = find(desc, '@');
|
||||||
auto percent = find(desc, '%');
|
auto percent = find(desc, '%');
|
||||||
|
|
||||||
if (arobase == desc.end() or percent == desc.end())
|
if (arobase == desc.end() or percent == desc.end())
|
||||||
throw runtime_error(format("Register {} does not contain a selections desc", *cp));
|
throw runtime_error(format("Register {} does not contain a selections desc", reg));
|
||||||
|
|
||||||
Buffer& buffer = BufferManager::instance().get_buffer({arobase+1, percent});
|
Buffer& buffer = BufferManager::instance().get_buffer({arobase+1, percent});
|
||||||
size_t timestamp = str_to_int({percent + 1, desc.end()});
|
size_t timestamp = str_to_int({percent + 1, desc.end()});
|
||||||
|
|
||||||
Vector<Selection> sels;
|
Vector<Selection> sels;
|
||||||
for (auto sel_desc : split({desc.begin(), arobase}, ':'))
|
for (auto sel_desc : split({desc.begin(), arobase}, ':'))
|
||||||
sels.push_back(selection_from_string(sel_desc));
|
sels.push_back(selection_from_string(sel_desc));
|
||||||
|
|
||||||
SelectionList sel_list{buffer, std::move(sels), timestamp};
|
SelectionList sel_list{buffer, std::move(sels), timestamp};
|
||||||
|
|
||||||
if (&buffer != &context.buffer())
|
if (&buffer != &context.buffer())
|
||||||
context.change_buffer(buffer);
|
context.change_buffer(buffer);
|
||||||
|
|
||||||
context.selections_write_only() = std::move(sel_list);
|
context.selections_write_only() = std::move(sel_list);
|
||||||
|
|
||||||
context.print_status({format("Restored selections from register '{}'", *cp), get_face("Information")});
|
context.print_status({format("Restored selections from register '{}'", reg), get_face("Information")});
|
||||||
}, "Restore selections", "Enter register to restore selections from");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void undo(Context& context, NormalParams)
|
void undo(Context& context, NormalParams)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user