Browse Source

Multiple cursor cleanup and improvement

pipelines/235045657
eidheim 6 years ago
parent
commit
e1aae1cee3
  1. 21
      src/source.cpp
  2. 315
      src/source_base.cpp
  3. 23
      src/source_base.hpp
  4. 2
      src/source_language_protocol.cpp

21
src/source.cpp

@ -2025,9 +2025,7 @@ bool Source::View::on_key_press_event(GdkEventKey *key) {
if((key->keyval == GDK_KEY_Tab || key->keyval == GDK_KEY_ISO_Left_Tab) && (key->state & GDK_SHIFT_MASK) == 0 && select_snippet_parameter()) if((key->keyval == GDK_KEY_Tab || key->keyval == GDK_KEY_ISO_Left_Tab) && (key->state & GDK_SHIFT_MASK) == 0 && select_snippet_parameter())
return true; return true;
else if(key->keyval == GDK_KEY_Escape && clear_snippet_marks()) if(on_key_press_event_extra_cursors(key))
return true;
else if(Config::get().source.enable_multiple_cursors && on_key_press_event_extra_cursors(key))
return true; return true;
{ {
@ -2246,23 +2244,6 @@ bool Source::View::on_key_press_event_basic(GdkEventKey *key) {
return true; return true;
} }
} }
// Smart Home/End-keys
else if((key->keyval == GDK_KEY_Home || key->keyval == GDK_KEY_KP_Home) && (key->state & GDK_CONTROL_MASK) == 0) {
if((key->state & GDK_SHIFT_MASK) > 0)
get_buffer()->move_mark_by_name("insert", get_smart_home_iter(iter));
else
get_buffer()->place_cursor(get_smart_home_iter(iter));
scroll_to(get_buffer()->get_insert());
return true;
}
else if((key->keyval == GDK_KEY_End || key->keyval == GDK_KEY_KP_End) && (key->state & GDK_CONTROL_MASK) == 0) {
if((key->state & GDK_SHIFT_MASK) > 0)
get_buffer()->move_mark_by_name("insert", get_smart_end_iter(iter));
else
get_buffer()->place_cursor(get_smart_end_iter(iter));
scroll_to(get_buffer()->get_insert());
return true;
}
// Workaround for TextView::on_key_press_event bug sometimes causing segmentation faults // Workaround for TextView::on_key_press_event bug sometimes causing segmentation faults
// TODO: figure out the bug and create pull request to gtk // TODO: figure out the bug and create pull request to gtk

315
src/source_base.cpp

