summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commands.cc6
-rw-r--r--src/context.cc5
-rw-r--r--src/input_handler.cc64
-rw-r--r--src/input_handler.hh2
-rw-r--r--src/main.cc5
-rw-r--r--src/normal.cc79
-rw-r--r--src/register_manager.hh72
7 files changed, 146 insertions, 87 deletions
diff --git a/src/commands.cc b/src/commands.cc
index 75ccecc2..0a4ec97d 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -1739,10 +1739,10 @@ void context_wrap(const ParametersParser& parser, Context& context, StringView d
auto& register_manager = RegisterManager::instance();
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
{
- RegisterManager::instance()[c].set(context, save);
+ RegisterManager::instance()[c].restore(context, save);
}
catch (runtime_error& err)
{
@@ -2001,7 +2001,7 @@ const CommandDesc prompt_cmd = {
CapturedShellContext sc{shell_context};
context.input_handler().prompt(
parser[0], initstr.str(), {}, context.faces()["Prompt"],
- flags, std::move(completer),
+ flags, '_', std::move(completer),
[=](StringView str, PromptEvent event, Context& context) mutable
{
if ((event == PromptEvent::Abort and on_abort.empty()) or
diff --git a/src/context.cc b/src/context.cc
index 08a0b544..d969ffd0 100644
--- a/src/context.cc
+++ b/src/context.cc
@@ -239,11 +239,8 @@ void Context::end_edition()
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;
- if (strings.size() <= index)
- index = strings.size() - 1;
- return strings[index];
+ return RegisterManager::instance()[reg].get_main(*this, index);
}
}
diff --git a/src/input_handler.cc b/src/input_handler.cc
index 750ec1d4..5bda3324 100644
--- a/src/input_handler.cc
+++ b/src/input_handler.cc
@@ -751,11 +751,13 @@ class Prompt : public InputMode
public:
Prompt(InputHandler& input_handler, StringView prompt,
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)),
m_prompt(prompt.str()), m_prompt_face(face),
m_empty_text{std::move(emptystr)},
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_idle_timer{TimePoint::max(), context().flags() & Context::Flags::Draft ?
Timer::Callback{} : [this](Timer&) {
@@ -769,13 +771,11 @@ public:
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);
}
void on_key(Key key) override
{
- History& history = ms_history[m_prompt];
const String& line = m_line_editor.line();
if (key == Key::Return)
@@ -790,7 +790,7 @@ public:
}
if (not context().history_disabled())
- history_push(history, line);
+ history_push(line);
context().print_status(DisplayLine{});
if (context().has_client())
context().client().menu_hide();
@@ -807,7 +807,7 @@ public:
else if (key == Key::Escape or key == ctrl('c'))
{
if (not context().history_disabled())
- history_push(history, line);
+ history_push(line);
context().print_status(DisplayLine{});
if (context().has_client())
context().client().menu_hide();
@@ -853,22 +853,25 @@ public:
}
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;
- auto it = m_history_it;
+ auto index = m_current_history;
// search for the previous history entry matching typed prefix
do
{
- --it;
- if (prefix_match(*it, m_prefix))
+ --index;
+ if (prefix_match(history[index], m_prefix))
{
- m_history_it = it;
- m_line_editor.reset(*it, m_empty_text);
+ m_current_history = index;
+ m_line_editor.reset(history[index], m_empty_text);
break;
}
- } while (it != history.begin());
+ } while (index != 0);
clear_completions();
m_refresh_completion_pending = true;
@@ -876,16 +879,19 @@ public:
}
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
- ++m_history_it;
- while (m_history_it != history.end() and
- not prefix_match(*m_history_it, m_prefix))
- ++m_history_it;
+ ++m_current_history;
+ while (m_current_history != history.size() and
+ not prefix_match(history[m_current_history], m_prefix))
+ ++m_current_history;
- if (m_history_it != history.end())
- m_line_editor.reset(*m_history_it, m_empty_text);
+ if (m_current_history != history.size())
+ m_line_editor.reset(history[m_current_history], m_empty_text);
else
m_line_editor.reset(m_prefix, m_empty_text);
@@ -1089,27 +1095,22 @@ private:
LineEditor m_line_editor;
bool m_line_changed = false;
PromptFlags m_flags;
+ Register& m_history;
+ size_t m_current_history;
bool m_auto_complete;
bool m_refresh_completion_pending = true;
Timer m_idle_timer;
- using History = Vector<String, MemoryDomain::History>;
- static HashMap<String, History, MemoryDomain::History> ms_history;
- History::iterator m_history_it;
-
- void history_push(History& history, StringView entry)
+ void history_push(StringView entry)
{
if (entry.empty() or
(m_flags & PromptFlags::DropHistoryEntriesWithBlankPrefix and
is_horizontal_blank(entry[0_byte])))
return;
- history.erase(std::remove(history.begin(), history.end(), entry),
- history.end());
- history.push_back(entry.str());
+ m_history.set(context(), {entry.str()});
}
};
-HashMap<String, Prompt::History, MemoryDomain::History> Prompt::ms_history;
class NextKey : public InputMode
{
@@ -1592,11 +1593,12 @@ void InputHandler::repeat_last_insert()
}
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)
{
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)
diff --git a/src/input_handler.hh b/src/input_handler.hh
index 0dc98b70..e9528a07 100644
--- a/src/input_handler.hh
+++ b/src/input_handler.hh
@@ -68,7 +68,7 @@ public:
// returns to normal mode after validation if callback does
// not change the mode itself
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);
void set_prompt_face(Face prompt_face);
diff --git a/src/main.cc b/src/main.cc
index b4622aea..53df2492 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -280,9 +280,12 @@ void register_registers()
{
RegisterManager& register_manager = RegisterManager::instance();
- for (auto c : "abcdefghijklmnopqrstuvwxyz/\"|^@:")
+ for (auto c : StringView{"abcdefghijklmnopqrstuvwxyz\"^@"})
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>;
register_manager.add_register('%', make_dyn_reg(
diff --git a/src/normal.cc b/src/normal.cc
index 2fb66e49..51308e7c 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -456,6 +456,7 @@ void command(Context& context, EnvVarMap env_vars)
context.input_handler().prompt(
":", {}, context.main_sel_register_value(':').str(),
context.faces()["Prompt"], PromptFlags::DropHistoryEntriesWithBlankPrefix,
+ ':',
[](const Context& context, CompletionFlags flags,
StringView cmd_line, ByteCount 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:";
context.input_handler().prompt(
prompt, {}, context.main_sel_register_value("|").str(), context.faces()["Prompt"],
- PromptFlags::DropHistoryEntriesWithBlankPrefix,
+ PromptFlags::DropHistoryEntriesWithBlankPrefix, '|',
shell_complete,
[](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:";
context.input_handler().prompt(
prompt, {}, context.main_sel_register_value("|").str(), context.faces()["Prompt"],
- PromptFlags::DropHistoryEntriesWithBlankPrefix,
+ PromptFlags::DropHistoryEntriesWithBlankPrefix, '|',
shell_complete,
[](StringView cmdline, PromptEvent event, Context& context)
{
@@ -753,14 +754,15 @@ constexpr RegexCompileFlags direction_flags(RegexMode mode)
}
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));
DisplayCoord position = context.has_window() ? context.window().position() : DisplayCoord{};
SelectionList selections = context.selections();
+ auto default_regex = RegisterManager::instance()[reg].get_main(context, context.selections().main_index());
context.input_handler().prompt(
std::move(prompt), {}, default_regex, context.faces()["Prompt"],
- PromptFlags::Search,
+ PromptFlags::Search, reg,
[](const Context& context, CompletionFlags, StringView regex, ByteCount pos) -> Completions {
auto current_word = [](StringView s) {
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; });
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
{
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 int count = params.count;
- auto reg_content = RegisterManager::instance()[reg].get(context);
- Vector<String> saved_reg{reg_content.begin(), reg_content.end()};
- 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]
+ regex_prompt<regex_mode>(context, prompt.str(), reg,
+ [reg, count, saved_reg = RegisterManager::instance()[reg].save(context)]
(const Regex& regex, PromptEvent event, Context& context) {
if (event == PromptEvent::Abort)
{
- RegisterManager::instance()[reg].set(context, saved_reg);
+ RegisterManager::instance()[reg].restore(context, saved_reg);
return;
}
RegisterManager::instance()[reg].set(context, regex.str());
@@ -907,7 +905,7 @@ template<SelectMode mode, RegexMode regex_mode>
void search_next(Context& context, NormalParams params)
{
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())
{
Regex regex{str, direction_flags(regex_mode)};
@@ -942,25 +940,21 @@ void search_next(Context& context, NormalParams params)
template<bool smart>
void use_selection_as_search_pattern(Context& context, NormalParams params)
{
- Vector<String> patterns;
- auto& sels = context.selections();
const auto& buffer = context.buffer();
- for (auto& sel : sels)
- {
- const auto beg = sel.min(), end = buffer.char_next(sel.max());
- patterns.push_back(format("{}{}{}",
- smart and is_bow(buffer, beg) ? "\\b" : "",
- escape(buffer.string(beg, end), "^$\\.*+?()[]{}|", '\\'),
- smart and is_eow(buffer, end) ? "\\b" : ""));
- }
+ auto& sel = context.selections().main();
+ const auto beg = sel.min(), end = buffer.char_next(sel.max());
+ String pattern = format("{}{}{}",
+ smart and is_bow(buffer, beg) ? "\\b" : "",
+ escape(buffer.string(beg, end), "^$\\.*+?()[]{}|", '\\'),
+ smart and is_eow(buffer, end) ? "\\b" : "");
const char reg = to_lower(params.reg ? params.reg : '/');
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"] });
- RegisterManager::instance()[reg].set(context, patterns);
+ RegisterManager::instance()[reg].set(context, {pattern});
// Hack, as Window do not take register state into account
if (context.has_window())
@@ -973,15 +967,12 @@ void select_regex(Context& context, NormalParams params)
const int capture = params.count;
auto prompt = capture ? format("select (capture {}):", capture) : "select:"_str;
- auto reg_content = RegisterManager::instance()[reg].get(context);
- Vector<String> saved_reg{reg_content.begin(), reg_content.end()};
- const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1);
-
- regex_prompt(context, std::move(prompt), saved_reg[main_index],
- [reg, capture, saved_reg](Regex ex, PromptEvent event, Context& context) {
+ regex_prompt(context, std::move(prompt), reg,
+ [reg, capture, saved_reg = RegisterManager::instance()[reg].save(context)]
+ (Regex ex, PromptEvent event, Context& context) {
if (event == PromptEvent::Abort)
{
- RegisterManager::instance()[reg].set(context, saved_reg);
+ RegisterManager::instance()[reg].restore(context, saved_reg);
return;
}
@@ -1000,15 +991,12 @@ void split_regex(Context& context, NormalParams params)
const int capture = params.count;
auto prompt = capture ? format("split (on capture {}):", (int)capture) : "split:"_str;
- auto reg_content = RegisterManager::instance()[reg].get(context);
- Vector<String> saved_reg{reg_content.begin(), reg_content.end()};
- const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1);
-
- regex_prompt(context, std::move(prompt), saved_reg[main_index],
- [reg, capture, saved_reg](Regex ex, PromptEvent event, Context& context) {
+ regex_prompt(context, std::move(prompt), reg,
+ [reg, capture, saved_reg = RegisterManager::instance()[reg].save(context)]
+ (Regex ex, PromptEvent event, Context& context) {
if (event == PromptEvent::Abort)
{
- RegisterManager::instance()[reg].set(context, saved_reg);
+ RegisterManager::instance()[reg].restore(context, saved_reg);
return;
}
@@ -1102,16 +1090,13 @@ void keep(Context& context, NormalParams params)
constexpr StringView prompt = matching ? "keep matching:" : "keep not matching:";
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],
- [saved_reg, reg]
+ regex_prompt(context, prompt.str(), reg,
+ [reg, saved_reg = RegisterManager::instance()[reg].save(context)]
(const Regex& regex, PromptEvent event, Context& context) {
-
if (event == PromptEvent::Abort)
{
- RegisterManager::instance()[reg].set(context, saved_reg);
+ RegisterManager::instance()[reg].restore(context, saved_reg);
return;
}
if (not context.history_disabled())
@@ -1144,7 +1129,7 @@ void keep_pipe(Context& context, NormalParams)
{
context.input_handler().prompt(
"keep pipe:", {}, {}, context.faces()["Prompt"],
- PromptFlags::DropHistoryEntriesWithBlankPrefix, shell_complete,
+ PromptFlags::DropHistoryEntriesWithBlankPrefix, '|', shell_complete,
[](StringView cmdline, PromptEvent event, Context& context) {
if (event != PromptEvent::Validate)
return;
@@ -1301,7 +1286,7 @@ void select_object(Context& context, NormalParams params)
context.input_handler().prompt(
"object desc:", {}, {}, context.faces()["Prompt"],
- PromptFlags::None, complete_nothing,
+ PromptFlags::None, '_', complete_nothing,
[count,info](StringView cmdline, PromptEvent event, Context& context) {
if (event != PromptEvent::Change)
hide_auto_info_ifn(context, info);
diff --git a/src/register_manager.hh b/src/register_manager.hh
index 4337f257..c463ad3a 100644
--- a/src/register_manager.hh
+++ b/src/register_manager.hh
@@ -20,6 +20,15 @@ public:
virtual void set(Context& context, ConstArrayView<String> values) = 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
@@ -39,6 +48,25 @@ public:
else
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:
Vector<String, MemoryDomain::Registers> m_content;
};
@@ -63,11 +91,47 @@ public:
return StaticRegister::get(context);
}
+ void restore(Context& context, const RestoreInfo& info) override
+ {
+ set(context, info.data);
+ }
+
private:
Getter m_getter;
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>
std::unique_ptr<Register> make_dyn_reg(Func func)
{
@@ -93,6 +157,14 @@ public:
{
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>