Browse Source

Improved snippet support

pipelines/235045657
eidheim 6 years ago
parent
commit
7e17bb6f23
  1. 4
      src/notebook.cpp
  2. 62
      src/source.cpp
  3. 185
      src/source_base.cpp
  4. 24
      src/source_base.hpp
  5. 414
      tests/source_test.cpp

4
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<size_t>(-1)) {
if(current_cursor_location != static_cast<size_t>(-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();) {

62
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;
}

185
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<Gtk::TextBuffer::Mark> &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<Gtk::TextBuffer::Mark> &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;
if(extra_cursor.parameter_size != std::numeric_limits<int>::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<int>::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<size_t, std::vector<std::pair<size_t, size_t>>> arguments_offsets;
std::map<size_t, std::vector<std::pair<size_t, size_t>>> 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;
std::function<void(bool)> 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 if(snippet[i] == '\\') {
escape = true;
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;
}

24
src/source_base.hpp

@ -141,19 +141,31 @@ namespace Source {
bool enable_multiple_cursors = false;
std::vector<std::pair<Glib::RefPtr<Gtk::TextBuffer::Mark>, int>> extra_cursors;
std::vector<Glib::RefPtr<Gtk::TextBuffer::Mark>> extra_snippet_cursors;
struct ExtraCursor {
Glib::RefPtr<Gtk::TextBuffer::Mark> mark;
int offset;
};
std::vector<ExtraCursor> extra_cursors;
struct ExtraSnippetCursor {
Glib::RefPtr<Gtk::TextBuffer::Mark> mark;
int parameter_size;
};
std::vector<ExtraSnippetCursor> 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::Snippet> *snippets GUARDED_BY(snippets_mutex) = nullptr;
std::list<std::vector<std::pair<Glib::RefPtr<Gtk::TextBuffer::Mark>, Glib::RefPtr<Gtk::TextBuffer::Mark>>>> snippets_marks;
Glib::RefPtr<Gtk::TextTag> snippet_argument_tag;
struct SnippetParameter {
Glib::RefPtr<Gtk::TextBuffer::Mark> start, end;
int size;
};
std::list<std::vector<SnippetParameter>> snippet_parameters_list;
Glib::RefPtr<Gtk::TextTag> 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

414
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<int, int>(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}</$1>");
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() == "<t>test</t>");
g_assert(buffer->get_text() == "<t>test</t>");
event.keyval = GDK_KEY_e;
view.on_key_press_event(&event);
assert(buffer->get_text() == "<te>test</te>");
g_assert(buffer->get_text() == "<te>test</te>");
}
{
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}</$1>");
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() == "<t>test</t> test");
g_assert(buffer->get_text() == "<t>test</t> test");
event.keyval = GDK_KEY_e;
view.on_key_press_event(&event);
assert(buffer->get_text() == "<te>test</te> test");
g_assert(buffer->get_text() == "<te>test</te> test");
}
{
buffer->set_text("test test");
view.insert_snippet(buffer->get_insert()->get_iter(), "<$1>${TM_SELECTED_TEXT:TM_CURRENT_LINE}</$1>");
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() == "<t>test test</t>");
event.keyval = GDK_KEY_e;
view.on_key_press_event(&event);
g_assert(buffer->get_text() == "<te>test test</te>");
}
{
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(), "<div${1: id=\"${2:some_id}\"}>\n $0\n</div>");
auto result = "<div id=\"some_id\">\n \n</div>";
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(), "<div${1: id=\"${2:some_id}\"}>\n $0\n</div>");
g_assert(buffer->get_text() == "<div id=\"some_id\">\n \n</div>");
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() == "<t>test test</t>");
g_assert(buffer->get_text() == "<divt>\n \n</div>");
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() == "<divt>\n \n</div>");
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() == "<te>test test</te>");
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);
}
}
}

Loading…
Cancel
Save