Split InsertMode into InsertMode and PasteMode
They are quite different use cases, and this allow moving InsertMode to input_handler.hh which is what uses it. This also cleans up the code as we can get rid of get_insert_pos and rely more on SelectionList::for_each.
This commit is contained in:
parent
b609adc84c
commit
689553c2e9
|
@ -1467,13 +1467,19 @@ private:
|
||||||
|
|
||||||
void insert(ConstArrayView<String> strings)
|
void insert(ConstArrayView<String> strings)
|
||||||
{
|
{
|
||||||
context().selections().insert(strings, InsertMode::InsertCursor);
|
context().selections().for_each([strings, &buffer=context().buffer()]
|
||||||
|
(size_t index, Selection& sel) {
|
||||||
|
Kakoune::insert(buffer, sel, sel.cursor(), strings[std::min(strings.size()-1, index)]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(Codepoint key)
|
void insert(Codepoint key)
|
||||||
{
|
{
|
||||||
String str{key};
|
String str{key};
|
||||||
context().selections().insert(str, InsertMode::InsertCursor);
|
context().selections().for_each([&buffer=context().buffer(), &str]
|
||||||
|
(size_t index, Selection& sel) {
|
||||||
|
Kakoune::insert(buffer, sel, sel.cursor(), str);
|
||||||
|
});
|
||||||
context().hooks().run_hook(Hook::InsertChar, str, context());
|
context().hooks().run_hook(Hook::InsertChar, str, context());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1551,10 +1557,6 @@ private:
|
||||||
sel.set(pos);
|
sel.set(pos);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InsertMode::InsertAtNextLineBegin:
|
|
||||||
case InsertMode::InsertCursor:
|
|
||||||
kak_assert(false); // invalid for interactive insert
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
selections.check_invariant();
|
selections.check_invariant();
|
||||||
buffer.check_invariant();
|
buffer.check_invariant();
|
||||||
|
|
|
@ -44,12 +44,21 @@ constexpr bool with_bit_ops(Meta::Type<PromptFlags>) { return true; }
|
||||||
using KeyCallback = std::function<void (Key, Context&)>;
|
using KeyCallback = std::function<void (Key, Context&)>;
|
||||||
|
|
||||||
class InputMode;
|
class InputMode;
|
||||||
enum class InsertMode : unsigned;
|
|
||||||
enum class KeymapMode : char;
|
enum class KeymapMode : char;
|
||||||
enum class CursorMode;
|
enum class CursorMode;
|
||||||
|
|
||||||
using PromptCompleter = std::function<Completions (const Context&, CompletionFlags,
|
using PromptCompleter = std::function<Completions (const Context&, CompletionFlags,
|
||||||
StringView, ByteCount)>;
|
StringView, ByteCount)>;
|
||||||
|
enum class InsertMode : unsigned
|
||||||
|
{
|
||||||
|
Insert,
|
||||||
|
Append,
|
||||||
|
Replace,
|
||||||
|
InsertAtLineBegin,
|
||||||
|
AppendAtLineEnd,
|
||||||
|
OpenLineBelow,
|
||||||
|
OpenLineAbove
|
||||||
|
};
|
||||||
|
|
||||||
class InputHandler : public SafeCountable
|
class InputHandler : public SafeCountable
|
||||||
{
|
{
|
||||||
|
|
138
src/normal.cc
138
src/normal.cc
|
@ -619,45 +619,6 @@ void pipe(Context& context, NormalParams params)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<InsertMode mode>
|
|
||||||
void insert_output(Context& context, NormalParams params)
|
|
||||||
{
|
|
||||||
const char* prompt = mode == InsertMode::Insert ? "insert-output:" : "append-output:";
|
|
||||||
String default_command = context.main_sel_register_value(params.reg ? params.reg : '|').str();
|
|
||||||
|
|
||||||
context.input_handler().prompt(
|
|
||||||
prompt, {}, default_command, context.faces()["Prompt"],
|
|
||||||
PromptFlags::DropHistoryEntriesWithBlankPrefix, '|',
|
|
||||||
shell_complete,
|
|
||||||
[default_command](StringView cmdline, PromptEvent event, Context& context)
|
|
||||||
{
|
|
||||||
if (event != PromptEvent::Validate)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (cmdline.empty())
|
|
||||||
cmdline = default_command;
|
|
||||||
|
|
||||||
if (cmdline.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
ScopedEdition edition(context);
|
|
||||||
auto& selections = context.selections();
|
|
||||||
auto& buffer = context.buffer();
|
|
||||||
const size_t old_main = selections.main_index();
|
|
||||||
|
|
||||||
selections.for_each([&](size_t index, Selection& sel) {
|
|
||||||
selections.set_main_index(index);
|
|
||||||
auto [out, status] = ShellManager::instance().eval(
|
|
||||||
cmdline, context, content(context.buffer(), sel),
|
|
||||||
ShellManager::Flags::WaitForStdout);
|
|
||||||
|
|
||||||
insert(buffer, sel, out, mode);
|
|
||||||
});
|
|
||||||
|
|
||||||
selections.set_main_index(old_main);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void yank(Context& context, NormalParams params)
|
void yank(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
const char reg = params.reg ? params.reg : '"';
|
const char reg = params.reg ? params.reg : '"';
|
||||||
|
@ -690,22 +651,28 @@ void change(Context& context, NormalParams params)
|
||||||
enter_insert_mode<InsertMode::Replace>(context, params);
|
enter_insert_mode<InsertMode::Replace>(context, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertMode adapt_for_linewise(InsertMode mode, bool linewise)
|
enum class PasteMode
|
||||||
{
|
{
|
||||||
if (not linewise)
|
Append,
|
||||||
return mode;
|
Insert,
|
||||||
|
Replace
|
||||||
|
};
|
||||||
|
|
||||||
|
BufferCoord paste_pos(Buffer& buffer, const Selection& sel, PasteMode mode, bool linewise)
|
||||||
|
{
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case InsertMode::Append: return InsertMode::InsertAtNextLineBegin;
|
case PasteMode::Append:
|
||||||
case InsertMode::Insert: return InsertMode::InsertAtLineBegin;
|
return linewise ? std::min(buffer.line_count(), sel.max().line+1) : buffer.char_next(sel.max());
|
||||||
default: break;
|
case PasteMode::Insert:
|
||||||
|
return linewise ? sel.min().line : sel.min();
|
||||||
|
default:
|
||||||
|
kak_assert(false);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
kak_assert(false);
|
|
||||||
return InsertMode::Insert;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<InsertMode mode>
|
template<PasteMode mode>
|
||||||
void paste(Context& context, NormalParams params)
|
void paste(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
const char reg = params.reg ? params.reg : '"';
|
const char reg = params.reg ? params.reg : '"';
|
||||||
|
@ -714,14 +681,18 @@ void paste(Context& context, NormalParams params)
|
||||||
return not str.empty() and str.back() == '\n';
|
return not str.empty() and str.back() == '\n';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto& buffer = context.buffer();
|
||||||
ScopedEdition edition(context);
|
ScopedEdition edition(context);
|
||||||
if (mode == InsertMode::Replace)
|
context.selections().for_each([&](size_t index, Selection& sel) {
|
||||||
context.selections().replace(strings);
|
auto& str = strings[std::min(strings.size()-1, index)];
|
||||||
else
|
if (mode == PasteMode::Replace)
|
||||||
context.selections().insert(strings, adapt_for_linewise(mode, linewise));
|
replace(buffer, sel, str);
|
||||||
|
else
|
||||||
|
insert(buffer, sel, paste_pos(buffer, sel, mode, linewise), str);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<InsertMode mode>
|
template<PasteMode mode>
|
||||||
void paste_all(Context& context, NormalParams params)
|
void paste_all(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
const char reg = params.reg ? params.reg : '"';
|
const char reg = params.reg ? params.reg : '"';
|
||||||
|
@ -740,17 +711,15 @@ void paste_all(Context& context, NormalParams params)
|
||||||
offsets.push_back(all.length());
|
offsets.push_back(all.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertMode effective_mode = adapt_for_linewise(mode, linewise);
|
|
||||||
|
|
||||||
Buffer& buffer = context.buffer();
|
Buffer& buffer = context.buffer();
|
||||||
Vector<Selection> result;
|
Vector<Selection> result;
|
||||||
auto& selections = context.selections();
|
auto& selections = context.selections();
|
||||||
{
|
{
|
||||||
ScopedEdition edition(context);
|
ScopedEdition edition(context);
|
||||||
selections.for_each([&](size_t, const Selection& sel) {
|
selections.for_each([&](size_t, const Selection& sel) {
|
||||||
auto range = (mode == InsertMode::Replace) ?
|
auto range = (mode == PasteMode::Replace) ?
|
||||||
buffer.replace(sel.min(), buffer.char_next(sel.max()), all)
|
buffer.replace(sel.min(), buffer.char_next(sel.max()), all)
|
||||||
: buffer.insert(get_insert_pos(buffer, sel, effective_mode), all);
|
: buffer.insert(paste_pos(buffer, sel, mode, linewise), all);
|
||||||
|
|
||||||
ByteCount pos_offset = 0;
|
ByteCount pos_offset = 0;
|
||||||
BufferCoord pos = range.begin;
|
BufferCoord pos = range.begin;
|
||||||
|
@ -766,6 +735,45 @@ void paste_all(Context& context, NormalParams params)
|
||||||
selections = std::move(result);
|
selections = std::move(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<PasteMode mode>
|
||||||
|
void insert_output(Context& context, NormalParams params)
|
||||||
|
{
|
||||||
|
const char* prompt = mode == PasteMode::Insert ? "insert-output:" : "append-output:";
|
||||||
|
String default_command = context.main_sel_register_value(params.reg ? params.reg : '|').str();
|
||||||
|
|
||||||
|
context.input_handler().prompt(
|
||||||
|
prompt, {}, default_command, context.faces()["Prompt"],
|
||||||
|
PromptFlags::DropHistoryEntriesWithBlankPrefix, '|',
|
||||||
|
shell_complete,
|
||||||
|
[default_command](StringView cmdline, PromptEvent event, Context& context)
|
||||||
|
{
|
||||||
|
if (event != PromptEvent::Validate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cmdline.empty())
|
||||||
|
cmdline = default_command;
|
||||||
|
|
||||||
|
if (cmdline.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ScopedEdition edition(context);
|
||||||
|
auto& selections = context.selections();
|
||||||
|
auto& buffer = context.buffer();
|
||||||
|
const size_t old_main = selections.main_index();
|
||||||
|
|
||||||
|
selections.for_each([&](size_t index, Selection& sel) {
|
||||||
|
selections.set_main_index(index);
|
||||||
|
auto [out, status] = ShellManager::instance().eval(
|
||||||
|
cmdline, context, content(context.buffer(), sel),
|
||||||
|
ShellManager::Flags::WaitForStdout);
|
||||||
|
|
||||||
|
insert(buffer, sel, paste_pos(buffer, sel, mode, false), out);
|
||||||
|
});
|
||||||
|
|
||||||
|
selections.set_main_index(old_main);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
constexpr RegexCompileFlags direction_flags(RegexMode mode)
|
constexpr RegexCompileFlags direction_flags(RegexMode mode)
|
||||||
{
|
{
|
||||||
return (mode & RegexMode::Forward) ?
|
return (mode & RegexMode::Forward) ?
|
||||||
|
@ -2235,12 +2243,12 @@ static constexpr HashMap<Key, NormalCmd, MemoryDomain::Undefined, KeymapBackend>
|
||||||
{ {'V'}, {"move view (locked)", view_commands<true>} },
|
{ {'V'}, {"move view (locked)", view_commands<true>} },
|
||||||
|
|
||||||
{ {'y'}, {"yank selected text", yank} },
|
{ {'y'}, {"yank selected text", yank} },
|
||||||
{ {'p'}, {"paste after selected text", repeated<paste<InsertMode::Append>>} },
|
{ {'p'}, {"paste after selected text", repeated<paste<PasteMode::Append>>} },
|
||||||
{ {'P'}, {"paste before selected text", repeated<paste<InsertMode::Insert>>} },
|
{ {'P'}, {"paste before selected text", repeated<paste<PasteMode::Insert>>} },
|
||||||
{ {alt('p')}, {"paste every yanked selection after selected text", paste_all<InsertMode::Append>} },
|
{ {alt('p')}, {"paste every yanked selection after selected text", paste_all<PasteMode::Append>} },
|
||||||
{ {alt('P')}, {"paste every yanked selection before selected text", paste_all<InsertMode::Insert>} },
|
{ {alt('P')}, {"paste every yanked selection before selected text", paste_all<PasteMode::Insert>} },
|
||||||
{ {'R'}, {"replace selected text with yanked text", paste<InsertMode::Replace>} },
|
{ {'R'}, {"replace selected text with yanked text", paste<PasteMode::Replace>} },
|
||||||
{ {alt('R')}, {"replace selected text with every yanked text", paste_all<InsertMode::Replace>} },
|
{ {alt('R')}, {"replace selected text with every yanked text", paste_all<PasteMode::Replace>} },
|
||||||
|
|
||||||
{ {'s'}, {"select regex matches in selected text", select_regex} },
|
{ {'s'}, {"select regex matches in selected text", select_regex} },
|
||||||
{ {'S'}, {"split selected text on regex matches", split_regex} },
|
{ {'S'}, {"split selected text on regex matches", split_regex} },
|
||||||
|
@ -2255,8 +2263,8 @@ static constexpr HashMap<Key, NormalCmd, MemoryDomain::Undefined, KeymapBackend>
|
||||||
{ {':'}, {"enter command prompt", command} },
|
{ {':'}, {"enter command prompt", command} },
|
||||||
{ {'|'}, {"pipe each selection through filter and replace with output", pipe<true>} },
|
{ {'|'}, {"pipe each selection through filter and replace with output", pipe<true>} },
|
||||||
{ {alt('|')}, {"pipe each selection through command and ignore output", pipe<false>} },
|
{ {alt('|')}, {"pipe each selection through command and ignore output", pipe<false>} },
|
||||||
{ {'!'}, {"insert command output", insert_output<InsertMode::Insert>} },
|
{ {'!'}, {"insert command output", insert_output<PasteMode::Insert>} },
|
||||||
{ {alt('!')}, {"append command output", insert_output<InsertMode::Append>} },
|
{ {alt('!')}, {"append command output", insert_output<PasteMode::Append>} },
|
||||||
|
|
||||||
{ {' '}, {"remove all selections except main", keep_selection} },
|
{ {' '}, {"remove all selections except main", keep_selection} },
|
||||||
{ {alt(' ')}, {"remove main selection", remove_selection} },
|
{ {alt(' ')}, {"remove main selection", remove_selection} },
|
||||||
|
|
|
@ -351,29 +351,6 @@ void SelectionList::sort_and_merge_overlapping()
|
||||||
merge_overlapping();
|
merge_overlapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferCoord get_insert_pos(const Buffer& buffer, const Selection& sel,
|
|
||||||
InsertMode mode)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case InsertMode::Insert:
|
|
||||||
return sel.min();
|
|
||||||
case InsertMode::InsertCursor:
|
|
||||||
return sel.cursor();
|
|
||||||
case InsertMode::Append:
|
|
||||||
return buffer.char_next(sel.max());
|
|
||||||
case InsertMode::InsertAtLineBegin:
|
|
||||||
return sel.min().line;
|
|
||||||
case InsertMode::AppendAtLineEnd:
|
|
||||||
return {sel.max().line, buffer[sel.max().line].length() - 1};
|
|
||||||
case InsertMode::InsertAtNextLineBegin:
|
|
||||||
return std::min(buffer.line_count(), sel.max().line+1);
|
|
||||||
default:
|
|
||||||
kak_assert(false);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fix_overflowing_selections(Vector<Selection>& selections,
|
static void fix_overflowing_selections(Vector<Selection>& selections,
|
||||||
const Buffer& buffer)
|
const Buffer& buffer)
|
||||||
{
|
{
|
||||||
|
@ -385,16 +362,6 @@ static void fix_overflowing_selections(Vector<Selection>& selections,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectionList::insert(ConstArrayView<String> strings, InsertMode mode)
|
|
||||||
{
|
|
||||||
if (strings.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
for_each([&](size_t index, Selection& sel) {
|
|
||||||
Kakoune::insert(*m_buffer, sel, strings[std::min(strings.size()-1, index)], mode);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void SelectionList::for_each(ApplyFunc func)
|
void SelectionList::for_each(ApplyFunc func)
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
|
@ -432,9 +399,9 @@ void replace(Buffer& buffer, Selection& sel, StringView content)
|
||||||
max = range.end > range.begin ? buffer.char_prev(range.end) : range.begin;
|
max = range.end > range.begin ? buffer.char_prev(range.end) : range.begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(Buffer& buffer, Selection& sel, StringView content, InsertMode mode)
|
void insert(Buffer& buffer, Selection& sel, BufferCoord pos, StringView content)
|
||||||
{
|
{
|
||||||
auto range = buffer.insert(get_insert_pos(buffer, sel, mode), content);
|
auto range = buffer.insert(pos, content);
|
||||||
sel.anchor() = buffer.clamp(update_insert(sel.anchor(), range.begin, range.end));
|
sel.anchor() = buffer.clamp(update_insert(sel.anchor(), range.begin, range.end));
|
||||||
sel.cursor() = buffer.clamp(update_insert(sel.cursor(), range.begin, range.end));
|
sel.cursor() = buffer.clamp(update_insert(sel.cursor(), range.begin, range.end));
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,24 +74,8 @@ void sort_selections(Vector<Selection>& selections, size_t& main);
|
||||||
void merge_overlapping_selections(Vector<Selection>& selections, size_t& main);
|
void merge_overlapping_selections(Vector<Selection>& selections, size_t& main);
|
||||||
void clamp_selections(Vector<Selection>& sel, const Buffer& buffer);
|
void clamp_selections(Vector<Selection>& sel, const Buffer& buffer);
|
||||||
|
|
||||||
enum class InsertMode : unsigned
|
|
||||||
{
|
|
||||||
Insert,
|
|
||||||
InsertCursor,
|
|
||||||
Append,
|
|
||||||
Replace,
|
|
||||||
InsertAtLineBegin,
|
|
||||||
InsertAtNextLineBegin,
|
|
||||||
AppendAtLineEnd,
|
|
||||||
OpenLineBelow,
|
|
||||||
OpenLineAbove
|
|
||||||
};
|
|
||||||
|
|
||||||
BufferCoord get_insert_pos(const Buffer& buffer, const Selection& sel, InsertMode mode);
|
|
||||||
|
|
||||||
void replace(Buffer& buffer, Selection& sel, StringView content);
|
void replace(Buffer& buffer, Selection& sel, StringView content);
|
||||||
void insert(Buffer& buffer, Selection& sel, StringView content, InsertMode mode);
|
void insert(Buffer& buffer, Selection& sel, BufferCoord pos, StringView content);
|
||||||
|
|
||||||
|
|
||||||
struct SelectionList
|
struct SelectionList
|
||||||
{
|
{
|
||||||
|
@ -154,7 +138,6 @@ struct SelectionList
|
||||||
using ApplyFunc = FunctionRef<void (size_t index, Selection& sel)>;
|
using ApplyFunc = FunctionRef<void (size_t index, Selection& sel)>;
|
||||||
void for_each(ApplyFunc apply);
|
void for_each(ApplyFunc apply);
|
||||||
|
|
||||||
void insert(ConstArrayView<String> strings, InsertMode mode);
|
|
||||||
void replace(ConstArrayView<String> strings);
|
void replace(ConstArrayView<String> strings);
|
||||||
|
|
||||||
void erase();
|
void erase();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user