@ -184,9 +184,6 @@ Source::BaseView::BaseView(const boost::filesystem::path &file_path, const Glib:
get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator &iter, const Glib::RefPtr<Gtk::TextBuffer::Mark> &mark) { get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator &iter, const Glib::RefPtr<Gtk::TextBuffer::Mark> &mark) {
if(mark->get_name() == "insert") { if(mark->get_name() == "insert") {
keep_clipboard = false; keep_clipboard = false;
if(!keep_snippet_marks)
clear_snippet_marks();
} }
}); });
@ -993,14 +990,48 @@ bool Source::BaseView::on_key_press_event(GdkEventKey *key) {
scroll_to(get_buffer()->get_insert()); scroll_to(get_buffer()->get_insert());
return true; return true;
} }
// Smart Home
if((key->keyval == GDK_KEY_Home || key->keyval == GDK_KEY_KP_Home) && (key->state & GDK_CONTROL_MASK) == 0) {
enable_multiple_cursors = false;
for(auto &extra_cursor : extra_cursors) {
extra_cursor.move(get_smart_home_iter(extra_cursor.insert->get_iter()), key->state & GDK_SHIFT_MASK);
extra_cursor.line_offset = extra_cursor.insert->get_iter().get_line_offset();
}
auto insert = get_buffer()->get_insert();
auto iter = get_smart_home_iter(get_buffer()->get_insert()->get_iter());
get_buffer()->move_mark(insert, iter);
if((key->state & GDK_SHIFT_MASK) == 0)
get_buffer()->move_mark_by_name("selection_bound", iter);
scroll_to(get_buffer()->get_insert());
enable_multiple_cursors = true;
return true;
}
// Smart End
if((key->keyval == GDK_KEY_End || key->keyval == GDK_KEY_KP_End) && (key->state & GDK_CONTROL_MASK) == 0) {
enable_multiple_cursors = false;
for(auto &extra_cursor : extra_cursors) {
extra_cursor.move(get_smart_end_iter(extra_cursor.insert->get_iter()), key->state & GDK_SHIFT_MASK);
extra_cursor.line_offset = std::max(extra_cursor.line_offset, extra_cursor.insert->get_iter().get_line_offset());
}
auto insert = get_buffer()->get_insert();
auto iter = get_smart_end_iter(get_buffer()->get_insert()->get_iter());
get_buffer()->move_mark(insert, iter);
if((key->state & GDK_SHIFT_MASK) == 0)
get_buffer()->move_mark_by_name("selection_bound", iter);
scroll_to(get_buffer()->get_insert());
enable_multiple_cursors = true;
return true;
}
// Move cursors left one word // Move cursors left one word
if((key->keyval == GDK_KEY_Left || key->keyval == GDK_KEY_KP_Left) && (key->state & GDK_CONTROL_MASK) > 0) { if((key->keyval == GDK_KEY_Left || key->keyval == GDK_KEY_KP_Left) && (key->state & GDK_CONTROL_MASK) > 0) {
enable_multiple_cursors = false; enable_multiple_cursors = false;
for(auto &extra_cursor : extra_cursors) { for(auto &extra_cursor : extra_cursors) {
auto iter = extra_cursor.mark->get_iter(); auto iter = extra_cursor.insert->get_iter();
iter.backward_word_start(); iter.backward_word_start();
extra_cursor.line_offset = iter.get_line_offset(); extra_cursor.line_offset = iter.get_line_offset();
get_buffer()->move_mark(extra_cursor.mark, iter); extra_cursor.move(iter, key->state & GDK_SHIFT_MASK);
} }
auto insert = get_buffer()->get_insert(); auto insert = get_buffer()->get_insert();
auto iter = insert->get_iter(); auto iter = insert->get_iter();
@ -1015,14 +1046,15 @@ bool Source::BaseView::on_key_press_event(GdkEventKey *key) {
if((key->keyval == GDK_KEY_Right || key->keyval == GDK_KEY_KP_Right) && (key->state & GDK_CONTROL_MASK) > 0) { if((key->keyval == GDK_KEY_Right || key->keyval == GDK_KEY_KP_Right) && (key->state & GDK_CONTROL_MASK) > 0) {
enable_multiple_cursors = false; enable_multiple_cursors = false;
for(auto &extra_cursor : extra_cursors) { for(auto &extra_cursor : extra_cursors) {
auto iter = extra_cursor.mark->get_iter(); auto iter = extra_cursor.insert->get_iter();
iter.forward_visible_word_end(); iter.forward_word_end();
extra_cursor.line_offset = iter.get_line_offset(); extra_cursor.line_offset = iter.get_line_offset();
get_buffer()->move_mark(extra_cursor.mark, iter); extra_cursor.move(iter, key->state & GDK_SHIFT_MASK);
extra_cursor.insert->get_buffer()->apply_tag(extra_cursor_selection, extra_cursor.insert->get_iter(), extra_cursor.selection_bound->get_iter());
} }
auto insert = get_buffer()->get_insert(); auto insert = get_buffer()->get_insert();
auto iter = insert->get_iter(); auto iter = insert->get_iter();
iter.forward_visible_word_end(); iter.forward_word_end();
get_buffer()->move_mark(insert, iter); get_buffer()->move_mark(insert, iter);
if((key->state & GDK_SHIFT_MASK) == 0) if((key->state & GDK_SHIFT_MASK) == 0)
get_buffer()->move_mark_by_name("selection_bound", iter); get_buffer()->move_mark_by_name("selection_bound", iter);
@ -1034,16 +1066,19 @@ bool Source::BaseView::on_key_press_event(GdkEventKey *key) {
} }
bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) { bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) {
setup_extra_cursor_signals(); if(key->keyval == GDK_KEY_Escape) {
if(clear_snippet_marks())
if(key->keyval == GDK_KEY_Escape && !extra_cursors.empty()) { return true;
for(auto &extra_cursor : extra_cursors) { if(!extra_cursors.empty()) {
extra_cursor.mark->set_visible(false);
get_buffer()->delete_mark(extra_cursor.mark);
}
extra_cursors.clear(); extra_cursors.clear();
return true; return true;
} }
}
if(!Config::get().source.enable_multiple_cursors)
return false;
setup_extra_cursor_signals();
unsigned create_cursor_mask = GDK_MOD1_MASK; unsigned create_cursor_mask = GDK_MOD1_MASK;
unsigned move_last_created_cursor_mask = GDK_SHIFT_MASK | GDK_MOD1_MASK; unsigned move_last_created_cursor_mask = GDK_SHIFT_MASK | GDK_MOD1_MASK;
@ -1052,84 +1087,80 @@ bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) {
if((key->keyval == GDK_KEY_Left || key->keyval == GDK_KEY_KP_Left) && (key->state & move_last_created_cursor_mask) == move_last_created_cursor_mask) { if((key->keyval == GDK_KEY_Left || key->keyval == GDK_KEY_KP_Left) && (key->state & move_last_created_cursor_mask) == move_last_created_cursor_mask) {
if(extra_cursors.empty()) if(extra_cursors.empty())
return false; return false;
auto &cursor = extra_cursors.back().mark; auto iter = extra_cursors.back().insert->get_iter();
auto iter = cursor->get_iter();
iter.backward_char(); iter.backward_char();
get_buffer()->move_mark(cursor, iter); extra_cursors.back().move(iter, false);
return true; return true;
} }
if((key->keyval == GDK_KEY_Right || key->keyval == GDK_KEY_KP_Right) && (key->state & move_last_created_cursor_mask) == move_last_created_cursor_mask) { if((key->keyval == GDK_KEY_Right || key->keyval == GDK_KEY_KP_Right) && (key->state & move_last_created_cursor_mask) == move_last_created_cursor_mask) {
if(extra_cursors.empty()) if(extra_cursors.empty())
return false; return false;
auto &cursor = extra_cursors.back().mark; auto iter = extra_cursors.back().insert->get_iter();
auto iter = cursor->get_iter();
iter.forward_char(); iter.forward_char();
get_buffer()->move_mark(cursor, iter); extra_cursors.back().move(iter, false);
return true; return true;
} }
if((key->keyval == GDK_KEY_Up || key->keyval == GDK_KEY_KP_Up) && (key->state & move_last_created_cursor_mask) == move_last_created_cursor_mask) { if((key->keyval == GDK_KEY_Up || key->keyval == GDK_KEY_KP_Up) && (key->state & move_last_created_cursor_mask) == move_last_created_cursor_mask) {
if(extra_cursors.empty()) if(extra_cursors.empty())
return false; return false;
auto &extra_cursor = extra_cursors.back(); auto iter = extra_cursors.back().insert->get_iter();
auto iter = extra_cursor.mark->get_iter();
auto line_offset = extra_cursor.line_offset;
if(iter.backward_line()) { if(iter.backward_line()) {
auto end_line_iter = iter; auto end_line_iter = iter;
if(!end_line_iter.ends_line()) if(!end_line_iter.ends_line())
end_line_iter.forward_to_line_end(); end_line_iter.forward_to_line_end();
iter.forward_chars(std::min(line_offset, end_line_iter.get_line_offset())); iter.forward_chars(std::min(extra_cursors.back().line_offset, end_line_iter.get_line_offset()));
get_buffer()->move_mark(extra_cursor.mark, iter); extra_cursors.back().move(iter, false);
} }
return true; return true;
} }
if((key->keyval == GDK_KEY_Down || key->keyval == GDK_KEY_KP_Down) && (key->state & move_last_created_cursor_mask) == move_last_created_cursor_mask) { if((key->keyval == GDK_KEY_Down || key->keyval == GDK_KEY_KP_Down) && (key->state & move_last_created_cursor_mask) == move_last_created_cursor_mask) {
if(extra_cursors.empty()) if(extra_cursors.empty())
return false; return false;
auto &extra_cursor = extra_cursors.back(); auto iter = extra_cursors.back().insert->get_iter();
auto iter = extra_cursor.mark->get_iter();
auto line_offset = extra_cursor.line_offset;
if(iter.forward_line()) { if(iter.forward_line()) {
auto end_line_iter = iter; auto end_line_iter = iter;
if(!end_line_iter.ends_line()) if(!end_line_iter.ends_line())
end_line_iter.forward_to_line_end(); end_line_iter.forward_to_line_end();
iter.forward_chars(std::min(line_offset, end_line_iter.get_line_offset())); iter.forward_chars(std::min(extra_cursors.back().line_offset, end_line_iter.get_line_offset()));
get_buffer()->move_mark(extra_cursor.mark, iter); extra_cursors.back().move(iter, false);
} }
return true; return true;
} }
// Create extra cursor // Create extra cursor
if((key->keyval == GDK_KEY_Up || key->keyval == GDK_KEY_KP_Up) && (key->state & create_cursor_mask) == create_cursor_mask) { if((key->keyval == GDK_KEY_Up || key->keyval == GDK_KEY_KP_Up) && (key->state & create_cursor_mask) == create_cursor_mask) {
auto insert_iter = get_buffer()->get_insert()->get_iter(); auto iter = get_buffer()->get_insert()->get_iter();
auto insert_line_offset = insert_iter.get_line_offset(); auto insert_line_offset = iter.get_line_offset();
auto offset = insert_iter.get_offset(); auto offset = iter.get_offset();
for(auto &extra_cursor : extra_cursors) for(auto &extra_cursor : extra_cursors) { // Find topmost cursor
offset = std::min(offset, extra_cursor.mark->get_iter().get_offset()); if(!extra_cursor.snippet)
auto iter = get_buffer()->get_iter_at_offset(offset); offset = std::min(offset, extra_cursor.insert->get_iter().get_offset());
}
iter = get_buffer()->get_iter_at_offset(offset);
if(iter.backward_line()) { if(iter.backward_line()) {
auto end_line_iter = iter; auto end_line_iter = iter;
if(!end_line_iter.ends_line()) if(!end_line_iter.ends_line())
end_line_iter.forward_to_line_end(); end_line_iter.forward_to_line_end();
iter.forward_chars(std::min(insert_line_offset, end_line_iter.get_line_offset())); iter.forward_chars(std::min(insert_line_offset, end_line_iter.get_line_offset()));
extra_cursors.emplace_back(ExtraCursor{get_buffer()->create_mark(iter, false), insert_line_offset}); extra_cursors.emplace_back(extra_cursor_selection, iter, false, insert_line_offset);
extra_cursors.back().mark->set_visible(true);
} }
return true; return true;
} }
if((key->keyval == GDK_KEY_Down || key->keyval == GDK_KEY_KP_Down) && (key->state & create_cursor_mask) == create_cursor_mask) { if((key->keyval == GDK_KEY_Down || key->keyval == GDK_KEY_KP_Down) && (key->state & create_cursor_mask) == create_cursor_mask) {
auto insert_iter = get_buffer()->get_insert()->get_iter(); auto iter = get_buffer()->get_insert()->get_iter();
auto insert_line_offset = insert_iter.get_line_offset(); auto insert_line_offset = iter.get_line_offset();
auto offset = insert_iter.get_offset(); auto offset = iter.get_offset();
for(auto &extra_cursor : extra_cursors) for(auto &extra_cursor : extra_cursors) { // Find bottommost cursor
offset = std::max(offset, extra_cursor.mark->get_iter().get_offset()); if(!extra_cursor.snippet)
auto iter = get_buffer()->get_iter_at_offset(offset); offset = std::max(offset, extra_cursor.insert->get_iter().get_offset());
}
iter = get_buffer()->get_iter_at_offset(offset);
if(iter.forward_line()) { if(iter.forward_line()) {
auto end_line_iter = iter; auto end_line_iter = iter;
if(!end_line_iter.ends_line()) if(!end_line_iter.ends_line())
end_line_iter.forward_to_line_end(); end_line_iter.forward_to_line_end();
iter.forward_chars(std::min(insert_line_offset, end_line_iter.get_line_offset())); iter.forward_chars(std::min(insert_line_offset, end_line_iter.get_line_offset()));
extra_cursors.emplace_back(ExtraCursor{get_buffer()->create_mark(iter, false), insert_line_offset}); extra_cursors.emplace_back(extra_cursor_selection, iter, false, insert_line_offset);
extra_cursors.back().mark->set_visible(true);
} }
return true; return true;
} }
@ -1138,14 +1169,13 @@ bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) {
if((key->keyval == GDK_KEY_Up || key->keyval == GDK_KEY_KP_Up)) { if((key->keyval == GDK_KEY_Up || key->keyval == GDK_KEY_KP_Up)) {
enable_multiple_cursors = false; enable_multiple_cursors = false;
for(auto &extra_cursor : extra_cursors) { for(auto &extra_cursor : extra_cursors) {
auto iter = extra_cursor.mark->get_iter(); auto iter = extra_cursor.insert->get_iter();
auto line_offset = extra_cursor.line_offset;
if(iter.backward_line()) { if(iter.backward_line()) {
auto end_line_iter = iter; auto end_line_iter = iter;
if(!end_line_iter.ends_line()) if(!end_line_iter.ends_line())
end_line_iter.forward_to_line_end(); end_line_iter.forward_to_line_end();
iter.forward_chars(std::min(line_offset, end_line_iter.get_line_offset())); iter.forward_chars(std::min(extra_cursor.line_offset, end_line_iter.get_line_offset()));
get_buffer()->move_mark(extra_cursor.mark, iter); extra_cursor.move(iter, key->state & GDK_SHIFT_MASK);
} }
} }
return false; return false;
@ -1153,31 +1183,15 @@ bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) {
if((key->keyval == GDK_KEY_Down || key->keyval == GDK_KEY_KP_Down)) { if((key->keyval == GDK_KEY_Down || key->keyval == GDK_KEY_KP_Down)) {
enable_multiple_cursors = false; enable_multiple_cursors = false;
for(auto &extra_cursor : extra_cursors) { for(auto &extra_cursor : extra_cursors) {
auto iter = extra_cursor.mark->get_iter(); auto iter = extra_cursor.insert->get_iter();
auto line_offset = extra_cursor.line_offset;
if(iter.forward_line()) { if(iter.forward_line()) {
auto end_line_iter = iter; auto end_line_iter = iter;
if(!end_line_iter.ends_line()) if(!end_line_iter.ends_line())
end_line_iter.forward_to_line_end(); end_line_iter.forward_to_line_end();
iter.forward_chars(std::min(line_offset, end_line_iter.get_line_offset())); iter.forward_chars(std::min(extra_cursor.line_offset, end_line_iter.get_line_offset()));
get_buffer()->move_mark(extra_cursor.mark, iter); extra_cursor.move(iter, key->state & GDK_SHIFT_MASK);
}
} }
return false;
} }
// Smart Home-key, start of line
if((key->keyval == GDK_KEY_Home || key->keyval == GDK_KEY_KP_Home) && (key->state & GDK_CONTROL_MASK) == 0) {
for(auto &extra_cursor : extra_cursors)
get_buffer()->move_mark(extra_cursor.mark, get_smart_home_iter(extra_cursor.mark->get_iter()));
enable_multiple_cursors = false;
return false;
}
// Smart End-key, end of line
if((key->keyval == GDK_KEY_End || key->keyval == GDK_KEY_KP_End) && (key->state & GDK_CONTROL_MASK) == 0) {
for(auto &extra_cursor : extra_cursors)
get_buffer()->move_mark(extra_cursor.mark, get_smart_end_iter(extra_cursor.mark->get_iter()));
enable_multiple_cursors = false;
return false; return false;
} }
@ -1189,52 +1203,57 @@ void Source::BaseView::setup_extra_cursor_signals() {
return; return;
extra_cursors_signals_set = true; extra_cursors_signals_set = true;
extra_cursor_selection->set_priority(get_buffer()->get_tag_table()->get_size() - 1);
auto last_insert = get_buffer()->create_mark(get_buffer()->get_insert()->get_iter(), false); auto last_insert = get_buffer()->create_mark(get_buffer()->get_insert()->get_iter(), false);
get_buffer()->signal_mark_set().connect([this, last_insert](const Gtk::TextBuffer::iterator &iter, const Glib::RefPtr<Gtk::TextBuffer::Mark> &mark) mutable { auto last_selection_bound = get_buffer()->create_mark(get_buffer()->get_selection_bound()->get_iter(), false);
for(auto &extra_cursor : extra_cursors) { get_buffer()->signal_mark_set().connect([this, last_insert, last_selection_bound](const Gtk::TextBuffer::iterator &iter, const Glib::RefPtr<Gtk::TextBuffer::Mark> &mark) mutable {
if(extra_cursor.mark == mark && !iter.ends_line()) { auto is_insert = mark->get_name() == "insert";
extra_cursor.line_offset = std::max(extra_cursor.line_offset, iter.get_line_offset()); if(is_insert && !keep_snippet_marks)
break; clear_snippet_marks();
}
}
if(mark->get_name() == "insert") { if(is_insert) {
if(enable_multiple_cursors) { if(enable_multiple_cursors) {
enable_multiple_cursors = false; enable_multiple_cursors = false;
auto offset_diff = mark->get_iter().get_offset() - last_insert->get_iter().get_offset(); auto offset_diff = mark->get_iter().get_offset() - last_insert->get_iter().get_offset();
if(offset_diff != 0) { if(offset_diff != 0) {
for(auto &extra_cursor : extra_cursors) { for(auto &extra_cursor : extra_cursors) {
auto iter = extra_cursor.mark->get_iter();
iter.forward_chars(offset_diff);
get_buffer()->move_mark(extra_cursor.mark, iter);
}
for(auto &extra_cursor : extra_snippet_cursors) {
auto iter = extra_cursor.insert->get_iter(); auto iter = extra_cursor.insert->get_iter();
iter.forward_chars(offset_diff); iter.forward_chars(offset_diff);
get_buffer()->move_mark(extra_cursor.insert, iter); extra_cursor.move(iter, true);
extra_cursor.line_offset = iter.get_line_offset();
} }
} }
enable_multiple_cursors = true; enable_multiple_cursors = true;
} }
get_buffer()->move_mark(last_insert, mark->get_iter()); get_buffer()->move_mark(last_insert, mark->get_iter());
} }
if(mark->get_name() == "selection_bound") {
if(enable_multiple_cursors) {
enable_multiple_cursors = false;
auto offset_diff = mark->get_iter().get_offset() - last_selection_bound->get_iter().get_offset();
if(offset_diff != 0) {
for(auto &extra_cursor : extra_cursors) {
auto iter = extra_cursor.selection_bound->get_iter();
auto start = iter;
iter.forward_chars(offset_diff);
extra_cursor.move_selection_bound(iter);
}
}
enable_multiple_cursors = true;
}
get_buffer()->move_mark(last_selection_bound, mark->get_iter());
}
}); });
get_buffer()->signal_insert().connect([this](const Gtk::TextBuffer::iterator &iter, const Glib::ustring &text, int bytes) { get_buffer()->signal_insert().connect([this](const Gtk::TextBuffer::iterator &iter, const Glib::ustring &text, int bytes) {
if(enable_multiple_cursors && (!extra_cursors.empty() || !extra_snippet_cursors.empty())) { if(enable_multiple_cursors && !extra_cursors.empty()) {
enable_multiple_cursors = false; enable_multiple_cursors = false;
auto offset = iter.get_offset() - get_buffer()->get_insert()->get_iter().get_offset(); auto offset = iter.get_offset() - get_buffer()->get_insert()->get_iter().get_offset();
if(offset > 0) if(offset > 0)
offset -= text.size(); offset -= text.size();
for(auto &extra_cursor : extra_cursors) { for(auto &extra_cursor : extra_cursors) {
auto iter = extra_cursor.mark->get_iter();
iter.forward_chars(offset);
get_buffer()->insert(iter, text);
auto extra_cursor_iter = extra_cursor.mark->get_iter();
if(!extra_cursor_iter.ends_line())
extra_cursor.line_offset = extra_cursor_iter.get_line_offset();
}
for(auto &extra_cursor : extra_snippet_cursors) {
auto start_iter = extra_cursor.insert->get_iter(); auto start_iter = extra_cursor.insert->get_iter();
auto end_iter = extra_cursor.selection_bound->get_iter(); auto end_iter = extra_cursor.selection_bound->get_iter();
if(start_iter != end_iter) // Erase selection if any if(start_iter != end_iter) // Erase selection if any
@ -1243,6 +1262,8 @@ void Source::BaseView::setup_extra_cursor_signals() {
auto iter = extra_cursor.insert->get_iter(); auto iter = extra_cursor.insert->get_iter();
iter.forward_chars(offset); iter.forward_chars(offset);
get_buffer()->insert(iter, text); get_buffer()->insert(iter, text);
extra_cursor.line_offset = extra_cursor.insert->get_iter().get_line_offset();
} }
enable_multiple_cursors = true; enable_multiple_cursors = true;
} }
@ -1252,7 +1273,7 @@ void Source::BaseView::setup_extra_cursor_signals() {
auto erase_forward_length = std::make_shared<int>(0); auto erase_forward_length = std::make_shared<int>(0);
auto erase_selection = std::make_shared<bool>(false); auto erase_selection = std::make_shared<bool>(false);
get_buffer()->signal_erase().connect([this, erase_backward_length, erase_forward_length, erase_selection](const Gtk::TextBuffer::iterator &iter_start, const Gtk::TextBuffer::iterator &iter_end) { get_buffer()->signal_erase().connect([this, erase_backward_length, erase_forward_length, erase_selection](const Gtk::TextBuffer::iterator &iter_start, const Gtk::TextBuffer::iterator &iter_end) {
if(enable_multiple_cursors && (!extra_cursors.empty() || !extra_snippet_cursors.empty())) { if(enable_multiple_cursors && (!extra_cursors.empty())) {
auto insert_offset = get_buffer()->get_insert()->get_iter().get_offset(); auto insert_offset = get_buffer()->get_insert()->get_iter().get_offset();
*erase_backward_length = insert_offset - iter_start.get_offset(); *erase_backward_length = insert_offset - iter_start.get_offset();
*erase_forward_length = iter_end.get_offset() - insert_offset; *erase_forward_length = iter_end.get_offset() - insert_offset;
@ -1263,22 +1284,18 @@ void Source::BaseView::setup_extra_cursor_signals() {
if(iter == get_buffer()->get_selection_bound()->get_iter()) if(iter == get_buffer()->get_selection_bound()->get_iter())
*erase_selection = true; *erase_selection = true;
} }
else if(*erase_forward_length == 0) {
auto iter = get_buffer()->get_insert()->get_iter();
iter.backward_chars(*erase_backward_length);
if(iter == get_buffer()->get_selection_bound()->get_iter())
*erase_selection = true;
}
} }
}, false); }, false);
get_buffer()->signal_erase().connect([this, erase_backward_length, erase_forward_length, erase_selection](const Gtk::TextBuffer::iterator &iter_start, const Gtk::TextBuffer::iterator &iter_end) { get_buffer()->signal_erase().connect([this, erase_backward_length, erase_forward_length, erase_selection](const Gtk::TextBuffer::iterator & /*iter_start*/, const Gtk::TextBuffer::iterator & /*iter_end*/) {
if(enable_multiple_cursors && (*erase_backward_length != 0 || *erase_forward_length != 0)) { if(enable_multiple_cursors && (*erase_backward_length != 0 || *erase_forward_length != 0)) {
enable_multiple_cursors = false; enable_multiple_cursors = false;
for(auto &extra_cursor : extra_cursors) { for(auto &extra_cursor : extra_cursors) {
auto start_iter = extra_cursor.mark->get_iter();
auto end_iter = start_iter;
start_iter.backward_chars(*erase_backward_length);
end_iter.forward_chars(*erase_forward_length);
get_buffer()->erase(start_iter, end_iter);
auto extra_cursor_iter = extra_cursor.mark->get_iter();
if(!extra_cursor_iter.ends_line())
extra_cursor.line_offset = extra_cursor_iter.get_line_offset();
}
for(auto &extra_cursor : extra_snippet_cursors) {
if(*erase_selection) if(*erase_selection)
get_buffer()->erase(extra_cursor.insert->get_iter(), extra_cursor.selection_bound->get_iter()); get_buffer()->erase(extra_cursor.insert->get_iter(), extra_cursor.selection_bound->get_iter());
else { else {
@ -1292,6 +1309,8 @@ void Source::BaseView::setup_extra_cursor_signals() {
end_iter.forward_chars(*erase_forward_length); end_iter.forward_chars(*erase_forward_length);
start_iter.backward_chars(*erase_backward_length); start_iter.backward_chars(*erase_backward_length);
get_buffer()->erase(start_iter, end_iter); get_buffer()->erase(start_iter, end_iter);
extra_cursor.line_offset = extra_cursor.insert->get_iter().get_line_offset();
} }
} }
enable_multiple_cursors = true; enable_multiple_cursors = true;
@ -1526,22 +1545,21 @@ void Source::BaseView::insert_snippet(Gtk::TextIter iter, const std::string &sni
} }
bool Source::BaseView::select_snippet_parameter() { bool Source::BaseView::select_snippet_parameter() {
if(!extra_snippet_cursors.empty()) { for(auto it = extra_cursors.begin(); it != extra_cursors.end();) {
for(auto &extra_cursor : extra_snippet_cursors) { if(it->snippet)
extra_cursor.insert->set_visible(false); it = extra_cursors.erase(it);
get_buffer()->delete_mark(extra_cursor.insert); else
get_buffer()->delete_mark(extra_cursor.selection_bound); ++it;
}
extra_snippet_cursors.clear();
} }
get_buffer()->remove_tag(snippet_parameter_tag, get_buffer()->begin(), get_buffer()->end()); get_buffer()->remove_tag(snippet_parameter_tag, get_buffer()->begin(), get_buffer()->end());
get_buffer()->remove_tag(extra_cursor_selection, get_buffer()->begin(), get_buffer()->end());
bool first = true; bool first = true;
for(auto &parameters : snippet_parameters_list) { for(auto &parameters : snippet_parameters_list) {
for(auto &parameter : parameters) for(auto &parameter : parameters) {
get_buffer()->apply_tag(first ? extra_cursor_selection : snippet_parameter_tag, parameter.start->get_iter(), parameter.end->get_iter()); if(!first)
get_buffer()->apply_tag(snippet_parameter_tag, parameter.start->get_iter(), parameter.end->get_iter());
}
first = false; first = false;
} }
@ -1562,8 +1580,16 @@ bool Source::BaseView::select_snippet_parameter() {
first = false; first = false;
} }
else { else {
extra_snippet_cursors.emplace_back(ExtraSnippetCursor{get_buffer()->create_mark(start, false), get_buffer()->create_mark(end, false)}); extra_cursors.emplace_back(extra_cursor_selection, start, end, true);
extra_snippet_cursors.back().insert->set_visible(true); for(auto it = extra_cursors.begin(); it != extra_cursors.end(); ++it) {
if(!it->snippet) {
auto new_start = it->insert->get_iter();
new_start.forward_chars(start.get_offset() - get_buffer()->get_insert()->get_iter().get_offset());
auto new_end = new_start;
new_end.forward_chars(end.get_offset() - start.get_offset());
extra_cursors.emplace_back(extra_cursor_selection, new_start, new_end, true);
}
}
setup_extra_cursor_signals(); setup_extra_cursor_signals();
} }
@ -1590,18 +1616,55 @@ bool Source::BaseView::clear_snippet_marks() {
cleared = true; cleared = true;
} }
if(!extra_snippet_cursors.empty()) { for(auto it = extra_cursors.begin(); it != extra_cursors.end();) {
for(auto &extra_cursor : extra_snippet_cursors) { if(it->snippet) {
extra_cursor.insert->set_visible(false); it = extra_cursors.erase(it);
get_buffer()->delete_mark(extra_cursor.insert);
get_buffer()->delete_mark(extra_cursor.selection_bound);
}
extra_snippet_cursors.clear();
cleared = true; cleared = true;
} }
else
++it;
}
if(cleared)
get_buffer()->remove_tag(snippet_parameter_tag, get_buffer()->begin(), get_buffer()->end()); get_buffer()->remove_tag(snippet_parameter_tag, get_buffer()->begin(), get_buffer()->end());
get_buffer()->remove_tag(extra_cursor_selection, get_buffer()->begin(), get_buffer()->end());
return cleared; return cleared;
} }
Source::BaseView::ExtraCursor::ExtraCursor(const Glib::RefPtr<Gtk::TextTag> &extra_cursor_selection, const Gtk::TextIter &start_iter, const Gtk::TextIter &end_iter, bool snippet, int line_offset)
: extra_cursor_selection(extra_cursor_selection),
insert(start_iter.get_buffer()->create_mark(start_iter, false)),
selection_bound(start_iter.get_buffer()->create_mark(end_iter, false)),
line_offset(line_offset), snippet(snippet) {
insert->set_visible(true);
if(start_iter != end_iter)
insert->get_buffer()->apply_tag(extra_cursor_selection, insert->get_iter(), selection_bound->get_iter());
}
Source::BaseView::ExtraCursor::~ExtraCursor() {
insert->get_buffer()->remove_tag(extra_cursor_selection, insert->get_iter(), selection_bound->get_iter());
insert->set_visible(false);
insert->get_buffer()->delete_mark(insert);
selection_bound->get_buffer()->delete_mark(selection_bound);
}
void Source::BaseView::ExtraCursor::move(const Gtk::TextIter &iter, bool selection_activated) {
insert->get_buffer()->remove_tag(extra_cursor_selection, insert->get_iter(), selection_bound->get_iter());
insert->get_buffer()->move_mark(insert, iter);
if(!selection_activated)
selection_bound->get_buffer()->move_mark(selection_bound, iter);
auto start = insert->get_iter();
auto end = selection_bound->get_iter();
if(start != end)
insert->get_buffer()->apply_tag(extra_cursor_selection, start, end);
}
void Source::BaseView::ExtraCursor::move_selection_bound(const Gtk::TextIter &iter) {
insert->get_buffer()->remove_tag(extra_cursor_selection, insert->get_iter(), selection_bound->get_iter());
selection_bound->get_buffer()->move_mark(selection_bound, iter);
auto start = insert->get_iter();
auto end = selection_bound->get_iter();
if(start != end)
insert->get_buffer()->apply_tag(extra_cursor_selection, start, end);
}

23
src/source_base.hpp

@ -146,18 +146,25 @@ namespace Source {
bool on_key_press_event(GdkEventKey *key) override; bool on_key_press_event(GdkEventKey *key) override;
bool on_key_press_event_extra_cursors(GdkEventKey *key); bool on_key_press_event_extra_cursors(GdkEventKey *key);
struct ExtraCursor { class ExtraCursor {
Glib::RefPtr<Gtk::TextBuffer::Mark> mark; Glib::RefPtr<Gtk::TextTag> extra_cursor_selection;
/// Used when moving cursor up/down lines
int line_offset; public:
}; ExtraCursor(const Glib::RefPtr<Gtk::TextTag> &extra_cursor_selection, const Gtk::TextIter &start_iter, const Gtk::TextIter &end_iter, bool snippet, int line_offset = 0);
std::vector<ExtraCursor> extra_cursors; ExtraCursor(const Glib::RefPtr<Gtk::TextTag> &extra_cursor_selection, const Gtk::TextIter &start_iter, bool snippet, int line_offset = 0) : ExtraCursor(extra_cursor_selection, start_iter, start_iter, snippet, line_offset) {}
~ExtraCursor();
void move(const Gtk::TextIter &iter, bool selection_activated);
void move_selection_bound(const Gtk::TextIter &iter);
struct ExtraSnippetCursor {
Glib::RefPtr<Gtk::TextBuffer::Mark> insert; Glib::RefPtr<Gtk::TextBuffer::Mark> insert;
Glib::RefPtr<Gtk::TextBuffer::Mark> selection_bound; Glib::RefPtr<Gtk::TextBuffer::Mark> selection_bound;
/// Used when moving cursor up/down lines
int line_offset;
/// Set to true when the extra cursor corresponds to a snippet parameter
bool snippet;
}; };
std::vector<ExtraSnippetCursor> extra_snippet_cursors; std::list<ExtraCursor> extra_cursors;
void setup_extra_cursor_signals(); void setup_extra_cursor_signals();
bool extra_cursors_signals_set = false; bool extra_cursors_signals_set = false;

2
src/source_language_protocol.cpp

@ -281,8 +281,8 @@ void LanguageProtocol::Client::parse_server_message() {
tmp.seekg(0, std::ios::end); tmp.seekg(0, std::ios::end);
if(tmp.tellg() > 0) { if(tmp.tellg() > 0) {
tmp.seekg(0, std::ios::beg);
server_message_stream = std::move(tmp); server_message_stream = std::move(tmp);
server_message_stream.seekg(0, std::ios::beg);
parse_server_message(); parse_server_message();
} }
} }

Loading…
Cancel
Save