diff --git a/src/autocomplete.cpp b/src/autocomplete.cpp index fc967a7..d776b39 100644 --- a/src/autocomplete.cpp +++ b/src/autocomplete.cpp @@ -104,7 +104,7 @@ void Autocomplete::run() { reparse(); return; } - CompletionDialog::create(view, view->get_buffer()->create_mark(start_iter)); + CompletionDialog::create(view, start_iter); setup_dialog(); for(auto &row : rows) { CompletionDialog::get()->add_row(row); @@ -163,7 +163,7 @@ void Autocomplete::setup_dialog() { else { tooltips.clear(); auto iter = CompletionDialog::get()->start_mark->get_iter(); - tooltips.emplace_back(view, view->get_buffer()->create_mark(iter), view->get_buffer()->create_mark(iter), [set_buffer = std::move(set_buffer)](Tooltip &tooltip) { + tooltips.emplace_back(view, iter, iter, [set_buffer = std::move(set_buffer)](Tooltip &tooltip) { set_buffer(tooltip); }); tooltips.show(true); diff --git a/src/project.cpp b/src/project.cpp index ca2ec5c..db7d7b1 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -634,7 +634,7 @@ void Project::LLDB::debug_show_variables() { }; if(view) { auto iter = view->get_buffer()->get_insert()->get_iter(); - self->debug_variable_tooltips.emplace_back(view, view->get_buffer()->create_mark(iter), view->get_buffer()->create_mark(iter), std::move(set_tooltip_buffer)); + self->debug_variable_tooltips.emplace_back(view, iter, iter, std::move(set_tooltip_buffer)); } else self->debug_variable_tooltips.emplace_back(std::move(set_tooltip_buffer)); diff --git a/src/selection_dialog.cpp b/src/selection_dialog.cpp index 2950115..d9e7728 100644 --- a/src/selection_dialog.cpp +++ b/src/selection_dialog.cpp @@ -35,8 +35,8 @@ void SelectionDialogBase::ListViewText::clear() { size = 0; } -SelectionDialogBase::SelectionDialogBase(Gtk::TextView *text_view, const Glib::RefPtr &start_mark, bool show_search_entry, bool use_markup) - : start_mark(start_mark), text_view(text_view), window(Gtk::WindowType::WINDOW_POPUP), vbox(Gtk::Orientation::ORIENTATION_VERTICAL), list_view_text(use_markup), show_search_entry(show_search_entry) { +SelectionDialogBase::SelectionDialogBase(Gtk::TextView *text_view, const boost::optional &start_iter, bool show_search_entry, bool use_markup) + : start_mark(start_iter ? start_iter->get_buffer()->create_mark(*start_iter) : Glib::RefPtr()), text_view(text_view), window(Gtk::WindowType::WINDOW_POPUP), vbox(Gtk::Orientation::ORIENTATION_VERTICAL), list_view_text(use_markup), show_search_entry(show_search_entry) { auto g_application = g_application_get_default(); auto gio_application = Glib::wrap(g_application, true); auto application = Glib::RefPtr::cast_static(gio_application); @@ -213,8 +213,8 @@ void SelectionDialogBase::hide() { std::unique_ptr SelectionDialog::instance; -SelectionDialog::SelectionDialog(Gtk::TextView *text_view, const Glib::RefPtr &start_mark, bool show_search_entry, bool use_markup) - : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) { +SelectionDialog::SelectionDialog(Gtk::TextView *text_view, const boost::optional &start_iter, bool show_search_entry, bool use_markup) + : SelectionDialogBase(text_view, start_iter, show_search_entry, use_markup) { auto search_key = std::make_shared(); auto filter_model = Gtk::TreeModelFilter::create(list_view_text.get_model()); @@ -342,7 +342,7 @@ bool SelectionDialog::on_key_press(GdkEventKey *key) { std::unique_ptr CompletionDialog::instance; -CompletionDialog::CompletionDialog(Gtk::TextView *text_view, const Glib::RefPtr &start_mark) : SelectionDialogBase(text_view, start_mark, false, false) { +CompletionDialog::CompletionDialog(Gtk::TextView *text_view, const Gtk::TextIter &start_iter) : SelectionDialogBase(text_view, start_iter, false, false) { show_offset = text_view->get_buffer()->get_insert()->get_iter().get_offset(); auto search_key = std::make_shared(); diff --git a/src/selection_dialog.hpp b/src/selection_dialog.hpp index c12dad3..4f58471 100644 --- a/src/selection_dialog.hpp +++ b/src/selection_dialog.hpp @@ -37,7 +37,7 @@ class SelectionDialogBase { }; public: - SelectionDialogBase(Gtk::TextView *text_view, const Glib::RefPtr &start_mark, bool show_search_entry, bool use_markup); + SelectionDialogBase(Gtk::TextView *text_view, const boost::optional &start_iter, bool show_search_entry, bool use_markup); virtual ~SelectionDialogBase(); void add_row(const std::string &row); void erase_rows(); @@ -70,31 +70,31 @@ protected: }; class SelectionDialog : public SelectionDialogBase { - SelectionDialog(Gtk::TextView *text_view, const Glib::RefPtr &start_mark, bool show_search_entry, bool use_markup); + SelectionDialog(Gtk::TextView *text_view, const boost::optional &start_iter, bool show_search_entry, bool use_markup); static std::unique_ptr instance; public: bool on_key_press(GdkEventKey *key); static void create(Gtk::TextView *text_view, bool show_search_entry = true, bool use_markup = false) { - instance = std::unique_ptr(new SelectionDialog(text_view, text_view->get_buffer()->create_mark(text_view->get_buffer()->get_insert()->get_iter()), show_search_entry, use_markup)); + instance = std::unique_ptr(new SelectionDialog(text_view, text_view->get_buffer()->get_insert()->get_iter(), show_search_entry, use_markup)); } static void create(bool show_search_entry = true, bool use_markup = false) { - instance = std::unique_ptr(new SelectionDialog(nullptr, Glib::RefPtr(), show_search_entry, use_markup)); + instance = std::unique_ptr(new SelectionDialog(nullptr, {}, show_search_entry, use_markup)); } static std::unique_ptr &get() { return instance; } }; class CompletionDialog : public SelectionDialogBase { - CompletionDialog(Gtk::TextView *text_view, const Glib::RefPtr &start_mark); + CompletionDialog(Gtk::TextView *text_view, const Gtk::TextIter &start_iter); static std::unique_ptr instance; public: bool on_key_release(GdkEventKey *key); bool on_key_press(GdkEventKey *key); - static void create(Gtk::TextView *text_view, const Glib::RefPtr &start_mark) { - instance = std::unique_ptr(new CompletionDialog(text_view, start_mark)); + static void create(Gtk::TextView *text_view, const Gtk::TextIter &start_iter) { + instance = std::unique_ptr(new CompletionDialog(text_view, start_iter)); } static std::unique_ptr &get() { return instance; } diff --git a/src/source.cpp b/src/source.cpp index d3ce2eb..2553f06 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -1619,7 +1619,7 @@ void Source::View::add_diagnostic_tooltip(const Gtk::TextIter &start, const Gtk: std::string severity_tag_name = error ? "def:error" : "def:warning"; - diagnostic_tooltips.emplace_back(this, get_buffer()->create_mark(start), get_buffer()->create_mark(end), [error, severity_tag_name, set_buffer = std::move(set_buffer)](Tooltip &tooltip) { + diagnostic_tooltips.emplace_back(this, start, end, [error, severity_tag_name, set_buffer = std::move(set_buffer)](Tooltip &tooltip) { tooltip.buffer->insert_with_tag(tooltip.buffer->get_insert()->get_iter(), error ? "Error" : "Warning", severity_tag_name); tooltip.buffer->insert(tooltip.buffer->get_insert()->get_iter(), ":\n"); set_buffer(tooltip); diff --git a/src/source_base.cpp b/src/source_base.cpp index daa681a..fa19951 100644 --- a/src/source_base.cpp +++ b/src/source_base.cpp @@ -1090,6 +1090,7 @@ bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) { auto iter = extra_cursors.back().insert->get_iter(); iter.backward_char(); extra_cursors.back().move(iter, false); + extra_cursors.back().line_offset = iter.get_line_offset(); 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) { @@ -1098,32 +1099,31 @@ bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) { auto iter = extra_cursors.back().insert->get_iter(); iter.forward_char(); extra_cursors.back().move(iter, false); + extra_cursors.back().line_offset = iter.get_line_offset(); 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 iter = extra_cursors.back().insert->get_iter(); - 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(extra_cursors.back().line_offset, end_line_iter.get_line_offset())); - extra_cursors.back().move(iter, false); - } + 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(extra_cursors.back().line_offset, end_line_iter.get_line_offset())); + extra_cursors.back().move(iter, false); 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 iter = extra_cursors.back().insert->get_iter(); - 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(extra_cursors.back().line_offset, end_line_iter.get_line_offset())); - extra_cursors.back().move(iter, false); - } + 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(extra_cursors.back().line_offset, end_line_iter.get_line_offset())); + extra_cursors.back().move(iter, false); return true; } @@ -1136,8 +1136,10 @@ bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) { if(!extra_cursor.snippet) offset = std::min(offset, extra_cursor.insert->get_iter().get_offset()); } - iter = get_buffer()->get_iter_at_offset(offset); - if(iter.backward_line()) { + auto test_iter = get_buffer()->get_iter_at_offset(offset); + iter = test_iter; + iter.backward_line(); + if(iter.get_line() != test_iter.get_line()) { auto end_line_iter = iter; if(!end_line_iter.ends_line()) end_line_iter.forward_to_line_end(); @@ -1154,8 +1156,10 @@ bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) { if(!extra_cursor.snippet) offset = std::max(offset, extra_cursor.insert->get_iter().get_offset()); } - iter = get_buffer()->get_iter_at_offset(offset); - if(iter.forward_line()) { + auto test_iter = get_buffer()->get_iter_at_offset(offset); + iter = test_iter; + iter.forward_line(); + if(iter.get_line() != test_iter.get_line()) { auto end_line_iter = iter; if(!end_line_iter.ends_line()) end_line_iter.forward_to_line_end(); @@ -1170,13 +1174,12 @@ bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) { enable_multiple_cursors = false; for(auto &extra_cursor : extra_cursors) { auto iter = extra_cursor.insert->get_iter(); - 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(extra_cursor.line_offset, end_line_iter.get_line_offset())); - extra_cursor.move(iter, key->state & GDK_SHIFT_MASK); - } + 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(extra_cursor.line_offset, end_line_iter.get_line_offset())); + extra_cursor.move(iter, key->state & GDK_SHIFT_MASK); } return false; } @@ -1184,13 +1187,12 @@ bool Source::BaseView::on_key_press_event_extra_cursors(GdkEventKey *key) { enable_multiple_cursors = false; for(auto &extra_cursor : extra_cursors) { auto iter = extra_cursor.insert->get_iter(); - 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(extra_cursor.line_offset, end_line_iter.get_line_offset())); - extra_cursor.move(iter, key->state & GDK_SHIFT_MASK); - } + 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(extra_cursor.line_offset, end_line_iter.get_line_offset())); + extra_cursor.move(iter, key->state & GDK_SHIFT_MASK); } return false; } diff --git a/src/source_clang.cpp b/src/source_clang.cpp index 0ce90ce..778ba7d 100644 --- a/src/source_clang.cpp +++ b/src/source_clang.cpp @@ -509,7 +509,7 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) auto start = get_buffer()->get_iter_at_line_index(token_offsets.first.line - 1, token_offsets.first.index - 1); auto end = get_buffer()->get_iter_at_line_index(token_offsets.second.line - 1, token_offsets.second.index - 1); - type_tooltips.emplace_back(this, get_buffer()->create_mark(start), get_buffer()->create_mark(end), [this, token](Tooltip &tooltip) { + type_tooltips.emplace_back(this, start, end, [this, token](Tooltip &tooltip) { auto cursor = token.get_cursor(); tooltip.buffer->insert(tooltip.buffer->get_insert()->get_iter(), "Type: " + cursor.get_type_description()); auto brief_comment = cursor.get_brief_comments(); diff --git a/src/source_language_protocol.cpp b/src/source_language_protocol.cpp index 51d4b08..0828af6 100644 --- a/src/source_language_protocol.cpp +++ b/src/source_language_protocol.cpp @@ -1096,7 +1096,7 @@ void Source::LanguageProtocolView::update_diagnostics(std::vectorget_iter(), mark.second->get_iter(), false, [](Tooltip &tooltip) { + add_diagnostic_tooltip(mark.start->get_iter(), mark.end->get_iter(), false, [](Tooltip &tooltip) { tooltip.buffer->insert_at_cursor(type_coverage_message); }); num_warnings++; @@ -1172,7 +1172,7 @@ void Source::LanguageProtocolView::show_type_tooltips(const Gdk::Rectangle &rect type_tooltips.clear(); auto token_iters = get_token_iters(get_buffer()->get_iter_at_offset(offset)); - type_tooltips.emplace_back(this, get_buffer()->create_mark(token_iters.first), get_buffer()->create_mark(token_iters.second), [this, offset, contents = std::move(contents)](Tooltip &tooltip) { + type_tooltips.emplace_back(this, token_iters.first, token_iters.second, [this, offset, contents = std::move(contents)](Tooltip &tooltip) { for(size_t i = 0; i < contents.size(); i++) { if(i > 0) tooltip.buffer->insert_at_cursor("\n\n"); @@ -1735,15 +1735,11 @@ void Source::LanguageProtocolView::update_type_coverage() { } dispatcher.post([this, ranges = std::move(ranges)] { - for(auto &mark : type_coverage_marks) { - get_buffer()->delete_mark(mark.first); - get_buffer()->delete_mark(mark.second); - } type_coverage_marks.clear(); for(auto &range : ranges) { auto start = get_iter_at_line_pos(range.start.line, range.start.character); auto end = get_iter_at_line_pos(range.end.line, range.end.character); - type_coverage_marks.emplace_back(get_buffer()->create_mark(start), get_buffer()->create_mark(end)); + type_coverage_marks.emplace_back(start, end); } update_diagnostics(last_diagnostics); diff --git a/src/source_language_protocol.hpp b/src/source_language_protocol.hpp index be5bd90..4b6cc1b 100644 --- a/src/source_language_protocol.hpp +++ b/src/source_language_protocol.hpp @@ -214,7 +214,17 @@ namespace Source { std::vector last_diagnostics; sigc::connection update_type_coverage_connection; - std::vector, Glib::RefPtr>> type_coverage_marks; + class TypeCoverageMark { + public: + TypeCoverageMark(const Gtk::TextIter &start_iter, const Gtk::TextIter &end_iter) + : start(start_iter.get_buffer()->create_mark(start_iter)), end(end_iter.get_buffer()->create_mark(end_iter)) {} + ~TypeCoverageMark() { + start->get_buffer()->delete_mark(start); + end->get_buffer()->delete_mark(end); + } + Glib::RefPtr start, end; + }; + std::list type_coverage_marks; size_t num_warnings = 0, num_errors = 0, num_fix_its = 0; void update_type_coverage(); std::atomic update_type_coverage_retries = {60}; diff --git a/src/tooltips.cpp b/src/tooltips.cpp index 4b7398b..e2b868f 100644 --- a/src/tooltips.cpp +++ b/src/tooltips.cpp @@ -11,9 +11,11 @@ std::set Tooltips::shown_tooltips; Gdk::Rectangle Tooltips::drawn_tooltips_rectangle = Gdk::Rectangle(); -Tooltip::Tooltip(Gtk::TextView *text_view, Glib::RefPtr start_mark_, - Glib::RefPtr end_mark_, std::function set_buffer_) - : start_mark(std::move(start_mark_)), end_mark(std::move(end_mark_)), text_view(text_view), set_buffer(std::move(set_buffer_)) {} +Tooltip::Tooltip(Gtk::TextView *text_view, const Gtk::TextIter &start_iter, const Gtk::TextIter &end_iter, std::function set_buffer_) + : start_mark(start_iter.get_buffer()->create_mark(start_iter)), end_mark(end_iter.get_buffer()->create_mark(end_iter)), text_view(text_view), set_buffer(std::move(set_buffer_)) {} + +Tooltip::Tooltip(std::function set_buffer_) + : text_view(nullptr), set_buffer(std::move(set_buffer_)) {} Tooltip::~Tooltip() { Tooltips::shown_tooltips.erase(this); diff --git a/src/tooltips.hpp b/src/tooltips.hpp index d4f62b5..fe6202f 100644 --- a/src/tooltips.hpp +++ b/src/tooltips.hpp @@ -9,8 +9,8 @@ class Tooltip { public: - Tooltip(Gtk::TextView *text_view, Glib::RefPtr start_mark_, Glib::RefPtr end_mark_, std::function set_buffer_); - Tooltip(std::function set_buffer_) : Tooltip(nullptr, Glib::RefPtr(), Glib::RefPtr(), std::move(set_buffer_)) {} + Tooltip(Gtk::TextView *text_view, const Gtk::TextIter &start_iter, const Gtk::TextIter &end_iter, std::function set_buffer_); + Tooltip(std::function set_buffer_); ~Tooltip(); void update(); diff --git a/tests/source_test.cpp b/tests/source_test.cpp index 17b5dea..0eb5018 100644 --- a/tests/source_test.cpp +++ b/tests/source_test.cpp @@ -1,3 +1,4 @@ +#include "config.hpp" #include "filesystem.hpp" #include "source.hpp" #include @@ -696,5 +697,38 @@ int main() { view.insert_snippet(buffer->get_insert()->get_iter(), "\\test\\"); g_assert(buffer->get_text() == "\\test\\"); } + { + Config::get().source.enable_multiple_cursors = true; + buffer->set_text("\n"); + buffer->place_cursor(buffer->begin()); + event.keyval = GDK_KEY_Down; + event.state = GDK_MOD1_MASK; + view.on_key_press_event(&event); + event.state = 0; + + view.enable_multiple_cursors = true; + view.insert_snippet(buffer->get_insert()->get_iter(), "\\begin{${1:enumerate}}\n $0\n\\end{${1:enum}}"); + g_assert(buffer->get_text() == "\\begin{enumerate}\n \n\\end{enum}\n\\begin{enumerate}\n \n\\end{enum}"); + Gtk::TextIter start, end; + buffer->get_selection_bounds(start, end); + g_assert(start.get_offset() == 7); + g_assert(end.get_offset() == 16); + + event.keyval = GDK_KEY_t; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "\\begin{t}\n \n\\end{t}\n\\begin{t}\n \n\\end{t}"); + event.keyval = GDK_KEY_e; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "\\begin{te}\n \n\\end{te}\n\\begin{te}\n \n\\end{te}"); + + event.keyval = GDK_KEY_Tab; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "\\begin{te}\n \n\\end{te}\n\\begin{te}\n \n\\end{te}"); + g_assert(buffer->get_insert()->get_iter().get_offset() == 13); + + event.keyval = GDK_KEY_t; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "\\begin{te}\n t\n\\end{te}\n\\begin{te}\n t\n\\end{te}"); + } } } diff --git a/tests/stubs/selection_dialog.cpp b/tests/stubs/selection_dialog.cpp index f46d7d0..9d659a8 100644 --- a/tests/stubs/selection_dialog.cpp +++ b/tests/stubs/selection_dialog.cpp @@ -2,7 +2,7 @@ SelectionDialogBase::ListViewText::ListViewText(bool use_markup) {} -SelectionDialogBase::SelectionDialogBase(Gtk::TextView *text_view, const Glib::RefPtr &start_mark, bool show_search_entry, bool use_markup) +SelectionDialogBase::SelectionDialogBase(Gtk::TextView *text_view, const boost::optional &start_iter, bool show_search_entry, bool use_markup) : text_view(text_view), list_view_text(use_markup) {} void SelectionDialogBase::show() {} @@ -13,8 +13,8 @@ void SelectionDialogBase::add_row(const std::string &row) {} std::unique_ptr SelectionDialog::instance; -SelectionDialog::SelectionDialog(Gtk::TextView *text_view, const Glib::RefPtr &start_mark, bool show_search_entry, bool use_markup) - : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) {} +SelectionDialog::SelectionDialog(Gtk::TextView *text_view, const boost::optional &start_iter, bool show_search_entry, bool use_markup) + : SelectionDialogBase(text_view, start_iter, show_search_entry, use_markup) {} SelectionDialogBase::~SelectionDialogBase() {} @@ -22,8 +22,8 @@ bool SelectionDialog::on_key_press(GdkEventKey *key) { return true; } std::unique_ptr CompletionDialog::instance; -CompletionDialog::CompletionDialog(Gtk::TextView *text_view, const Glib::RefPtr &start_mark) - : SelectionDialogBase(text_view, start_mark, false, false) {} +CompletionDialog::CompletionDialog(Gtk::TextView *text_view, const Gtk::TextIter &start_iter) + : SelectionDialogBase(text_view, start_iter, false, false) {} bool CompletionDialog::on_key_press(GdkEventKey *key) { return true; }