From 7e17bb6f23d3f9ea9caf8f8ec7625f46471a201f Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 9 Jun 2020 13:32:06 +0200 Subject: [PATCH] Improved snippet support --- src/notebook.cpp | 4 +- src/source.cpp | 62 +++---- src/source_base.cpp | 193 +++++++++++--------- src/source_base.hpp | 24 ++- tests/source_test.cpp | 414 +++++++++++++++++++++++++++--------------- 5 files changed, 424 insertions(+), 273 deletions(-) diff --git a/src/notebook.cpp b/src/notebook.cpp index 0a41b7d..5413a65 100644 --- a/src/notebook.cpp +++ b/src/notebook.cpp @@ -337,7 +337,7 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position } } if(!mark_moved) { - if(current_cursor_location != static_cast(-1)) { + if(current_cursor_location != static_cast(-1) && current_cursor_location + 1 < cursor_locations.size()) { for(auto it = cursor_locations.begin() + current_cursor_location + 1; it != cursor_locations.end();) { it->view->get_buffer()->delete_mark(it->mark); it = cursor_locations.erase(it); @@ -348,7 +348,7 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position } // Combine adjacent cursor histories that are similar - if(!cursor_locations.empty()) { + if(cursor_locations.size() > 1) { size_t cursor_locations_index = 1; auto last_it = cursor_locations.begin(); for(auto it = cursor_locations.begin() + 1; it != cursor_locations.end();) { diff --git a/src/source.cpp b/src/source.cpp index bd83939..9c19765 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -2008,7 +2008,7 @@ bool Source::View::on_key_press_event(GdkEventKey *key) { previous_non_modifier_keyval = last_keyval; last_keyval = key->keyval; - if((key->keyval == GDK_KEY_Tab || key->keyval == GDK_KEY_ISO_Left_Tab) && (key->state & GDK_SHIFT_MASK) == 0 && select_snippet_argument()) + if((key->keyval == GDK_KEY_Tab || key->keyval == GDK_KEY_ISO_Left_Tab) && (key->state & GDK_SHIFT_MASK) == 0 && select_snippet_parameter()) return true; else if(key->keyval == GDK_KEY_Escape && clear_snippet_marks()) return true; @@ -3150,8 +3150,8 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { if(key->keyval == GDK_KEY_Escape && !extra_cursors.empty()) { for(auto &extra_cursor : extra_cursors) { - extra_cursor.first->set_visible(false); - get_buffer()->delete_mark(extra_cursor.first); + extra_cursor.mark->set_visible(false); + get_buffer()->delete_mark(extra_cursor.mark); } extra_cursors.clear(); return true; @@ -3164,7 +3164,7 @@ bool Source::View::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(extra_cursors.empty()) return false; - auto &cursor = extra_cursors.back().first; + auto &cursor = extra_cursors.back().mark; auto iter = cursor->get_iter(); iter.backward_char(); get_buffer()->move_mark(cursor, iter); @@ -3173,7 +3173,7 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { 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().first; + auto &cursor = extra_cursors.back().mark; auto iter = cursor->get_iter(); iter.forward_char(); get_buffer()->move_mark(cursor, iter); @@ -3183,14 +3183,14 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { if(extra_cursors.empty()) return false; auto &extra_cursor = extra_cursors.back(); - auto iter = extra_cursor.first->get_iter(); - auto line_offset = extra_cursor.second; + 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.first, iter); + get_buffer()->move_mark(extra_cursor.mark, iter); } return true; } @@ -3198,14 +3198,14 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { if(extra_cursors.empty()) return false; auto &extra_cursor = extra_cursors.back(); - auto iter = extra_cursor.first->get_iter(); - auto line_offset = extra_cursor.second; + 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.first, iter); + get_buffer()->move_mark(extra_cursor.mark, iter); } return true; } @@ -3216,15 +3216,15 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { 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.first->get_iter().get_offset()); + 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(get_buffer()->create_mark(iter, false), insert_line_offset); - extra_cursors.back().first->set_visible(true); + extra_cursors.emplace_back(ExtraCursor{get_buffer()->create_mark(iter, false), insert_line_offset}); + extra_cursors.back().mark->set_visible(true); } return true; } @@ -3233,15 +3233,15 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { 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.first->get_iter().get_offset()); + 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(get_buffer()->create_mark(iter, false), insert_line_offset); - extra_cursors.back().first->set_visible(true); + extra_cursors.emplace_back(ExtraCursor{get_buffer()->create_mark(iter, false), insert_line_offset}); + extra_cursors.back().mark->set_visible(true); } return true; } @@ -3250,10 +3250,10 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { 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.first->get_iter(); + auto iter = extra_cursor.mark->get_iter(); iter.backward_word_start(); - extra_cursor.second = iter.get_line_offset(); - get_buffer()->move_mark(extra_cursor.first, iter); + 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(); @@ -3266,10 +3266,10 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { 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.first->get_iter(); + auto iter = extra_cursor.mark->get_iter(); iter.forward_visible_word_end(); - extra_cursor.second = iter.get_line_offset(); - get_buffer()->move_mark(extra_cursor.first, iter); + 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(); @@ -3284,14 +3284,14 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { 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.first->get_iter(); - auto line_offset = extra_cursor.second; + 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.first, iter); + get_buffer()->move_mark(extra_cursor.mark, iter); } } return false; @@ -3299,14 +3299,14 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { 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.first->get_iter(); - auto line_offset = extra_cursor.second; + 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.first, iter); + get_buffer()->move_mark(extra_cursor.mark, iter); } } return false; @@ -3315,14 +3315,14 @@ bool Source::View::on_key_press_event_extra_cursors(GdkEventKey *key) { // 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.first, get_smart_home_iter(extra_cursor.first->get_iter())); + 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.first, get_smart_end_iter(extra_cursor.first->get_iter())); + get_buffer()->move_mark(extra_cursor.mark, get_smart_end_iter(extra_cursor.mark->get_iter())); enable_multiple_cursors = false; return false; } diff --git a/src/source_base.cpp b/src/source_base.cpp index 0111acc..59ee74d 100644 --- a/src/source_base.cpp +++ b/src/source_base.cpp @@ -173,11 +173,11 @@ Source::BaseView::BaseView(const boost::filesystem::path &file_path, const Glib: set_snippets(); - snippet_argument_tag = get_buffer()->create_tag(); + snippet_parameter_tag = get_buffer()->create_tag(); Gdk::RGBA rgba; rgba.set_rgba(0.5, 0.5, 0.5, 0.4); - snippet_argument_tag->property_background_rgba() = rgba; - snippet_argument_tag->property_background_set() = true; + snippet_parameter_tag->property_background_rgba() = rgba; + snippet_parameter_tag->property_background_set() = true; get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator &iter, const Glib::RefPtr &mark) { if(mark->get_name() == "insert") { @@ -949,8 +949,8 @@ void Source::BaseView::setup_extra_cursor_signals() { 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 &mark) mutable { for(auto &extra_cursor : extra_cursors) { - if(extra_cursor.first == mark && !iter.ends_line()) { - extra_cursor.second = std::max(extra_cursor.second, iter.get_line_offset()); + if(extra_cursor.mark == mark && !iter.ends_line()) { + extra_cursor.offset = std::max(extra_cursor.offset, iter.get_line_offset()); break; } } @@ -961,14 +961,14 @@ void Source::BaseView::setup_extra_cursor_signals() { auto offset_diff = mark->get_iter().get_offset() - last_insert->get_iter().get_offset(); if(offset_diff != 0) { for(auto &extra_cursor : extra_cursors) { - auto iter = extra_cursor.first->get_iter(); + auto iter = extra_cursor.mark->get_iter(); iter.forward_chars(offset_diff); - get_buffer()->move_mark(extra_cursor.first, iter); + get_buffer()->move_mark(extra_cursor.mark, iter); } for(auto &extra_cursor : extra_snippet_cursors) { - auto iter = extra_cursor->get_iter(); + auto iter = extra_cursor.mark->get_iter(); iter.forward_chars(offset_diff); - get_buffer()->move_mark(extra_cursor, iter); + get_buffer()->move_mark(extra_cursor.mark, iter); } } enable_multiple_cursors = true; @@ -984,15 +984,15 @@ void Source::BaseView::setup_extra_cursor_signals() { if(offset > 0) offset -= text.size(); for(auto &extra_cursor : extra_cursors) { - auto iter = extra_cursor.first->get_iter(); + auto iter = extra_cursor.mark->get_iter(); iter.forward_chars(offset); get_buffer()->insert(iter, text); - auto extra_cursor_iter = extra_cursor.first->get_iter(); + auto extra_cursor_iter = extra_cursor.mark->get_iter(); if(!extra_cursor_iter.ends_line()) - extra_cursor.second = extra_cursor_iter.get_line_offset(); + extra_cursor.offset = extra_cursor_iter.get_line_offset(); } for(auto &extra_cursor : extra_snippet_cursors) { - auto iter = extra_cursor->get_iter(); + auto iter = extra_cursor.mark->get_iter(); iter.forward_chars(offset); get_buffer()->insert(iter, text); } @@ -1013,20 +1013,27 @@ void Source::BaseView::setup_extra_cursor_signals() { if(enable_multiple_cursors && (*erase_backward_length != 0 || *erase_forward_length != 0)) { enable_multiple_cursors = false; for(auto &extra_cursor : extra_cursors) { - auto start_iter = extra_cursor.first->get_iter(); + 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.first->get_iter(); + auto extra_cursor_iter = extra_cursor.mark->get_iter(); if(!extra_cursor_iter.ends_line()) - extra_cursor.second = extra_cursor_iter.get_line_offset(); + extra_cursor.offset = extra_cursor_iter.get_line_offset(); } for(auto &extra_cursor : extra_snippet_cursors) { - auto start_iter = extra_cursor->get_iter(); + 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); + if(extra_cursor.parameter_size != std::numeric_limits::max()) { // In case of different sized placeholders + if(*erase_backward_length == 0) + end_iter.forward_chars(extra_cursor.parameter_size); + extra_cursor.parameter_size = std::numeric_limits::max(); + } + else { + start_iter.backward_chars(*erase_backward_length); + end_iter.forward_chars(*erase_forward_length); + } get_buffer()->erase(start_iter, end_iter); } enable_multiple_cursors = true; @@ -1037,13 +1044,16 @@ void Source::BaseView::setup_extra_cursor_signals() { } void Source::BaseView::insert_snippet(Gtk::TextIter iter, const std::string &snippet) { - std::map>> arguments_offsets; + std::map>> parameter_offsets_and_sizes_map; std::string insert; insert.reserve(snippet.size()); + + bool erase_line = false, erase_word = false; + size_t i = 0; - int number; - auto parse_number = [&snippet, &i, &number]() { + + auto parse_number = [&](int &number) { if(i >= snippet.size()) throw std::out_of_range("unexpected end"); std::string str; @@ -1059,15 +1069,14 @@ void Source::BaseView::insert_snippet(Gtk::TextIter iter, const std::string &sni return false; } }; - auto compare_variable = [&snippet, &i](const char *text) { + auto compare_variable = [&](const char *text) { if(starts_with(snippet, i, text)) { i += strlen(text); return true; } return false; }; - bool erase_line = false, erase_word = false; - auto parse_variable = [this, &iter, &snippet, &i, &insert, &compare_variable, &erase_line, &erase_word] { + auto parse_variable = [&] { if(i >= snippet.size()) throw std::out_of_range("unexpected end"); if(compare_variable("TM_SELECTED_TEXT")) { @@ -1125,41 +1134,46 @@ void Source::BaseView::insert_snippet(Gtk::TextIter iter, const std::string &sni // TODO: support other variables return false; }; - try { - bool escape = false; - while(i < snippet.size()) { - if(escape) { - insert += snippet[i]; - escape = false; - ++i; - } - else if(snippet[i] == '\\') { - escape = true; - ++i; + + std::function parse_snippet = [&](bool stop_at_curly_end) { + int number; + for(; i < snippet.size() && !(stop_at_curly_end && snippet[i] == '}');) { + if(snippet[i] == '\\') { + if(i + 1 < snippet.size() && + (snippet[i + 1] == '$' || snippet[i + 1] == '`' || (stop_at_curly_end && snippet[i + 1] == '}'))) { + insert += snippet[i + 1]; + i += 2; + } + else { + insert += '\\'; + ++i; + } } else if(snippet[i] == '$') { ++i; if(snippet.at(i) == '{') { ++i; - if(parse_number()) { + int number; + if(parse_number(number)) { std::string placeholder; if(snippet.at(i) == ':') { ++i; - for(; snippet.at(i) != '}'; ++i) - placeholder += snippet[i]; + auto pos = insert.size(); + parse_snippet(true); + placeholder = insert.substr(pos); } if(snippet.at(i) != '}') throw std::logic_error("closing } not found"); ++i; - auto insert_character_count = utf8_character_count(insert); - arguments_offsets[number].emplace_back(insert_character_count, insert_character_count + utf8_character_count(placeholder)); - insert += placeholder; + auto placeholder_character_count = utf8_character_count(placeholder); + parameter_offsets_and_sizes_map[number].emplace_back(utf8_character_count(insert) - placeholder_character_count, placeholder_character_count); } else { if(!parse_variable()) { if(snippet.at(i) == ':') { // Use default value ++i; - parse_variable(); + if(!parse_variable()) + parse_snippet(true); } } else if(snippet.at(i) == ':') { // Skip default value @@ -1171,28 +1185,31 @@ void Source::BaseView::insert_snippet(Gtk::TextIter iter, const std::string &sni ++i; } } - else if(parse_number()) { - auto insert_character_count = utf8_character_count(insert); - arguments_offsets[number].emplace_back(insert_character_count, insert_character_count); - } + else if(parse_number(number)) + parameter_offsets_and_sizes_map[number].emplace_back(utf8_character_count(insert), 0); else parse_variable(); } - else - insert += snippet[i++]; + else { + insert += snippet[i]; + ++i; + } } + }; + try { + parse_snippet(false); } catch(...) { Terminal::get().print("Error: could not parse snippet: " + snippet + '\n', true); return; } - // $0 should be last argument - auto it = arguments_offsets.find(0); - if(it != arguments_offsets.end()) { - auto rit = arguments_offsets.rbegin(); - arguments_offsets.emplace(rit->first + 1, std::move(it->second)); - arguments_offsets.erase(it); + // $0 should be last parameter + auto it = parameter_offsets_and_sizes_map.find(0); + if(it != parameter_offsets_and_sizes_map.end()) { + auto rit = parameter_offsets_and_sizes_map.rbegin(); + parameter_offsets_and_sizes_map.emplace(rit->first + 1, std::move(it->second)); + parameter_offsets_and_sizes_map.erase(it); } auto mark = get_buffer()->create_mark(iter); @@ -1219,53 +1236,59 @@ void Source::BaseView::insert_snippet(Gtk::TextIter iter, const std::string &sni iter = mark->get_iter(); get_buffer()->delete_mark(mark); - for(auto arguments_offsets_it = arguments_offsets.rbegin(); arguments_offsets_it != arguments_offsets.rend(); ++arguments_offsets_it) { - snippets_marks.emplace_front(); - for(auto &offsets : arguments_offsets_it->second) { + for(auto it = parameter_offsets_and_sizes_map.rbegin(); it != parameter_offsets_and_sizes_map.rend(); ++it) { + snippet_parameters_list.emplace_front(); + for(auto &offsets : it->second) { auto start = iter; - auto end = start; start.forward_chars(offsets.first); + auto end = start; end.forward_chars(offsets.second); - snippets_marks.front().emplace_back(get_buffer()->create_mark(start, false), get_buffer()->create_mark(end, false)); - get_buffer()->apply_tag(snippet_argument_tag, start, end); + snippet_parameters_list.front().emplace_back(SnippetParameter{get_buffer()->create_mark(start, false), get_buffer()->create_mark(end, false), end.get_offset() - start.get_offset()}); } } - if(!arguments_offsets.empty()) - select_snippet_argument(); + if(!parameter_offsets_and_sizes_map.empty()) + select_snippet_parameter(); } -bool Source::BaseView::select_snippet_argument() { +bool Source::BaseView::select_snippet_parameter() { if(!extra_snippet_cursors.empty()) { for(auto &extra_cursor : extra_snippet_cursors) { - extra_cursor->set_visible(false); - get_buffer()->delete_mark(extra_cursor); + extra_cursor.mark->set_visible(false); + get_buffer()->delete_mark(extra_cursor.mark); } extra_snippet_cursors.clear(); } - if(!snippets_marks.empty()) { - auto snippets_marks_it = snippets_marks.begin(); + get_buffer()->remove_tag(snippet_parameter_tag, get_buffer()->begin(), get_buffer()->end()); + if(!snippet_parameters_list.empty()) { + auto snippet_parameters_it = snippet_parameters_list.begin(); bool first = true; - for(auto &marks : *snippets_marks_it) { - auto start = marks.first->get_iter(); - auto end = marks.second->get_iter(); + for(auto &snippet_parameter : *snippet_parameters_it) { + auto start = snippet_parameter.start->get_iter(); + auto end = snippet_parameter.end->get_iter(); if(first) { + if(snippet_parameter.size > 0 && end.get_offset() - start.get_offset() == 0) { // If the parameter has been erased + snippet_parameters_list.erase(snippet_parameters_it); + return select_snippet_parameter(); + } keep_snippet_marks = true; get_buffer()->select_range(start, end); keep_snippet_marks = false; first = false; } else { - extra_snippet_cursors.emplace_back(get_buffer()->create_mark(start, false)); - extra_snippet_cursors.back()->set_visible(true); + extra_snippet_cursors.emplace_back(ExtraSnippetCursor{get_buffer()->create_mark(start, false), end.get_offset() - start.get_offset()}); + extra_snippet_cursors.back().mark->set_visible(true); + + get_buffer()->apply_tag(snippet_parameter_tag, start, end); setup_extra_cursor_signals(); } - get_buffer()->delete_mark(marks.first); - get_buffer()->delete_mark(marks.second); + get_buffer()->delete_mark(snippet_parameter.start); + get_buffer()->delete_mark(snippet_parameter.end); } - snippets_marks.erase(snippets_marks_it); + snippet_parameters_list.erase(snippet_parameters_it); return true; } return false; @@ -1274,27 +1297,27 @@ bool Source::BaseView::select_snippet_argument() { bool Source::BaseView::clear_snippet_marks() { bool cleared = false; - if(!snippets_marks.empty()) { - for(auto &snippet_marks : snippets_marks) { - for(auto &pair : snippet_marks) { - get_buffer()->delete_mark(pair.first); - get_buffer()->delete_mark(pair.second); + if(!snippet_parameters_list.empty()) { + for(auto &snippet_parameters : snippet_parameters_list) { + for(auto &snippet_parameter : snippet_parameters) { + get_buffer()->delete_mark(snippet_parameter.start); + get_buffer()->delete_mark(snippet_parameter.end); } } - snippets_marks.clear(); + snippet_parameters_list.clear(); cleared = true; } if(!extra_snippet_cursors.empty()) { for(auto &extra_cursor : extra_snippet_cursors) { - extra_cursor->set_visible(false); - get_buffer()->delete_mark(extra_cursor); + extra_cursor.mark->set_visible(false); + get_buffer()->delete_mark(extra_cursor.mark); } extra_snippet_cursors.clear(); cleared = true; } - get_buffer()->remove_tag(snippet_argument_tag, get_buffer()->begin(), get_buffer()->end()); + get_buffer()->remove_tag(snippet_parameter_tag, get_buffer()->begin(), get_buffer()->end()); return cleared; } diff --git a/src/source_base.hpp b/src/source_base.hpp index a4df26e..71173d7 100644 --- a/src/source_base.hpp +++ b/src/source_base.hpp @@ -141,19 +141,31 @@ namespace Source { bool enable_multiple_cursors = false; - std::vector, int>> extra_cursors; - std::vector> extra_snippet_cursors; + struct ExtraCursor { + Glib::RefPtr mark; + int offset; + }; + std::vector extra_cursors; + struct ExtraSnippetCursor { + Glib::RefPtr mark; + int parameter_size; + }; + std::vector extra_snippet_cursors; void setup_extra_cursor_signals(); bool extra_cursors_signals_set = false; - /// After inserting a snippet, one can use tab to select the next argument + /// After inserting a snippet, one can use tab to select the next parameter bool keep_snippet_marks = false; Mutex snippets_mutex; std::vector *snippets GUARDED_BY(snippets_mutex) = nullptr; - std::list, Glib::RefPtr>>> snippets_marks; - Glib::RefPtr snippet_argument_tag; + struct SnippetParameter { + Glib::RefPtr start, end; + int size; + }; + std::list> snippet_parameters_list; + Glib::RefPtr snippet_parameter_tag; void insert_snippet(Gtk::TextIter iter, const std::string &snippet); - bool select_snippet_argument(); + bool select_snippet_parameter(); bool clear_snippet_marks(); }; } // namespace Source diff --git a/tests/source_test.cpp b/tests/source_test.cpp index 71e9f13..1830b15 100644 --- a/tests/source_test.cpp +++ b/tests/source_test.cpp @@ -59,19 +59,19 @@ int main() { buffer->set_text(text); buffer->place_cursor(buffer->begin()); view.replace_text(text); - assert(buffer->get_text() == text); - assert(buffer->get_insert()->get_iter() == buffer->begin()); + g_assert(buffer->get_text() == text); + g_assert(buffer->get_insert()->get_iter() == buffer->begin()); buffer->place_cursor(buffer->end()); view.replace_text(text); - assert(buffer->get_text() == text); - assert(buffer->get_insert()->get_iter() == buffer->end()); + g_assert(buffer->get_text() == text); + g_assert(buffer->get_insert()->get_iter() == buffer->end()); view.place_cursor_at_line_offset(1, 0); view.replace_text(text); - assert(buffer->get_text() == text); - assert(buffer->get_insert()->get_iter().get_line() == 1); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == text); + g_assert(buffer->get_insert()->get_iter().get_line() == 1); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); } { auto old_text = "line 1\nline3"; @@ -79,65 +79,65 @@ int main() { buffer->set_text(old_text); view.place_cursor_at_line_offset(1, 0); view.replace_text(new_text); - assert(buffer->get_text() == new_text); - assert(buffer->get_insert()->get_iter().get_line() == 2); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == new_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 2); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); view.replace_text(old_text); - assert(buffer->get_text() == old_text); - assert(buffer->get_insert()->get_iter().get_line() == 1); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == old_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 1); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); view.place_cursor_at_line_offset(0, 0); view.replace_text(new_text); - assert(buffer->get_text() == new_text); - assert(buffer->get_insert()->get_iter().get_line() == 0); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == new_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 0); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); view.replace_text(old_text); - assert(buffer->get_text() == old_text); - assert(buffer->get_insert()->get_iter().get_line() == 0); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == old_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 0); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); view.replace_text(new_text); - assert(buffer->get_text() == new_text); + g_assert(buffer->get_text() == new_text); view.place_cursor_at_line_offset(2, 0); view.replace_text(old_text); - assert(buffer->get_text() == old_text); - assert(buffer->get_insert()->get_iter().get_line() == 1); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == old_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 1); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); } { auto old_text = "line 1\nline 3"; auto new_text = ""; buffer->set_text(old_text); view.replace_text(new_text); - assert(buffer->get_text() == new_text); + g_assert(buffer->get_text() == new_text); view.replace_text(old_text); - assert(buffer->get_text() == old_text); - assert(buffer->get_insert()->get_iter().get_line() == 1); - assert(buffer->get_insert()->get_iter().get_line_offset() == 6); + g_assert(buffer->get_text() == old_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 1); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 6); } { auto old_text = ""; auto new_text = ""; buffer->set_text(old_text); view.replace_text(new_text); - assert(buffer->get_text() == new_text); + g_assert(buffer->get_text() == new_text); } { auto old_text = "line 1\nline 3\n"; auto new_text = ""; buffer->set_text(old_text); view.replace_text(new_text); - assert(buffer->get_text() == new_text); + g_assert(buffer->get_text() == new_text); view.replace_text(old_text); - assert(buffer->get_text() == old_text); - assert(buffer->get_insert()->get_iter().get_line() == 2); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == old_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 2); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); } { auto old_text = "line 1\n\nline 3\nline 4\n\nline 5\n"; @@ -145,16 +145,16 @@ int main() { buffer->set_text(old_text); view.place_cursor_at_line_offset(2, 0); view.replace_text(new_text); - assert(buffer->get_text() == new_text); - assert(buffer->get_insert()->get_iter().get_line() == 2); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == new_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 2); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); buffer->set_text(old_text); view.place_cursor_at_line_offset(3, 0); view.replace_text(new_text); - assert(buffer->get_text() == new_text); - assert(buffer->get_insert()->get_iter().get_line() == 3); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == new_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 3); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); } { auto old_text = "line 1\n\nline 3\nline 4\n\nline 5\n"; @@ -162,16 +162,16 @@ int main() { buffer->set_text(old_text); view.place_cursor_at_line_offset(2, 0); view.replace_text(new_text); - assert(buffer->get_text() == new_text); - assert(buffer->get_insert()->get_iter().get_line() == 2); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == new_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 2); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); buffer->set_text(old_text); view.place_cursor_at_line_offset(3, 0); view.replace_text(new_text); - assert(buffer->get_text() == new_text); - assert(buffer->get_insert()->get_iter().get_line() == 4); - assert(buffer->get_insert()->get_iter().get_line_offset() == 0); + g_assert(buffer->get_text() == new_text); + g_assert(buffer->get_insert()->get_iter().get_line() == 4); + g_assert(buffer->get_insert()->get_iter().get_line_offset() == 0); } } @@ -184,61 +184,61 @@ int main() { { view.place_cursor_at_line_offset(0, 0); view.extend_selection(); - assert(view.get_selected_text() == "test"); + g_assert(view.get_selected_text() == "test"); view.extend_selection(); - assert(view.get_selected_text() == "test(1, test(10), \"100\")"); + g_assert(view.get_selected_text() == "test(1, test(10), \"100\")"); view.extend_selection(); - assert(view.get_selected_text() == source); + g_assert(view.get_selected_text() == source); } { view.place_cursor_at_line_offset(0, 5); view.extend_selection(); - assert(view.get_selected_text() == "1"); + g_assert(view.get_selected_text() == "1"); view.extend_selection(); - assert(view.get_selected_text() == "1, test(10), \"100\""); + g_assert(view.get_selected_text() == "1, test(10), \"100\""); view.extend_selection(); - assert(view.get_selected_text() == "test(1, test(10), \"100\")"); + g_assert(view.get_selected_text() == "test(1, test(10), \"100\")"); } { view.place_cursor_at_line_offset(0, 7); view.extend_selection(); - assert(view.get_selected_text() == " test(10)"); + g_assert(view.get_selected_text() == " test(10)"); } { view.place_cursor_at_line_offset(0, 8); view.extend_selection(); - assert(view.get_selected_text() == "test"); + g_assert(view.get_selected_text() == "test"); view.extend_selection(); - assert(view.get_selected_text() == "test(10)"); + g_assert(view.get_selected_text() == "test(10)"); view.extend_selection(); - assert(view.get_selected_text() == " test(10)"); + g_assert(view.get_selected_text() == " test(10)"); view.extend_selection(); - assert(view.get_selected_text() == "1, test(10), \"100\""); + g_assert(view.get_selected_text() == "1, test(10), \"100\""); } { view.place_cursor_at_line_offset(0, 18); view.extend_selection(); - assert(view.get_selected_text() == " \"100\""); + g_assert(view.get_selected_text() == " \"100\""); view.extend_selection(); - assert(view.get_selected_text() == "1, test(10), \"100\""); + g_assert(view.get_selected_text() == "1, test(10), \"100\""); } { view.place_cursor_at_line_offset(0, 26); view.extend_selection(); - assert(view.get_selected_text() == source); + g_assert(view.get_selected_text() == source); } { view.place_cursor_at_line_offset(0, 27); view.extend_selection(); - assert(view.get_selected_text() == source); + g_assert(view.get_selected_text() == source); } source = "int main() {\n return 1;\n}\n"; @@ -246,47 +246,47 @@ int main() { { view.place_cursor_at_line_offset(0, 0); view.extend_selection(); - assert(view.get_selected_text() == "int"); + g_assert(view.get_selected_text() == "int"); view.extend_selection(); - assert(view.get_selected_text() == source.substr(0, source.size() - 1)); + g_assert(view.get_selected_text() == source.substr(0, source.size() - 1)); view.extend_selection(); - assert(view.get_selected_text() == source); + g_assert(view.get_selected_text() == source); } { view.place_cursor_at_line_offset(0, 4); view.extend_selection(); - assert(view.get_selected_text() == "main"); + g_assert(view.get_selected_text() == "main"); view.extend_selection(); - assert(view.get_selected_text() == source.substr(4, source.size() - 1 - 4)); + g_assert(view.get_selected_text() == source.substr(4, source.size() - 1 - 4)); view.extend_selection(); - assert(view.get_selected_text() == source.substr(0, source.size() - 1)); + g_assert(view.get_selected_text() == source.substr(0, source.size() - 1)); view.extend_selection(); - assert(view.get_selected_text() == source); + g_assert(view.get_selected_text() == source); } { view.place_cursor_at_line_offset(1, 2); view.extend_selection(); - assert(view.get_selected_text() == "return"); + g_assert(view.get_selected_text() == "return"); view.extend_selection(); - assert(view.get_selected_text() == "return 1;"); + g_assert(view.get_selected_text() == "return 1;"); view.extend_selection(); - assert(view.get_selected_text() == source.substr(12, 13)); + g_assert(view.get_selected_text() == source.substr(12, 13)); view.extend_selection(); - assert(view.get_selected_text() == source.substr(4, source.size() - 1 - 4)); + g_assert(view.get_selected_text() == source.substr(4, source.size() - 1 - 4)); view.extend_selection(); - assert(view.get_selected_text() == source.substr(0, source.size() - 1)); + g_assert(view.get_selected_text() == source.substr(0, source.size() - 1)); view.extend_selection(); - assert(view.get_selected_text() == source); + g_assert(view.get_selected_text() == source); } source = "test(11, 22);"; @@ -294,35 +294,35 @@ int main() { { view.place_cursor_at_line_offset(0, 0); view.extend_selection(); - assert(view.get_selected_text() == "test"); + g_assert(view.get_selected_text() == "test"); view.extend_selection(); - assert(view.get_selected_text() == source.substr(0, source.size() - 1)); + g_assert(view.get_selected_text() == source.substr(0, source.size() - 1)); view.extend_selection(); - assert(view.get_selected_text() == source); + g_assert(view.get_selected_text() == source); } { view.place_cursor_at_line_offset(0, 5); view.extend_selection(); - assert(view.get_selected_text() == "int"); + g_assert(view.get_selected_text() == "int"); view.extend_selection(); - assert(view.get_selected_text() == source.substr(5, 8)); + g_assert(view.get_selected_text() == source.substr(5, 8)); view.extend_selection(); - assert(view.get_selected_text() == source.substr(0, source.size() - 1)); + g_assert(view.get_selected_text() == source.substr(0, source.size() - 1)); } { view.place_cursor_at_line_offset(0, 15); view.extend_selection(); - assert(view.get_selected_text() == "11"); + g_assert(view.get_selected_text() == "11"); view.extend_selection(); - assert(view.get_selected_text() == "11, 22"); + g_assert(view.get_selected_text() == "11, 22"); view.extend_selection(); - assert(view.get_selected_text() == source.substr(0, source.size() - 1)); + g_assert(view.get_selected_text() == source.substr(0, source.size() - 1)); } source = "{\n {\n test;\n }\n}\n"; @@ -330,34 +330,34 @@ int main() { { view.place_cursor_at_line_offset(2, 4); view.extend_selection(); - assert(view.get_selected_text() == "test"); + g_assert(view.get_selected_text() == "test"); view.extend_selection(); - assert(view.get_selected_text() == "test;"); + g_assert(view.get_selected_text() == "test;"); view.extend_selection(); - assert(view.get_selected_text() == "\n test;\n "); + g_assert(view.get_selected_text() == "\n test;\n "); view.extend_selection(); - assert(view.get_selected_text() == "{\n test;\n }"); + g_assert(view.get_selected_text() == "{\n test;\n }"); view.extend_selection(); - assert(view.get_selected_text() == "\n {\n test;\n }\n"); + g_assert(view.get_selected_text() == "\n {\n test;\n }\n"); view.extend_selection(); - assert(view.get_selected_text() == "{\n {\n test;\n }\n}"); + g_assert(view.get_selected_text() == "{\n {\n test;\n }\n}"); view.extend_selection(); - assert(view.get_selected_text() == source); + g_assert(view.get_selected_text() == source); view.shrink_selection(); - assert(view.get_selected_text() == "{\n {\n test;\n }\n}"); + g_assert(view.get_selected_text() == "{\n {\n test;\n }\n}"); view.shrink_selection(); - assert(view.get_selected_text() == "\n {\n test;\n }\n"); + g_assert(view.get_selected_text() == "\n {\n test;\n }\n"); view.shrink_selection(); - assert(view.get_selected_text() == "{\n test;\n }"); + g_assert(view.get_selected_text() == "{\n test;\n }"); } } @@ -369,159 +369,205 @@ int main() { { buffer->set_text(""); view.insert_snippet(buffer->get_insert()->get_iter(), "std::cout << ${1:content} << std::endl;"); - assert(buffer->get_text() == "std::cout << content << std::endl;"); + g_assert(buffer->get_text() == "std::cout << content << std::endl;"); Gtk::TextIter start, end; buffer->get_selection_bounds(start, end); - assert(start.get_offset() == 13); - assert(end.get_offset() == 20); + g_assert(start.get_offset() == 13); + g_assert(end.get_offset() == 20); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << t << std::endl;"); + g_assert(buffer->get_text() == "std::cout << t << std::endl;"); event.keyval = GDK_KEY_e; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << std::endl;"); } { buffer->set_text(""); view.insert_snippet(buffer->get_insert()->get_iter(), "std::cout << ${1:} << std::endl;"); - assert(buffer->get_text() == "std::cout << << std::endl;"); + g_assert(buffer->get_text() == "std::cout << << std::endl;"); Gtk::TextIter start, end; buffer->get_selection_bounds(start, end); - assert(start.get_offset() == 13); - assert(end.get_offset() == 13); + g_assert(start.get_offset() == 13); + g_assert(end.get_offset() == 13); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << t << std::endl;"); + g_assert(buffer->get_text() == "std::cout << t << std::endl;"); event.keyval = GDK_KEY_e; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << std::endl;"); } { buffer->set_text(""); view.insert_snippet(buffer->get_insert()->get_iter(), "std::cout << $1 << std::endl;"); - assert(buffer->get_text() == "std::cout << << std::endl;"); + g_assert(buffer->get_text() == "std::cout << << std::endl;"); Gtk::TextIter start, end; buffer->get_selection_bounds(start, end); - assert(start.get_offset() == 13); - assert(end.get_offset() == 13); + g_assert(start.get_offset() == 13); + g_assert(end.get_offset() == 13); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << t << std::endl;"); + g_assert(buffer->get_text() == "std::cout << t << std::endl;"); event.keyval = GDK_KEY_e; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << std::endl;"); } { buffer->set_text(""); view.insert_snippet(buffer->get_insert()->get_iter(), "std::cout << ${1:content} << ${1:content} << std::endl;"); - assert(buffer->get_text() == "std::cout << content << content << std::endl;"); + g_assert(buffer->get_text() == "std::cout << content << content << std::endl;"); Gtk::TextIter start, end; buffer->get_selection_bounds(start, end); - assert(start.get_offset() == 13); - assert(end.get_offset() == 20); + g_assert(start.get_offset() == 13); + g_assert(end.get_offset() == 20); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << t << t << std::endl;"); + g_assert(buffer->get_text() == "std::cout << t << t << std::endl;"); event.keyval = GDK_KEY_e; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << te << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << te << std::endl;"); event.keyval = GDK_KEY_Escape; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << te << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << te << std::endl;"); event.keyval = GDK_KEY_s; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << tes << te << std::endl;"); + g_assert(buffer->get_text() == "std::cout << tes << te << std::endl;"); + } + { + buffer->set_text(""); + view.insert_snippet(buffer->get_insert()->get_iter(), "std::cout << ${1:content} << ${1:cont} << std::endl;"); + g_assert(buffer->get_text() == "std::cout << content << cont << std::endl;"); + Gtk::TextIter start, end; + buffer->get_selection_bounds(start, end); + g_assert(start.get_offset() == 13); + g_assert(end.get_offset() == 20); + + event.keyval = GDK_KEY_t; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "std::cout << t << t << std::endl;"); + event.keyval = GDK_KEY_e; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "std::cout << te << te << std::endl;"); + + event.keyval = GDK_KEY_Escape; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "std::cout << te << te << std::endl;"); + event.keyval = GDK_KEY_s; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "std::cout << tes << te << std::endl;"); + } + { + buffer->set_text(""); + view.insert_snippet(buffer->get_insert()->get_iter(), "std::cout << ${1:content} << $1 << std::endl;"); + g_assert(buffer->get_text() == "std::cout << content << << std::endl;"); + Gtk::TextIter start, end; + buffer->get_selection_bounds(start, end); + g_assert(start.get_offset() == 13); + g_assert(end.get_offset() == 20); + + event.keyval = GDK_KEY_t; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "std::cout << t << t << std::endl;"); + event.keyval = GDK_KEY_e; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "std::cout << te << te << std::endl;"); + + event.keyval = GDK_KEY_Escape; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "std::cout << te << te << std::endl;"); + event.keyval = GDK_KEY_s; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "std::cout << tes << te << std::endl;"); } { buffer->set_text(""); view.insert_snippet(buffer->get_insert()->get_iter(), "std::cout << ${1:content1} << ${2:content2} << std::endl;"); - assert(buffer->get_text() == "std::cout << content1 << content2 << std::endl;"); + g_assert(buffer->get_text() == "std::cout << content1 << content2 << std::endl;"); Gtk::TextIter start, end; buffer->get_selection_bounds(start, end); - assert(start.get_offset() == 13); - assert(end.get_offset() == 21); + g_assert(start.get_offset() == 13); + g_assert(end.get_offset() == 21); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << t << content2 << std::endl;"); + g_assert(buffer->get_text() == "std::cout << t << content2 << std::endl;"); event.keyval = GDK_KEY_e; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << content2 << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << content2 << std::endl;"); event.keyval = GDK_KEY_Tab; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << content2 << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << content2 << std::endl;"); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << t << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << t << std::endl;"); } { buffer->set_text(""); view.insert_snippet(buffer->get_insert()->get_iter(), "std::cout << ${1:content} << $0 << std::endl;"); - assert(buffer->get_text() == "std::cout << content << << std::endl;"); + g_assert(buffer->get_text() == "std::cout << content << << std::endl;"); Gtk::TextIter start, end; buffer->get_selection_bounds(start, end); - assert(start.get_offset() == 13); - assert(end.get_offset() == 20); + g_assert(start.get_offset() == 13); + g_assert(end.get_offset() == 20); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << t << << std::endl;"); + g_assert(buffer->get_text() == "std::cout << t << << std::endl;"); event.keyval = GDK_KEY_e; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << << std::endl;"); event.keyval = GDK_KEY_Tab; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << << std::endl;"); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << te << t << std::endl;"); + g_assert(buffer->get_text() == "std::cout << te << t << std::endl;"); } { buffer->set_text(""); view.insert_snippet(buffer->get_insert()->get_iter(), "std::cout << ${2:content2} << ${1:content1} << std::endl;"); - assert(buffer->get_text() == "std::cout << content2 << content1 << std::endl;"); + g_assert(buffer->get_text() == "std::cout << content2 << content1 << std::endl;"); Gtk::TextIter start, end; buffer->get_selection_bounds(start, end); - assert(start.get_offset() == 25); - assert(end.get_offset() == 33); + g_assert(start.get_offset() == 25); + g_assert(end.get_offset() == 33); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << content2 << t << std::endl;"); + g_assert(buffer->get_text() == "std::cout << content2 << t << std::endl;"); event.keyval = GDK_KEY_e; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << content2 << te << std::endl;"); + g_assert(buffer->get_text() == "std::cout << content2 << te << std::endl;"); event.keyval = GDK_KEY_Tab; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << content2 << te << std::endl;"); + g_assert(buffer->get_text() == "std::cout << content2 << te << std::endl;"); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "std::cout << t << te << std::endl;"); + g_assert(buffer->get_text() == "std::cout << t << te << std::endl;"); } { buffer->set_text("test"); buffer->select_range(buffer->begin(), buffer->end()); view.insert_snippet(buffer->get_insert()->get_iter(), "<$1>${TM_SELECTED_TEXT}"); - assert(buffer->get_text() == "<>test"); + g_assert(buffer->get_text() == "<>test"); Gtk::TextIter start, end; buffer->get_selection_bounds(start, end); - assert(start.get_offset() == 1); - assert(end.get_offset() == 1); + g_assert(start.get_offset() == 1); + g_assert(end.get_offset() == 1); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "test"); + g_assert(buffer->get_text() == "test"); event.keyval = GDK_KEY_e; view.on_key_press_event(&event); - assert(buffer->get_text() == "test"); + g_assert(buffer->get_text() == "test"); } { buffer->set_text("test test"); @@ -531,33 +577,103 @@ int main() { end.forward_chars(4); buffer->select_range(start, end); view.insert_snippet(buffer->get_insert()->get_iter(), "<$1>${TM_SELECTED_TEXT:TM_CURRENT_LINE}"); - assert(buffer->get_text() == "<>test test"); + g_assert(buffer->get_text() == "<>test test"); buffer->get_selection_bounds(start, end); - assert(start.get_offset() == 1); - assert(end.get_offset() == 1); + g_assert(start.get_offset() == 1); + g_assert(end.get_offset() == 1); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "test test"); + g_assert(buffer->get_text() == "test test"); event.keyval = GDK_KEY_e; view.on_key_press_event(&event); - assert(buffer->get_text() == "test test"); + g_assert(buffer->get_text() == "test test"); } { buffer->set_text("test test"); view.insert_snippet(buffer->get_insert()->get_iter(), "<$1>${TM_SELECTED_TEXT:TM_CURRENT_LINE}"); - assert(buffer->get_text() == "<>test test"); + g_assert(buffer->get_text() == "<>test test"); + Gtk::TextIter start, end; + buffer->get_selection_bounds(start, end); + g_assert(start.get_offset() == 1); + g_assert(end.get_offset() == 1); + + event.keyval = GDK_KEY_t; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "test test"); + event.keyval = GDK_KEY_e; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "test test"); + } + { + buffer->set_text(""); + view.insert_snippet(buffer->get_insert()->get_iter(), "\\textbf{${TM_SELECTED_TEXT:no text was selected}}"); + g_assert(buffer->get_text() == "\\textbf{no text was selected}"); + g_assert(buffer->get_insert()->get_iter().get_offset() == 29); + } + { + buffer->set_text(""); + view.insert_snippet(buffer->get_insert()->get_iter(), "\n $0\n"); + auto result = "
\n \n
"; + g_assert(buffer->get_text() == result); Gtk::TextIter start, end; buffer->get_selection_bounds(start, end); - assert(start.get_offset() == 1); - assert(end.get_offset() == 1); + g_assert(start.get_offset() == 4); + g_assert(end.get_offset() == 17); + + event.keyval = GDK_KEY_Tab; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == result); + buffer->get_selection_bounds(start, end); + g_assert(start.get_offset() == 9); + g_assert(end.get_offset() == 16); + + event.keyval = GDK_KEY_Tab; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == result); + g_assert(buffer->get_insert()->get_iter().get_offset() == 21); + } + { + buffer->set_text(""); + view.insert_snippet(buffer->get_insert()->get_iter(), "\n $0\n"); + g_assert(buffer->get_text() == "
\n \n
"); + Gtk::TextIter start, end; + buffer->get_selection_bounds(start, end); + g_assert(start.get_offset() == 4); + g_assert(end.get_offset() == 17); event.keyval = GDK_KEY_t; view.on_key_press_event(&event); - assert(buffer->get_text() == "test test"); + g_assert(buffer->get_text() == "\n \n"); + buffer->get_selection_bounds(start, end); + g_assert(start.get_offset() == 5); + g_assert(end.get_offset() == 5); + + event.keyval = GDK_KEY_Tab; + view.on_key_press_event(&event); + g_assert(buffer->get_text() == "\n \n"); + g_assert(buffer->get_insert()->get_iter().get_offset() == 9); + } + { + buffer->set_text(""); + view.insert_snippet(buffer->get_insert()->get_iter(), "\\begin{${1:enumerate}}\n $0\n\\end{$1}"); + g_assert(buffer->get_text() == "\\begin{enumerate}\n \n\\end{}"); + 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}"); event.keyval = GDK_KEY_e; view.on_key_press_event(&event); - assert(buffer->get_text() == "test test"); + g_assert(buffer->get_text() == "\\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}"); + g_assert(buffer->get_insert()->get_iter().get_offset() == 13); } } }