Use register to store prompt history
This commit is contained in:
parent
a9e778fcc7
commit
e613292568
|
@ -1739,10 +1739,10 @@ void context_wrap(const ParametersParser& parser, Context& context, StringView d
|
||||||
|
|
||||||
auto& register_manager = RegisterManager::instance();
|
auto& register_manager = RegisterManager::instance();
|
||||||
auto make_register_restorer = [&](char c) {
|
auto make_register_restorer = [&](char c) {
|
||||||
return on_scope_end([&, c, save=register_manager[c].get(context) | gather<Vector<String>>()] {
|
return on_scope_end([&, c, save=register_manager[c].save(context)] {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RegisterManager::instance()[c].set(context, save);
|
RegisterManager::instance()[c].restore(context, save);
|
||||||
}
|
}
|
||||||
catch (runtime_error& err)
|
catch (runtime_error& err)
|
||||||
{
|
{
|
||||||
|
@ -2001,7 +2001,7 @@ const CommandDesc prompt_cmd = {
|
||||||
CapturedShellContext sc{shell_context};
|
CapturedShellContext sc{shell_context};
|
||||||
context.input_handler().prompt(
|
context.input_handler().prompt(
|
||||||
parser[0], initstr.str(), {}, context.faces()["Prompt"],
|
parser[0], initstr.str(), {}, context.faces()["Prompt"],
|
||||||
flags, std::move(completer),
|
flags, '_', std::move(completer),
|
||||||
[=](StringView str, PromptEvent event, Context& context) mutable
|
[=](StringView str, PromptEvent event, Context& context) mutable
|
||||||
{
|
{
|
||||||
if ((event == PromptEvent::Abort and on_abort.empty()) or
|
if ((event == PromptEvent::Abort and on_abort.empty()) or
|
||||||
|
|
|
@ -239,11 +239,8 @@ void Context::end_edition()
|
||||||
|
|
||||||
StringView Context::main_sel_register_value(StringView reg) const
|
StringView Context::main_sel_register_value(StringView reg) const
|
||||||
{
|
{
|
||||||
auto strings = RegisterManager::instance()[reg].get(*this);
|
|
||||||
size_t index = m_selections ? (*m_selections).main_index() : 0;
|
size_t index = m_selections ? (*m_selections).main_index() : 0;
|
||||||
if (strings.size() <= index)
|
return RegisterManager::instance()[reg].get_main(*this, index);
|
||||||
index = strings.size() - 1;
|
|
||||||
return strings[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -751,11 +751,13 @@ class Prompt : public InputMode
|
||||||
public:
|
public:
|
||||||
Prompt(InputHandler& input_handler, StringView prompt,
|
Prompt(InputHandler& input_handler, StringView prompt,
|
||||||
String initstr, String emptystr, Face face, PromptFlags flags,
|
String initstr, String emptystr, Face face, PromptFlags flags,
|
||||||
PromptCompleter completer, PromptCallback callback)
|
char history_register, PromptCompleter completer, PromptCallback callback)
|
||||||
: InputMode(input_handler), m_callback(std::move(callback)), m_completer(std::move(completer)),
|
: InputMode(input_handler), m_callback(std::move(callback)), m_completer(std::move(completer)),
|
||||||
m_prompt(prompt.str()), m_prompt_face(face),
|
m_prompt(prompt.str()), m_prompt_face(face),
|
||||||
m_empty_text{std::move(emptystr)},
|
m_empty_text{std::move(emptystr)},
|
||||||
m_line_editor{context().faces()}, m_flags(flags),
|
m_line_editor{context().faces()}, m_flags(flags),
|
||||||
|
m_history{RegisterManager::instance()[history_register]},
|
||||||
|
m_current_history{m_history.get(context()).size()},
|
||||||
m_auto_complete{context().options()["autocomplete"].get<AutoComplete>() & AutoComplete::Prompt},
|
m_auto_complete{context().options()["autocomplete"].get<AutoComplete>() & AutoComplete::Prompt},
|
||||||
m_idle_timer{TimePoint::max(), context().flags() & Context::Flags::Draft ?
|
m_idle_timer{TimePoint::max(), context().flags() & Context::Flags::Draft ?
|
||||||
Timer::Callback{} : [this](Timer&) {
|
Timer::Callback{} : [this](Timer&) {
|
||||||
|
@ -769,13 +771,11 @@ public:
|
||||||
context().hooks().run_hook(Hook::PromptIdle, "", context());
|
context().hooks().run_hook(Hook::PromptIdle, "", context());
|
||||||
}}
|
}}
|
||||||
{
|
{
|
||||||
m_history_it = ms_history[m_prompt].end();
|
|
||||||
m_line_editor.reset(std::move(initstr), m_empty_text);
|
m_line_editor.reset(std::move(initstr), m_empty_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_key(Key key) override
|
void on_key(Key key) override
|
||||||
{
|
{
|
||||||
History& history = ms_history[m_prompt];
|
|
||||||
const String& line = m_line_editor.line();
|
const String& line = m_line_editor.line();
|
||||||
|
|
||||||
if (key == Key::Return)
|
if (key == Key::Return)
|
||||||
|
@ -790,7 +790,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not context().history_disabled())
|
if (not context().history_disabled())
|
||||||
history_push(history, line);
|
history_push(line);
|
||||||
context().print_status(DisplayLine{});
|
context().print_status(DisplayLine{});
|
||||||
if (context().has_client())
|
if (context().has_client())
|
||||||
context().client().menu_hide();
|
context().client().menu_hide();
|
||||||
|
@ -807,7 +807,7 @@ public:
|
||||||
else if (key == Key::Escape or key == ctrl('c'))
|
else if (key == Key::Escape or key == ctrl('c'))
|
||||||
{
|
{
|
||||||
if (not context().history_disabled())
|
if (not context().history_disabled())
|
||||||
history_push(history, line);
|
history_push(line);
|
||||||
context().print_status(DisplayLine{});
|
context().print_status(DisplayLine{});
|
||||||
if (context().has_client())
|
if (context().has_client())
|
||||||
context().client().menu_hide();
|
context().client().menu_hide();
|
||||||
|
@ -853,22 +853,25 @@ public:
|
||||||
}
|
}
|
||||||
else if (key == Key::Up or key == ctrl('p'))
|
else if (key == Key::Up or key == ctrl('p'))
|
||||||
{
|
{
|
||||||
if (m_history_it != history.begin())
|
if (m_current_history != 0)
|
||||||
{
|
{
|
||||||
if (m_history_it == history.end())
|
auto history = m_history.get(context());
|
||||||
|
// The history register might have been mutated in the mean time
|
||||||
|
m_current_history = std::min(history.size(), m_current_history);
|
||||||
|
if (m_current_history == history.size())
|
||||||
m_prefix = line;
|
m_prefix = line;
|
||||||
auto it = m_history_it;
|
auto index = m_current_history;
|
||||||
// search for the previous history entry matching typed prefix
|
// search for the previous history entry matching typed prefix
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
--it;
|
--index;
|
||||||
if (prefix_match(*it, m_prefix))
|
if (prefix_match(history[index], m_prefix))
|
||||||
{
|
{
|
||||||
m_history_it = it;
|
m_current_history = index;
|
||||||
m_line_editor.reset(*it, m_empty_text);
|
m_line_editor.reset(history[index], m_empty_text);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (it != history.begin());
|
} while (index != 0);
|
||||||
|
|
||||||
clear_completions();
|
clear_completions();
|
||||||
m_refresh_completion_pending = true;
|
m_refresh_completion_pending = true;
|
||||||
|
@ -876,16 +879,19 @@ public:
|
||||||
}
|
}
|
||||||
else if (key == Key::Down or key == ctrl('n')) // next
|
else if (key == Key::Down or key == ctrl('n')) // next
|
||||||
{
|
{
|
||||||
if (m_history_it != history.end())
|
auto history = m_history.get(context());
|
||||||
|
// The history register might have been mutated in the mean time
|
||||||
|
m_current_history = std::min(history.size(), m_current_history);
|
||||||
|
if (m_current_history < history.size())
|
||||||
{
|
{
|
||||||
// search for the next history entry matching typed prefix
|
// search for the next history entry matching typed prefix
|
||||||
++m_history_it;
|
++m_current_history;
|
||||||
while (m_history_it != history.end() and
|
while (m_current_history != history.size() and
|
||||||
not prefix_match(*m_history_it, m_prefix))
|
not prefix_match(history[m_current_history], m_prefix))
|
||||||
++m_history_it;
|
++m_current_history;
|
||||||
|
|
||||||
if (m_history_it != history.end())
|
if (m_current_history != history.size())
|
||||||
m_line_editor.reset(*m_history_it, m_empty_text);
|
m_line_editor.reset(history[m_current_history], m_empty_text);
|
||||||
else
|
else
|
||||||
m_line_editor.reset(m_prefix, m_empty_text);
|
m_line_editor.reset(m_prefix, m_empty_text);
|
||||||
|
|
||||||
|
@ -1089,27 +1095,22 @@ private:
|
||||||
LineEditor m_line_editor;
|
LineEditor m_line_editor;
|
||||||
bool m_line_changed = false;
|
bool m_line_changed = false;
|
||||||
PromptFlags m_flags;
|
PromptFlags m_flags;
|
||||||
|
Register& m_history;
|
||||||
|
size_t m_current_history;
|
||||||
bool m_auto_complete;
|
bool m_auto_complete;
|
||||||
bool m_refresh_completion_pending = true;
|
bool m_refresh_completion_pending = true;
|
||||||
Timer m_idle_timer;
|
Timer m_idle_timer;
|
||||||
|
|
||||||
using History = Vector<String, MemoryDomain::History>;
|
void history_push(StringView entry)
|
||||||
static HashMap<String, History, MemoryDomain::History> ms_history;
|
|
||||||
History::iterator m_history_it;
|
|
||||||
|
|
||||||
void history_push(History& history, StringView entry)
|
|
||||||
{
|
{
|
||||||
if (entry.empty() or
|
if (entry.empty() or
|
||||||
(m_flags & PromptFlags::DropHistoryEntriesWithBlankPrefix and
|
(m_flags & PromptFlags::DropHistoryEntriesWithBlankPrefix and
|
||||||
is_horizontal_blank(entry[0_byte])))
|
is_horizontal_blank(entry[0_byte])))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
history.erase(std::remove(history.begin(), history.end(), entry),
|
m_history.set(context(), {entry.str()});
|
||||||
history.end());
|
|
||||||
history.push_back(entry.str());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
HashMap<String, Prompt::History, MemoryDomain::History> Prompt::ms_history;
|
|
||||||
|
|
||||||
class NextKey : public InputMode
|
class NextKey : public InputMode
|
||||||
{
|
{
|
||||||
|
@ -1592,11 +1593,12 @@ void InputHandler::repeat_last_insert()
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputHandler::prompt(StringView prompt, String initstr, String emptystr,
|
void InputHandler::prompt(StringView prompt, String initstr, String emptystr,
|
||||||
Face prompt_face, PromptFlags flags,
|
Face prompt_face, PromptFlags flags, char history_register,
|
||||||
PromptCompleter completer, PromptCallback callback)
|
PromptCompleter completer, PromptCallback callback)
|
||||||
{
|
{
|
||||||
push_mode(new InputModes::Prompt(*this, prompt, std::move(initstr), std::move(emptystr),
|
push_mode(new InputModes::Prompt(*this, prompt, std::move(initstr), std::move(emptystr),
|
||||||
prompt_face, flags, std::move(completer), std::move(callback)));
|
prompt_face, flags, history_register,
|
||||||
|
std::move(completer), std::move(callback)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputHandler::set_prompt_face(Face prompt_face)
|
void InputHandler::set_prompt_face(Face prompt_face)
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
// returns to normal mode after validation if callback does
|
// returns to normal mode after validation if callback does
|
||||||
// not change the mode itself
|
// not change the mode itself
|
||||||
void prompt(StringView prompt, String initstr, String emptystr,
|
void prompt(StringView prompt, String initstr, String emptystr,
|
||||||
Face prompt_face, PromptFlags flags,
|
Face prompt_face, PromptFlags flags, char history_register,
|
||||||
PromptCompleter completer, PromptCallback callback);
|
PromptCompleter completer, PromptCallback callback);
|
||||||
void set_prompt_face(Face prompt_face);
|
void set_prompt_face(Face prompt_face);
|
||||||
|
|
||||||
|
|
|
@ -280,9 +280,12 @@ void register_registers()
|
||||||
{
|
{
|
||||||
RegisterManager& register_manager = RegisterManager::instance();
|
RegisterManager& register_manager = RegisterManager::instance();
|
||||||
|
|
||||||
for (auto c : "abcdefghijklmnopqrstuvwxyz/\"|^@:")
|
for (auto c : StringView{"abcdefghijklmnopqrstuvwxyz\"^@"})
|
||||||
register_manager.add_register(c, std::make_unique<StaticRegister>());
|
register_manager.add_register(c, std::make_unique<StaticRegister>());
|
||||||
|
|
||||||
|
for (auto c : StringView{"/|:\\"})
|
||||||
|
register_manager.add_register(c, std::make_unique<HistoryRegister>());
|
||||||
|
|
||||||
using StringList = Vector<String, MemoryDomain::Registers>;
|
using StringList = Vector<String, MemoryDomain::Registers>;
|
||||||
|
|
||||||
register_manager.add_register('%', make_dyn_reg(
|
register_manager.add_register('%', make_dyn_reg(
|
||||||
|
|
|
@ -456,6 +456,7 @@ void command(Context& context, EnvVarMap env_vars)
|
||||||
context.input_handler().prompt(
|
context.input_handler().prompt(
|
||||||
":", {}, context.main_sel_register_value(':').str(),
|
":", {}, context.main_sel_register_value(':').str(),
|
||||||
context.faces()["Prompt"], PromptFlags::DropHistoryEntriesWithBlankPrefix,
|
context.faces()["Prompt"], PromptFlags::DropHistoryEntriesWithBlankPrefix,
|
||||||
|
':',
|
||||||
[](const Context& context, CompletionFlags flags,
|
[](const Context& context, CompletionFlags flags,
|
||||||
StringView cmd_line, ByteCount pos) {
|
StringView cmd_line, ByteCount pos) {
|
||||||
return CommandManager::instance().complete(context, flags, cmd_line, pos);
|
return CommandManager::instance().complete(context, flags, cmd_line, pos);
|
||||||
|
@ -544,7 +545,7 @@ void pipe(Context& context, NormalParams)
|
||||||
const char* prompt = replace ? "pipe:" : "pipe-to:";
|
const char* prompt = replace ? "pipe:" : "pipe-to:";
|
||||||
context.input_handler().prompt(
|
context.input_handler().prompt(
|
||||||
prompt, {}, context.main_sel_register_value("|").str(), context.faces()["Prompt"],
|
prompt, {}, context.main_sel_register_value("|").str(), context.faces()["Prompt"],
|
||||||
PromptFlags::DropHistoryEntriesWithBlankPrefix,
|
PromptFlags::DropHistoryEntriesWithBlankPrefix, '|',
|
||||||
shell_complete,
|
shell_complete,
|
||||||
[](StringView cmdline, PromptEvent event, Context& context)
|
[](StringView cmdline, PromptEvent event, Context& context)
|
||||||
{
|
{
|
||||||
|
@ -625,7 +626,7 @@ void insert_output(Context& context, NormalParams)
|
||||||
const char* prompt = mode == InsertMode::Insert ? "insert-output:" : "append-output:";
|
const char* prompt = mode == InsertMode::Insert ? "insert-output:" : "append-output:";
|
||||||
context.input_handler().prompt(
|
context.input_handler().prompt(
|
||||||
prompt, {}, context.main_sel_register_value("|").str(), context.faces()["Prompt"],
|
prompt, {}, context.main_sel_register_value("|").str(), context.faces()["Prompt"],
|
||||||
PromptFlags::DropHistoryEntriesWithBlankPrefix,
|
PromptFlags::DropHistoryEntriesWithBlankPrefix, '|',
|
||||||
shell_complete,
|
shell_complete,
|
||||||
[](StringView cmdline, PromptEvent event, Context& context)
|
[](StringView cmdline, PromptEvent event, Context& context)
|
||||||
{
|
{
|
||||||
|
@ -753,14 +754,15 @@ constexpr RegexCompileFlags direction_flags(RegexMode mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<RegexMode mode = RegexMode::Forward, typename T>
|
template<RegexMode mode = RegexMode::Forward, typename T>
|
||||||
void regex_prompt(Context& context, String prompt, String default_regex, T func)
|
void regex_prompt(Context& context, String prompt, char reg, T func)
|
||||||
{
|
{
|
||||||
static_assert(is_direction(mode));
|
static_assert(is_direction(mode));
|
||||||
DisplayCoord position = context.has_window() ? context.window().position() : DisplayCoord{};
|
DisplayCoord position = context.has_window() ? context.window().position() : DisplayCoord{};
|
||||||
SelectionList selections = context.selections();
|
SelectionList selections = context.selections();
|
||||||
|
auto default_regex = RegisterManager::instance()[reg].get_main(context, context.selections().main_index());
|
||||||
context.input_handler().prompt(
|
context.input_handler().prompt(
|
||||||
std::move(prompt), {}, default_regex, context.faces()["Prompt"],
|
std::move(prompt), {}, default_regex, context.faces()["Prompt"],
|
||||||
PromptFlags::Search,
|
PromptFlags::Search, reg,
|
||||||
[](const Context& context, CompletionFlags, StringView regex, ByteCount pos) -> Completions {
|
[](const Context& context, CompletionFlags, StringView regex, ByteCount pos) -> Completions {
|
||||||
auto current_word = [](StringView s) {
|
auto current_word = [](StringView s) {
|
||||||
auto it = s.end();
|
auto it = s.end();
|
||||||
|
@ -785,7 +787,7 @@ void regex_prompt(Context& context, String prompt, String default_regex, T func)
|
||||||
[&](auto&& m) { candidates.push_back(m.candidate().str()); return true; });
|
[&](auto&& m) { candidates.push_back(m.candidate().str()); return true; });
|
||||||
return {(int)(word.begin() - regex.begin()), pos, std::move(candidates) };
|
return {(int)(word.begin() - regex.begin()), pos, std::move(candidates) };
|
||||||
},
|
},
|
||||||
[=](StringView str, PromptEvent event, Context& context) mutable {
|
[=, func=T(std::move(func))](StringView str, PromptEvent event, Context& context) mutable {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (event != PromptEvent::Change and context.has_client())
|
if (event != PromptEvent::Change and context.has_client())
|
||||||
|
@ -879,16 +881,12 @@ void search(Context& context, NormalParams params)
|
||||||
const char reg = to_lower(params.reg ? params.reg : '/');
|
const char reg = to_lower(params.reg ? params.reg : '/');
|
||||||
const int count = params.count;
|
const int count = params.count;
|
||||||
|
|
||||||
auto reg_content = RegisterManager::instance()[reg].get(context);
|
regex_prompt<regex_mode>(context, prompt.str(), reg,
|
||||||
Vector<String> saved_reg{reg_content.begin(), reg_content.end()};
|
[reg, count, saved_reg = RegisterManager::instance()[reg].save(context)]
|
||||||
const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1);
|
|
||||||
|
|
||||||
regex_prompt<regex_mode>(context, prompt.str(), saved_reg[main_index],
|
|
||||||
[reg, count, saved_reg]
|
|
||||||
(const Regex& regex, PromptEvent event, Context& context) {
|
(const Regex& regex, PromptEvent event, Context& context) {
|
||||||
if (event == PromptEvent::Abort)
|
if (event == PromptEvent::Abort)
|
||||||
{
|
{
|
||||||
RegisterManager::instance()[reg].set(context, saved_reg);
|
RegisterManager::instance()[reg].restore(context, saved_reg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RegisterManager::instance()[reg].set(context, regex.str());
|
RegisterManager::instance()[reg].set(context, regex.str());
|
||||||
|
@ -907,7 +905,7 @@ template<SelectMode mode, RegexMode regex_mode>
|
||||||
void search_next(Context& context, NormalParams params)
|
void search_next(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
const char reg = to_lower(params.reg ? params.reg : '/');
|
const char reg = to_lower(params.reg ? params.reg : '/');
|
||||||
StringView str = context.main_sel_register_value(reg);
|
StringView str = RegisterManager::instance()[reg].get(context).back();
|
||||||
if (not str.empty())
|
if (not str.empty())
|
||||||
{
|
{
|
||||||
Regex regex{str, direction_flags(regex_mode)};
|
Regex regex{str, direction_flags(regex_mode)};
|
||||||
|
@ -942,25 +940,21 @@ void search_next(Context& context, NormalParams params)
|
||||||
template<bool smart>
|
template<bool smart>
|
||||||
void use_selection_as_search_pattern(Context& context, NormalParams params)
|
void use_selection_as_search_pattern(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
Vector<String> patterns;
|
|
||||||
auto& sels = context.selections();
|
|
||||||
const auto& buffer = context.buffer();
|
const auto& buffer = context.buffer();
|
||||||
for (auto& sel : sels)
|
auto& sel = context.selections().main();
|
||||||
{
|
|
||||||
const auto beg = sel.min(), end = buffer.char_next(sel.max());
|
const auto beg = sel.min(), end = buffer.char_next(sel.max());
|
||||||
patterns.push_back(format("{}{}{}",
|
String pattern = format("{}{}{}",
|
||||||
smart and is_bow(buffer, beg) ? "\\b" : "",
|
smart and is_bow(buffer, beg) ? "\\b" : "",
|
||||||
escape(buffer.string(beg, end), "^$\\.*+?()[]{}|", '\\'),
|
escape(buffer.string(beg, end), "^$\\.*+?()[]{}|", '\\'),
|
||||||
smart and is_eow(buffer, end) ? "\\b" : ""));
|
smart and is_eow(buffer, end) ? "\\b" : "");
|
||||||
}
|
|
||||||
|
|
||||||
const char reg = to_lower(params.reg ? params.reg : '/');
|
const char reg = to_lower(params.reg ? params.reg : '/');
|
||||||
|
|
||||||
context.print_status({
|
context.print_status({
|
||||||
format("register '{}' set to '{}'", reg, fix_atom_text(patterns[sels.main_index()])),
|
format("register '{}' set to '{}'", reg, fix_atom_text(pattern)),
|
||||||
context.faces()["Information"] });
|
context.faces()["Information"] });
|
||||||
|
|
||||||
RegisterManager::instance()[reg].set(context, patterns);
|
RegisterManager::instance()[reg].set(context, {pattern});
|
||||||
|
|
||||||
// Hack, as Window do not take register state into account
|
// Hack, as Window do not take register state into account
|
||||||
if (context.has_window())
|
if (context.has_window())
|
||||||
|
@ -973,15 +967,12 @@ void select_regex(Context& context, NormalParams params)
|
||||||
const int capture = params.count;
|
const int capture = params.count;
|
||||||
auto prompt = capture ? format("select (capture {}):", capture) : "select:"_str;
|
auto prompt = capture ? format("select (capture {}):", capture) : "select:"_str;
|
||||||
|
|
||||||
auto reg_content = RegisterManager::instance()[reg].get(context);
|
regex_prompt(context, std::move(prompt), reg,
|
||||||
Vector<String> saved_reg{reg_content.begin(), reg_content.end()};
|
[reg, capture, saved_reg = RegisterManager::instance()[reg].save(context)]
|
||||||
const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1);
|
(Regex ex, PromptEvent event, Context& context) {
|
||||||
|
|
||||||
regex_prompt(context, std::move(prompt), saved_reg[main_index],
|
|
||||||
[reg, capture, saved_reg](Regex ex, PromptEvent event, Context& context) {
|
|
||||||
if (event == PromptEvent::Abort)
|
if (event == PromptEvent::Abort)
|
||||||
{
|
{
|
||||||
RegisterManager::instance()[reg].set(context, saved_reg);
|
RegisterManager::instance()[reg].restore(context, saved_reg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1000,15 +991,12 @@ void split_regex(Context& context, NormalParams params)
|
||||||
const int capture = params.count;
|
const int capture = params.count;
|
||||||
auto prompt = capture ? format("split (on capture {}):", (int)capture) : "split:"_str;
|
auto prompt = capture ? format("split (on capture {}):", (int)capture) : "split:"_str;
|
||||||
|
|
||||||
auto reg_content = RegisterManager::instance()[reg].get(context);
|
regex_prompt(context, std::move(prompt), reg,
|
||||||
Vector<String> saved_reg{reg_content.begin(), reg_content.end()};
|
[reg, capture, saved_reg = RegisterManager::instance()[reg].save(context)]
|
||||||
const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1);
|
(Regex ex, PromptEvent event, Context& context) {
|
||||||
|
|
||||||
regex_prompt(context, std::move(prompt), saved_reg[main_index],
|
|
||||||
[reg, capture, saved_reg](Regex ex, PromptEvent event, Context& context) {
|
|
||||||
if (event == PromptEvent::Abort)
|
if (event == PromptEvent::Abort)
|
||||||
{
|
{
|
||||||
RegisterManager::instance()[reg].set(context, saved_reg);
|
RegisterManager::instance()[reg].restore(context, saved_reg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1102,16 +1090,13 @@ void keep(Context& context, NormalParams params)
|
||||||
constexpr StringView prompt = matching ? "keep matching:" : "keep not matching:";
|
constexpr StringView prompt = matching ? "keep matching:" : "keep not matching:";
|
||||||
|
|
||||||
const char reg = to_lower(params.reg ? params.reg : '/');
|
const char reg = to_lower(params.reg ? params.reg : '/');
|
||||||
auto saved_reg = RegisterManager::instance()[reg].get(context) | gather<Vector<String>>();
|
|
||||||
const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1);
|
|
||||||
|
|
||||||
regex_prompt(context, prompt.str(), saved_reg[main_index],
|
regex_prompt(context, prompt.str(), reg,
|
||||||
[saved_reg, reg]
|
[reg, saved_reg = RegisterManager::instance()[reg].save(context)]
|
||||||
(const Regex& regex, PromptEvent event, Context& context) {
|
(const Regex& regex, PromptEvent event, Context& context) {
|
||||||
|
|
||||||
if (event == PromptEvent::Abort)
|
if (event == PromptEvent::Abort)
|
||||||
{
|
{
|
||||||
RegisterManager::instance()[reg].set(context, saved_reg);
|
RegisterManager::instance()[reg].restore(context, saved_reg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (not context.history_disabled())
|
if (not context.history_disabled())
|
||||||
|
@ -1144,7 +1129,7 @@ void keep_pipe(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
context.input_handler().prompt(
|
context.input_handler().prompt(
|
||||||
"keep pipe:", {}, {}, context.faces()["Prompt"],
|
"keep pipe:", {}, {}, context.faces()["Prompt"],
|
||||||
PromptFlags::DropHistoryEntriesWithBlankPrefix, shell_complete,
|
PromptFlags::DropHistoryEntriesWithBlankPrefix, '|', shell_complete,
|
||||||
[](StringView cmdline, PromptEvent event, Context& context) {
|
[](StringView cmdline, PromptEvent event, Context& context) {
|
||||||
if (event != PromptEvent::Validate)
|
if (event != PromptEvent::Validate)
|
||||||
return;
|
return;
|
||||||
|
@ -1301,7 +1286,7 @@ void select_object(Context& context, NormalParams params)
|
||||||
|
|
||||||
context.input_handler().prompt(
|
context.input_handler().prompt(
|
||||||
"object desc:", {}, {}, context.faces()["Prompt"],
|
"object desc:", {}, {}, context.faces()["Prompt"],
|
||||||
PromptFlags::None, complete_nothing,
|
PromptFlags::None, '_', complete_nothing,
|
||||||
[count,info](StringView cmdline, PromptEvent event, Context& context) {
|
[count,info](StringView cmdline, PromptEvent event, Context& context) {
|
||||||
if (event != PromptEvent::Change)
|
if (event != PromptEvent::Change)
|
||||||
hide_auto_info_ifn(context, info);
|
hide_auto_info_ifn(context, info);
|
||||||
|
|
|
@ -20,6 +20,15 @@ public:
|
||||||
|
|
||||||
virtual void set(Context& context, ConstArrayView<String> values) = 0;
|
virtual void set(Context& context, ConstArrayView<String> values) = 0;
|
||||||
virtual ConstArrayView<String> get(const Context& context) = 0;
|
virtual ConstArrayView<String> get(const Context& context) = 0;
|
||||||
|
virtual const String& get_main(const Context& context, size_t main_index) = 0;
|
||||||
|
|
||||||
|
struct RestoreInfo
|
||||||
|
{
|
||||||
|
std::vector<String> data;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
virtual RestoreInfo save(const Context&) = 0;
|
||||||
|
virtual void restore(Context&, const RestoreInfo&) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// static value register, which can be modified
|
// static value register, which can be modified
|
||||||
|
@ -39,6 +48,25 @@ public:
|
||||||
else
|
else
|
||||||
return ConstArrayView<String>(m_content);
|
return ConstArrayView<String>(m_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const String& get_main(const Context& context, size_t main_index) override
|
||||||
|
{
|
||||||
|
return get(context)[std::min(main_index, m_content.size() - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
RestoreInfo save(const Context& context) override
|
||||||
|
{
|
||||||
|
//std::unique_ptr<String[]> data{new String[m_content.size()]};
|
||||||
|
//std::copy_n(m_content.data(), m_content.size(), data.get());
|
||||||
|
auto content = get(context);
|
||||||
|
std::vector<String> data{content.begin(), content.end()};
|
||||||
|
return {std::move(data), content.size()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore(Context&, const RestoreInfo& info) override
|
||||||
|
{
|
||||||
|
m_content.assign(info.data.begin(), info.data.begin() + info.size);
|
||||||
|
}
|
||||||
protected:
|
protected:
|
||||||
Vector<String, MemoryDomain::Registers> m_content;
|
Vector<String, MemoryDomain::Registers> m_content;
|
||||||
};
|
};
|
||||||
|
@ -63,11 +91,47 @@ public:
|
||||||
return StaticRegister::get(context);
|
return StaticRegister::get(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void restore(Context& context, const RestoreInfo& info) override
|
||||||
|
{
|
||||||
|
set(context, info.data);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Getter m_getter;
|
Getter m_getter;
|
||||||
Setter m_setter;
|
Setter m_setter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Register that is used to store some kind prompt history
|
||||||
|
class HistoryRegister : public StaticRegister
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void set(Context&, ConstArrayView<String> values) override
|
||||||
|
{
|
||||||
|
for (auto& entry : values)
|
||||||
|
{
|
||||||
|
m_content.erase(std::remove(m_content.begin(), m_content.end(), entry),
|
||||||
|
m_content.end());
|
||||||
|
m_content.push_back(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const String& get_main(const Context&, size_t) override
|
||||||
|
{
|
||||||
|
return m_content.empty() ? String::ms_empty : m_content.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
RestoreInfo save(const Context&) override
|
||||||
|
{
|
||||||
|
return {{}, m_content.size()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore(Context&, const RestoreInfo& info) override
|
||||||
|
{
|
||||||
|
if (info.size < m_content.size())
|
||||||
|
m_content.resize(info.size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
std::unique_ptr<Register> make_dyn_reg(Func func)
|
std::unique_ptr<Register> make_dyn_reg(Func func)
|
||||||
{
|
{
|
||||||
|
@ -93,6 +157,14 @@ public:
|
||||||
{
|
{
|
||||||
return ConstArrayView<String>(String::ms_empty);
|
return ConstArrayView<String>(String::ms_empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const String& get_main(const Context&, size_t) override
|
||||||
|
{
|
||||||
|
return String::ms_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
RestoreInfo save(const Context&) override { return {}; }
|
||||||
|
void restore(Context&, const RestoreInfo& info) override {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class RegisterManager : public Singleton<RegisterManager>
|
class RegisterManager : public Singleton<RegisterManager>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user