Skip to content

Commit

Permalink
Prepare to record selection changes as perceived by the user
Browse files Browse the repository at this point in the history
To be able to undo selection changes, we want to record selections
from all commands that modify selections. Each such command will get
its own private copy of the selections object.

This copy will live until the command is finished executing.
All child commands that are run while the command is executing,
will also use the same copy, because to the user it's all just one
selection change anyway.

Add an RAII object in all places where we might modify selections.
The next commit will use this to create the private selections copy
in the constructor (if there is none) and remove redundant history
items in the destructor.

We could avoid the RAII object in some places but that seems worse.
For lifetimes that don't correspond to a lexical scope, we use a
std::unique_ptr. For lambdas that require conversion to std::function,
we use std::shared_ptr because we need something that's copyable.
  • Loading branch information
krobelus committed Aug 31, 2022
1 parent 611bdeb commit a9866be
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 15 deletions.
2 changes: 2 additions & 0 deletions src/commands.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,7 @@ void context_wrap(const ParametersParser& parser, Context& context, StringView d

ScopedSetBool disable_history(c.history_disabled());
ScopedEdition edition{c};
ScopedSelectionEdition selection_edition{c};

if (parser.get_switch("itersel"))
{
Expand Down Expand Up @@ -2523,6 +2524,7 @@ const CommandDesc select_cmd = {
else if (parser.get_switch("display-column"))
column_type = ColumnType::DisplayColumn;
ColumnCount tabstop = context.options()["tabstop"].get<int>();
ScopedSelectionEdition selection_edition{context};
context.selections_write_only() = selection_list_from_strings(buffer, column_type, parser.positionals_from(0), timestamp, 0, tabstop);
}
};
Expand Down
14 changes: 14 additions & 0 deletions src/context.hh
Original file line number Diff line number Diff line change
Expand Up @@ -180,5 +180,19 @@ private:
SafePtr<Buffer> m_buffer;
};

struct ScopedSelectionEdition
{
ScopedSelectionEdition(Context& context)
: m_context{context},
m_buffer{context.has_buffer() ? &context.buffer() : nullptr} {}
ScopedSelectionEdition(ScopedSelectionEdition&& other) : m_context{other.m_context}, m_buffer{other.m_buffer}
{ other.m_buffer = nullptr; }

~ScopedSelectionEdition() {}
private:
Context& m_context;
SafePtr<Buffer> m_buffer;
};

}
#endif // context_hh_INCLUDED
31 changes: 21 additions & 10 deletions src/input_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,67 +93,75 @@ struct MouseHandler

Buffer& buffer = context.buffer();
BufferCoord cursor;
auto& selections = context.selections();
constexpr auto modifiers = Key::Modifiers::Control | Key::Modifiers::Alt | Key::Modifiers::Shift | Key::Modifiers::MouseButtonMask;
switch ((key.modifiers & ~modifiers).value)
{
case Key::Modifiers::MousePress:
switch (key.mouse_button())
{
case Key::MouseButton::Right:
m_dragging = false;
case Key::MouseButton::Right: {
m_dragging.reset();
cursor = context.window().buffer_coord(key.coord());
ScopedSelectionEdition selection_edition{context};
auto& selections = context.selections();
if (key.modifiers & Key::Modifiers::Control)
selections = {{selections.begin()->anchor(), cursor}};
else
selections.main() = {selections.main().anchor(), cursor};
selections.sort_and_merge_overlapping();
return true;
}

case Key::MouseButton::Left:
m_dragging = true;
case Key::MouseButton::Left: {
m_dragging.reset(new ScopedSelectionEdition{context});
m_anchor = context.window().buffer_coord(key.coord());
if (not (key.modifiers & Key::Modifiers::Control))
context.selections_write_only() = { buffer, m_anchor};
else
{
auto& selections = context.selections();
size_t main = selections.size();
selections.push_back({m_anchor});
selections.set_main_index(main);
selections.sort_and_merge_overlapping();
}
return true;
}

default: return true;
}

case Key::Modifiers::MouseRelease:
case Key::Modifiers::MouseRelease: {
if (not m_dragging)
return true;
m_dragging = false;
auto& selections = context.selections();
cursor = context.window().buffer_coord(key.coord());
selections.main() = {buffer.clamp(m_anchor), cursor};
selections.sort_and_merge_overlapping();
m_dragging.reset();
return true;
}

case Key::Modifiers::MousePos:
case Key::Modifiers::MousePos: {
if (not m_dragging)
return true;
cursor = context.window().buffer_coord(key.coord());
auto& selections = context.selections();
selections.main() = {buffer.clamp(m_anchor), cursor};
selections.sort_and_merge_overlapping();
return true;
}

case Key::Modifiers::Scroll:
scroll_window(context, static_cast<int32_t>(key.key), m_dragging);
scroll_window(context, static_cast<int32_t>(key.key), (bool)m_dragging);
return true;

default: return false;
}
}

private:
bool m_dragging = false;
std::unique_ptr<ScopedSelectionEdition> m_dragging;
BufferCoord m_anchor;
};

Expand Down Expand Up @@ -1199,6 +1207,7 @@ class Insert : public InputMode
Insert(InputHandler& input_handler, InsertMode mode, int count)
: InputMode(input_handler),
m_edition(context()),
m_selection_edition(context()),
m_completer(context()),
m_restore_cursor(mode == InsertMode::Append),
m_auto_complete{context().options()["autocomplete"].get<AutoComplete>() & AutoComplete::Insert},
Expand Down Expand Up @@ -1549,6 +1558,7 @@ class Insert : public InputMode
}

ScopedEdition m_edition;
ScopedSelectionEdition m_selection_edition;
InsertCompleter m_completer;
const bool m_restore_cursor;
bool m_auto_complete;
Expand Down Expand Up @@ -1806,6 +1816,7 @@ void scroll_window(Context& context, LineCount offset, bool mouse_dragging)

win_pos.line = clamp(win_pos.line + offset, 0_line, line_count-1);

ScopedSelectionEdition selection_edition{context};
SelectionList& selections = context.selections();
Selection& main_selection = selections.main();
const BufferCoord anchor = main_selection.anchor();
Expand Down
Loading

0 comments on commit a9866be

Please sign in to comment.