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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -1551,10 +1557,6 @@ private:
|
|||
sel.set(pos);
|
||||
}
|
||||
break;
|
||||
case InsertMode::InsertAtNextLineBegin:
|
||||
case InsertMode::InsertCursor:
|
||||
kak_assert(false); // invalid for interactive insert
|
||||
break;
|
||||
}
|
||||
selections.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&)>;
|
||||
|
||||
class InputMode;
|
||||
enum class InsertMode : unsigned;
|
||||
enum class KeymapMode : char;
|
||||
enum class CursorMode;
|
||||
|
||||
using PromptCompleter = std::function<Completions (const Context&, CompletionFlags,
|
||||
StringView, ByteCount)>;
|
||||
enum class InsertMode : unsigned
|
||||
{
|
||||
Insert,
|
||||
Append,
|
||||
Replace,
|
||||
InsertAtLineBegin,
|
||||
AppendAtLineEnd,
|
||||
OpenLineBelow,
|
||||
OpenLineAbove
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
const char reg = params.reg ? params.reg : '"';
|
||||
|
@ -690,22 +651,28 @@ void change(Context& context, NormalParams params)
|
|||
enter_insert_mode<InsertMode::Replace>(context, params);
|
||||
}
|
||||
|
||||
InsertMode adapt_for_linewise(InsertMode mode, bool linewise)
|
||||
enum class PasteMode
|
||||
{
|
||||
if (not linewise)
|
||||
return mode;
|
||||
Append,
|
||||
Insert,
|
||||
Replace
|
||||
};
|
||||
|
||||
BufferCoord paste_pos(Buffer& buffer, const Selection& sel, PasteMode mode, bool linewise)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case InsertMode::Append: return InsertMode::InsertAtNextLineBegin;
|
||||
case InsertMode::Insert: return InsertMode::InsertAtLineBegin;
|
||||
default: break;
|
||||
case PasteMode::Append:
|
||||
return linewise ? std::min(buffer.line_count(), sel.max().line+1) : buffer.char_next(sel.max());
|
||||
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)
|
||||
{
|
||||
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';
|
||||
});
|
||||
|
||||
auto& buffer = context.buffer();
|
||||
ScopedEdition edition(context);
|
||||
if (mode == InsertMode::Replace)
|
||||
context.selections().replace(strings);
|
||||
else
|
||||
context.selections().insert(strings, adapt_for_linewise(mode, linewise));
|
||||
context.selections().for_each([&](size_t index, Selection& sel) {
|
||||
auto& str = strings[std::min(strings.size()-1, index)];
|
||||
if (mode == PasteMode::Replace)
|
||||
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)
|
||||
{
|
||||
const char reg = params.reg ? params.reg : '"';
|
||||
|
@ -740,17 +711,15 @@ void paste_all(Context& context, NormalParams params)
|
|||
offsets.push_back(all.length());
|
||||
}
|
||||
|
||||
InsertMode effective_mode = adapt_for_linewise(mode, linewise);
|
||||
|
||||
Buffer& buffer = context.buffer();
|
||||
Vector<Selection> result;
|
||||
auto& selections = context.selections();
|
||||
{
|
||||
ScopedEdition edition(context);
|
||||
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.insert(get_insert_pos(buffer, sel, effective_mode), all);
|
||||
: buffer.insert(paste_pos(buffer, sel, mode, linewise), all);
|
||||
|
||||
ByteCount pos_offset = 0;
|
||||
BufferCoord pos = range.begin;
|
||||
|
@ -766,6 +735,45 @@ void paste_all(Context& context, NormalParams params)
|
|||
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)
|
||||
{
|
||||
return (mode & RegexMode::Forward) ?
|
||||
|
@ -2235,12 +2243,12 @@ static constexpr HashMap<Key, NormalCmd, MemoryDomain::Undefined, KeymapBackend>
|
|||
{ {'V'}, {"move view (locked)", view_commands<true>} },
|
||||
|
||||
{ {'y'}, {"yank selected text", yank} },
|
||||
{ {'p'}, {"paste after selected text", repeated<paste<InsertMode::Append>>} },
|
||||
{ {'P'}, {"paste before selected text", repeated<paste<InsertMode::Insert>>} },
|
||||
{ {alt('p')}, {"paste every yanked selection after selected text", paste_all<InsertMode::Append>} },
|
||||
{ {alt('P')}, {"paste every yanked selection before selected text", paste_all<InsertMode::Insert>} },
|
||||
{ {'R'}, {"replace selected text with yanked text", paste<InsertMode::Replace>} },
|
||||
{ {alt('R')}, {"replace selected text with every yanked text", paste_all<InsertMode::Replace>} },
|
||||
{ {'p'}, {"paste after selected text", repeated<paste<PasteMode::Append>>} },
|
||||
{ {'P'}, {"paste before selected text", repeated<paste<PasteMode::Insert>>} },
|
||||
{ {alt('p')}, {"paste every yanked selection after selected text", paste_all<PasteMode::Append>} },
|
||||
{ {alt('P')}, {"paste every yanked selection before selected text", paste_all<PasteMode::Insert>} },
|
||||
{ {'R'}, {"replace selected text with yanked text", paste<PasteMode::Replace>} },
|
||||
{ {alt('R')}, {"replace selected text with every yanked text", paste_all<PasteMode::Replace>} },
|
||||
|
||||
{ {'s'}, {"select regex matches in selected text", select_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} },
|
||||
{ {'|'}, {"pipe each selection through filter and replace with output", pipe<true>} },
|
||||
{ {alt('|')}, {"pipe each selection through command and ignore output", pipe<false>} },
|
||||
{ {'!'}, {"insert command output", insert_output<InsertMode::Insert>} },
|
||||
{ {alt('!')}, {"append command output", insert_output<InsertMode::Append>} },
|
||||
{ {'!'}, {"insert command output", insert_output<PasteMode::Insert>} },
|
||||
{ {alt('!')}, {"append command output", insert_output<PasteMode::Append>} },
|
||||
|
||||
{ {' '}, {"remove all selections except main", keep_selection} },
|
||||
{ {alt(' ')}, {"remove main selection", remove_selection} },
|
||||
|
|
|
@ -351,29 +351,6 @@ void SelectionList::sort_and_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,
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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.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 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 insert(Buffer& buffer, Selection& sel, StringView content, InsertMode mode);
|
||||
|
||||
void insert(Buffer& buffer, Selection& sel, BufferCoord pos, StringView content);
|
||||
|
||||
struct SelectionList
|
||||
{
|
||||
|
@ -154,7 +138,6 @@ struct SelectionList
|
|||
using ApplyFunc = FunctionRef<void (size_t index, Selection& sel)>;
|
||||
void for_each(ApplyFunc apply);
|
||||
|
||||
void insert(ConstArrayView<String> strings, InsertMode mode);
|
||||
void replace(ConstArrayView<String> strings);
|
||||
|
||||
void erase();
|
||||
|
|
Loading…
Reference in New Issue
Block a user