|
|
|
@ -925,20 +925,189 @@ std::string Source::BaseView::get_selected_text() { |
|
|
|
return get_buffer()->get_text(start, end); |
|
|
|
return get_buffer()->get_text(start, end); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Source::BaseView::set_snippets() { |
|
|
|
bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) { |
|
|
|
LockGuard lock(snippets_mutex); |
|
|
|
setup_extra_cursor_signals(); |
|
|
|
|
|
|
|
|
|
|
|
snippets = nullptr; |
|
|
|
if(key->keyval == GDK_KEY_Escape && !extra_cursors.empty()) { |
|
|
|
|
|
|
|
for(auto &extra_cursor : extra_cursors) { |
|
|
|
|
|
|
|
extra_cursor.mark->set_visible(false); |
|
|
|
|
|
|
|
get_buffer()->delete_mark(extra_cursor.mark); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
extra_cursors.clear(); |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(language) { |
|
|
|
unsigned create_cursor_mask = GDK_MOD1_MASK; |
|
|
|
for(auto &pair : Snippets::get().snippets) { |
|
|
|
unsigned move_last_created_cursor_mask = GDK_SHIFT_MASK | GDK_MOD1_MASK; |
|
|
|
std::smatch sm; |
|
|
|
|
|
|
|
if(std::regex_match(language->get_id().raw(), sm, pair.first)) { |
|
|
|
// Move last created cursor
|
|
|
|
snippets = &pair.second; |
|
|
|
if((key->keyval == GDK_KEY_Left || key->keyval == GDK_KEY_KP_Left) && (key->state & move_last_created_cursor_mask) == move_last_created_cursor_mask) { |
|
|
|
break; |
|
|
|
if(extra_cursors.empty()) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
auto &cursor = extra_cursors.back().mark; |
|
|
|
|
|
|
|
auto iter = cursor->get_iter(); |
|
|
|
|
|
|
|
iter.backward_char(); |
|
|
|
|
|
|
|
get_buffer()->move_mark(cursor, iter); |
|
|
|
|
|
|
|
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(extra_cursors.empty()) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
auto &cursor = extra_cursors.back().mark; |
|
|
|
|
|
|
|
auto iter = cursor->get_iter(); |
|
|
|
|
|
|
|
iter.forward_char(); |
|
|
|
|
|
|
|
get_buffer()->move_mark(cursor, iter); |
|
|
|
|
|
|
|
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(extra_cursors.empty()) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
auto &extra_cursor = extra_cursors.back(); |
|
|
|
|
|
|
|
auto iter = extra_cursor.mark->get_iter(); |
|
|
|
|
|
|
|
auto line_offset = extra_cursor.offset; |
|
|
|
|
|
|
|
if(iter.backward_line()) { |
|
|
|
|
|
|
|
auto end_line_iter = iter; |
|
|
|
|
|
|
|
if(!end_line_iter.ends_line()) |
|
|
|
|
|
|
|
end_line_iter.forward_to_line_end(); |
|
|
|
|
|
|
|
iter.forward_chars(std::min(line_offset, end_line_iter.get_line_offset())); |
|
|
|
|
|
|
|
get_buffer()->move_mark(extra_cursor.mark, iter); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
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(extra_cursors.empty()) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
auto &extra_cursor = extra_cursors.back(); |
|
|
|
|
|
|
|
auto iter = extra_cursor.mark->get_iter(); |
|
|
|
|
|
|
|
auto line_offset = extra_cursor.offset; |
|
|
|
|
|
|
|
if(iter.forward_line()) { |
|
|
|
|
|
|
|
auto end_line_iter = iter; |
|
|
|
|
|
|
|
if(!end_line_iter.ends_line()) |
|
|
|
|
|
|
|
end_line_iter.forward_to_line_end(); |
|
|
|
|
|
|
|
iter.forward_chars(std::min(line_offset, end_line_iter.get_line_offset())); |
|
|
|
|
|
|
|
get_buffer()->move_mark(extra_cursor.mark, iter); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create extra cursor
|
|
|
|
|
|
|
|
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 insert_line_offset = insert_iter.get_line_offset(); |
|
|
|
|
|
|
|
auto offset = insert_iter.get_offset(); |
|
|
|
|
|
|
|
for(auto &extra_cursor : extra_cursors) |
|
|
|
|
|
|
|
offset = std::min(offset, extra_cursor.mark->get_iter().get_offset()); |
|
|
|
|
|
|
|
auto iter = get_buffer()->get_iter_at_offset(offset); |
|
|
|
|
|
|
|
if(iter.backward_line()) { |
|
|
|
|
|
|
|
auto end_line_iter = iter; |
|
|
|
|
|
|
|
if(!end_line_iter.ends_line()) |
|
|
|
|
|
|
|
end_line_iter.forward_to_line_end(); |
|
|
|
|
|
|
|
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.back().mark->set_visible(true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
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 insert_line_offset = insert_iter.get_line_offset(); |
|
|
|
|
|
|
|
auto offset = insert_iter.get_offset(); |
|
|
|
|
|
|
|
for(auto &extra_cursor : extra_cursors) |
|
|
|
|
|
|
|
offset = std::max(offset, extra_cursor.mark->get_iter().get_offset()); |
|
|
|
|
|
|
|
auto iter = get_buffer()->get_iter_at_offset(offset); |
|
|
|
|
|
|
|
if(iter.forward_line()) { |
|
|
|
|
|
|
|
auto end_line_iter = iter; |
|
|
|
|
|
|
|
if(!end_line_iter.ends_line()) |
|
|
|
|
|
|
|
end_line_iter.forward_to_line_end(); |
|
|
|
|
|
|
|
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.back().mark->set_visible(true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Move cursors left/right
|
|
|
|
|
|
|
|
if((key->keyval == GDK_KEY_Left || key->keyval == GDK_KEY_KP_Left) && (key->state & GDK_CONTROL_MASK) > 0) { |
|
|
|
|
|
|
|
enable_multiple_cursors = false; |
|
|
|
|
|
|
|
for(auto &extra_cursor : extra_cursors) { |
|
|
|
|
|
|
|
auto iter = extra_cursor.mark->get_iter(); |
|
|
|
|
|
|
|
iter.backward_word_start(); |
|
|
|
|
|
|
|
extra_cursor.offset = iter.get_line_offset(); |
|
|
|
|
|
|
|
get_buffer()->move_mark(extra_cursor.mark, iter); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
auto insert = get_buffer()->get_insert(); |
|
|
|
|
|
|
|
auto iter = insert->get_iter(); |
|
|
|
|
|
|
|
iter.backward_word_start(); |
|
|
|
|
|
|
|
get_buffer()->move_mark(insert, iter); |
|
|
|
|
|
|
|
if((key->state & GDK_SHIFT_MASK) == 0) |
|
|
|
|
|
|
|
get_buffer()->move_mark_by_name("selection_bound", iter); |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if((key->keyval == GDK_KEY_Right || key->keyval == GDK_KEY_KP_Right) && (key->state & GDK_CONTROL_MASK) > 0) { |
|
|
|
|
|
|
|
enable_multiple_cursors = false; |
|
|
|
|
|
|
|
for(auto &extra_cursor : extra_cursors) { |
|
|
|
|
|
|
|
auto iter = extra_cursor.mark->get_iter(); |
|
|
|
|
|
|
|
iter.forward_visible_word_end(); |
|
|
|
|
|
|
|
extra_cursor.offset = iter.get_line_offset(); |
|
|
|
|
|
|
|
get_buffer()->move_mark(extra_cursor.mark, iter); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
auto insert = get_buffer()->get_insert(); |
|
|
|
|
|
|
|
auto iter = insert->get_iter(); |
|
|
|
|
|
|
|
iter.forward_visible_word_end(); |
|
|
|
|
|
|
|
get_buffer()->move_mark(insert, iter); |
|
|
|
|
|
|
|
if((key->state & GDK_SHIFT_MASK) == 0) |
|
|
|
|
|
|
|
get_buffer()->move_mark_by_name("selection_bound", iter); |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Move cursors up/down
|
|
|
|
|
|
|
|
if((key->keyval == GDK_KEY_Up || key->keyval == GDK_KEY_KP_Up)) { |
|
|
|
|
|
|
|
enable_multiple_cursors = false; |
|
|
|
|
|
|
|
for(auto &extra_cursor : extra_cursors) { |
|
|
|
|
|
|
|
auto iter = extra_cursor.mark->get_iter(); |
|
|
|
|
|
|
|
auto line_offset = extra_cursor.offset; |
|
|
|
|
|
|
|
if(iter.backward_line()) { |
|
|
|
|
|
|
|
auto end_line_iter = iter; |
|
|
|
|
|
|
|
if(!end_line_iter.ends_line()) |
|
|
|
|
|
|
|
end_line_iter.forward_to_line_end(); |
|
|
|
|
|
|
|
iter.forward_chars(std::min(line_offset, end_line_iter.get_line_offset())); |
|
|
|
|
|
|
|
get_buffer()->move_mark(extra_cursor.mark, iter); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if((key->keyval == GDK_KEY_Down || key->keyval == GDK_KEY_KP_Down)) { |
|
|
|
|
|
|
|
enable_multiple_cursors = false; |
|
|
|
|
|
|
|
for(auto &extra_cursor : extra_cursors) { |
|
|
|
|
|
|
|
auto iter = extra_cursor.mark->get_iter(); |
|
|
|
|
|
|
|
auto line_offset = extra_cursor.offset; |
|
|
|
|
|
|
|
if(iter.forward_line()) { |
|
|
|
|
|
|
|
auto end_line_iter = iter; |
|
|
|
|
|
|
|
if(!end_line_iter.ends_line()) |
|
|
|
|
|
|
|
end_line_iter.forward_to_line_end(); |
|
|
|
|
|
|
|
iter.forward_chars(std::min(line_offset, end_line_iter.get_line_offset())); |
|
|
|
|
|
|
|
get_buffer()->move_mark(extra_cursor.mark, iter); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Source::BaseView::setup_extra_cursor_signals() { |
|
|
|
void Source::BaseView::setup_extra_cursor_signals() { |
|
|
|
@ -1043,6 +1212,22 @@ void Source::BaseView::setup_extra_cursor_signals() { |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Source::BaseView::set_snippets() { |
|
|
|
|
|
|
|
LockGuard lock(snippets_mutex); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
snippets = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(language) { |
|
|
|
|
|
|
|
for(auto &pair : Snippets::get().snippets) { |
|
|
|
|
|
|
|
std::smatch sm; |
|
|
|
|
|
|
|
if(std::regex_match(language->get_id().raw(), sm, pair.first)) { |
|
|
|
|
|
|
|
snippets = &pair.second; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Source::BaseView::insert_snippet(Gtk::TextIter iter, const std::string &snippet) { |
|
|
|
void Source::BaseView::insert_snippet(Gtk::TextIter iter, const std::string &snippet) { |
|
|
|
std::map<size_t, std::vector<std::pair<size_t, size_t>>> parameter_offsets_and_sizes_map; |
|
|
|
std::map<size_t, std::vector<std::pair<size_t, size_t>>> parameter_offsets_and_sizes_map; |
|
|
|
|
|
|
|
|
|
|
|
|