Browse Source

Cleanup of is_code_iter and related functions

merge-requests/389/head
eidheim 7 years ago
parent
commit
e0de884cfe
  1. 88
      src/source.cc
  2. 1
      src/source.h
  3. 13
      src/source_base.cc
  4. 2
      src/source_base.h
  5. 92
      src/source_spellcheck.cc
  6. 8
      src/source_spellcheck.h
  7. 40
      tests/source_key_test.cc

88
src/source.cc

@ -212,15 +212,6 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr<
// }
// }
}
if(language_id == "chdr" || language_id == "cpphdr" || language_id == "c" ||
language_id == "cpp" || language_id == "objc" || language_id == "java" ||
language_id == "js" || language_id == "ts" || language_id == "proto" ||
language_id == "c-sharp" || language_id == "html" || language_id == "cuda" ||
language_id == "php" || language_id == "rust" || language_id == "swift" ||
language_id == "go" || language_id == "scala" || language_id == "opencl" ||
language_id == "json" || language_id == "css")
is_bracket_language = true;
}
setup_tooltip_and_dialog_events();
@ -1250,13 +1241,13 @@ void Source::View::hide_dialogs() {
Gtk::TextIter Source::View::find_non_whitespace_code_iter_backward(Gtk::TextIter iter) {
if(iter.starts_line())
return iter;
while(!iter.starts_line() && (is_comment_iter(iter) || *iter == ' ' || *iter == '\t' || iter.ends_line()) && iter.backward_char()) {
while(!iter.starts_line() && (!is_code_iter(iter) || *iter == ' ' || *iter == '\t' || iter.ends_line()) && iter.backward_char()) {
}
return iter;
}
Gtk::TextIter Source::View::get_start_of_expression(Gtk::TextIter iter) {
while(!iter.starts_line() && (*iter == ' ' || *iter == '\t' || iter.ends_line() || !is_code_iter(iter) || is_comment_iter(iter)) && iter.backward_char()) {
while(!iter.starts_line() && (*iter == ' ' || *iter == '\t' || iter.ends_line() || !is_code_iter(iter)) && iter.backward_char()) {
}
if(iter.starts_line())
@ -1323,7 +1314,7 @@ Gtk::TextIter Source::View::get_start_of_expression(Gtk::TextIter iter) {
// Handle ',', ':', or operators that can be used between two lines, on previous line:
auto previous_iter = iter;
previous_iter.backward_char();
while(!previous_iter.starts_line() && (*previous_iter == ' ' || previous_iter.ends_line() || is_comment_iter(previous_iter)) && previous_iter.backward_char()) {
while(!previous_iter.starts_line() && (*previous_iter == ' ' || previous_iter.ends_line() || !is_code_iter(previous_iter)) && previous_iter.backward_char()) {
}
if(previous_iter.starts_line())
return iter;
@ -1462,9 +1453,6 @@ long Source::View::symbol_count(Gtk::TextIter iter, unsigned int positive_char,
}
long curly_count = 0;
bool check_if_next_iter_is_code_iter = false;
if(positive_char == '\'' || negative_char == '\'' || positive_char == '"' || negative_char == '"')
check_if_next_iter_is_code_iter = true;
do {
if(*iter == positive_char && is_code_iter(iter))
@ -1478,14 +1466,6 @@ long Source::View::symbol_count(Gtk::TextIter iter, unsigned int positive_char,
}
else if(*iter == '}' && is_code_iter(iter))
curly_count--;
else if(check_if_next_iter_is_code_iter) {
auto next_iter = iter;
next_iter.forward_char();
if(*iter == positive_char && is_code_iter(next_iter))
symbol_count++;
else if(*iter == negative_char && is_code_iter(next_iter))
symbol_count--;
}
} while(iter.backward_char());
iter = iter_stored;
@ -1505,14 +1485,6 @@ long Source::View::symbol_count(Gtk::TextIter iter, unsigned int positive_char,
break;
curly_count--;
}
else if(check_if_next_iter_is_code_iter) {
auto next_iter = iter;
next_iter.forward_char();
if(*iter == positive_char && is_code_iter(next_iter))
symbol_count++;
else if(*iter == negative_char && is_code_iter(next_iter))
symbol_count--;
}
} while(iter.forward_char());
return symbol_count;
@ -2536,37 +2508,6 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
return false;
};
// Move right when clicking ' before a ' or when clicking " before a "
if(((key->keyval == GDK_KEY_apostrophe && *iter == '\'') ||
(key->keyval == GDK_KEY_quotedbl && *iter == '\"')) && is_code_iter(next_iter)) {
bool perform_move = false;
if(*previous_iter != '\\')
perform_move = true;
else {
auto it = previous_iter;
long backslash_count = 1;
while(it.backward_char() && *it == '\\') {
++backslash_count;
}
if(backslash_count % 2 == 0)
perform_move = true;
}
if(perform_move) {
get_buffer()->place_cursor(next_iter);
scroll_to(get_buffer()->get_insert());
return true;
}
}
// When to delete '' or ""
else if(key->keyval == GDK_KEY_BackSpace) {
if(((*previous_iter == '\'' && *iter == '\'') ||
(*previous_iter == '"' && *iter == '"')) && is_code_iter(previous_iter)) {
get_buffer()->erase(previous_iter, next_iter);
scroll_to(get_buffer()->get_insert());
return true;
}
}
if(is_code_iter(iter)) {
// Insert ()
if(key->keyval == GDK_KEY_parenleft && allow_insertion(iter)) {
@ -2590,7 +2531,7 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
return false;
}
}
// Move left on ] in []
// Move right on ] in []
else if(key->keyval == GDK_KEY_bracketright) {
if(*iter == ']' && symbol_count(iter, '[', ']') <= 0) {
iter.forward_char();
@ -2604,7 +2545,7 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
auto start_iter = get_start_of_expression(iter);
// Do not add } if { is at end of line and next line has a higher indentation
auto test_iter = iter;
while(!test_iter.ends_line() && (*test_iter == ' ' || *test_iter == '\t' || !is_code_iter(test_iter) || is_comment_iter(test_iter)) && test_iter.forward_char()) {
while(!test_iter.ends_line() && (*test_iter == ' ' || *test_iter == '\t' || !is_code_iter(test_iter)) && test_iter.forward_char()) {
}
if(test_iter.ends_line()) {
if(iter.get_line() + 1 < get_buffer()->get_line_count() && *start_iter != '(' && *start_iter != '[' && *start_iter != '{') {
@ -2648,7 +2589,7 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
}
return false;
}
// Move left on } in {}
// Move right on } in {}
else if(key->keyval == GDK_KEY_braceright) {
if(*iter == '}' && symbol_count(iter, '{', '}') <= 0) {
iter.forward_char();
@ -2675,6 +2616,12 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
scroll_to(get_buffer()->get_insert());
return true;
}
// Move right on last ' in '', or last " in ""
else if(((key->keyval == GDK_KEY_apostrophe && *iter == '\'') || (key->keyval == GDK_KEY_quotedbl && *iter == '\"')) && is_spellcheck_iter(iter)) {
get_buffer()->place_cursor(next_iter);
scroll_to(get_buffer()->get_insert());
return true;
}
// Insert ; at the end of line, if iter is at the last )
else if(key->keyval == GDK_KEY_semicolon) {
if(*iter == ')' && symbol_count(iter, '(', ')') <= 0 && next_iter.ends_line()) {
@ -2719,6 +2666,14 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
scroll_to(get_buffer()->get_insert());
return true;
}
// Delete '' or ""
else if(key->keyval == GDK_KEY_BackSpace) {
if((*previous_iter == '\'' && *iter == '\'') || (*previous_iter == '"' && *iter == '"')) {
get_buffer()->erase(previous_iter, next_iter);
scroll_to(get_buffer()->get_insert());
return true;
}
}
}
}
@ -3214,9 +3169,6 @@ Source::GenericView::GenericView(const boost::filesystem::path &file_path, const
configure();
spellcheck_all = true;
if(language)
get_source_buffer()->set_language(language);
auto completion = get_completion();
completion->property_show_headers() = false;
completion->property_show_icons() = false;

1
src/source.h

@ -158,7 +158,6 @@ namespace Source {
sigc::connection renderer_activate_connection;
bool is_bracket_language = false;
bool use_fixed_continuation_indenting = true;
bool is_cpp = false;
guint previous_non_modifier_keyval = 0;

13
src/source_base.cc

@ -16,6 +16,19 @@ Source::BaseView::BaseView(const boost::filesystem::path &file_path, const Glib:
});
monitor_file();
if(language) {
get_source_buffer()->set_language(language);
auto language_id = language->get_id();
if(language_id == "chdr" || language_id == "cpphdr" || language_id == "c" ||
language_id == "cpp" || language_id == "objc" || language_id == "java" ||
language_id == "js" || language_id == "ts" || language_id == "proto" ||
language_id == "c-sharp" || language_id == "html" || language_id == "cuda" ||
language_id == "php" || language_id == "rust" || language_id == "swift" ||
language_id == "go" || language_id == "scala" || language_id == "opencl" ||
language_id == "json" || language_id == "css")
is_bracket_language = true;
}
}
Source::BaseView::~BaseView() {

2
src/source_base.h

@ -52,6 +52,8 @@ namespace Source {
void monitor_file();
void check_last_write_time(std::time_t last_write_time_ = static_cast<std::time_t>(-1));
bool is_bracket_language = false;
/// Move iter to line start. Depending on iter position, before or after indentation.
/// Works with wrapped lines.
Gtk::TextIter get_smart_home_iter(const Gtk::TextIter &iter);

92
src/source_spellcheck.cc

@ -46,14 +46,14 @@ Source::SpellCheckView::SpellCheckView(const boost::filesystem::path &file_path,
return;
}
if(!is_code_iter(iter)) {
if(is_spellcheck_iter(iter)) {
if(last_keyval == GDK_KEY_Return || last_keyval == GDK_KEY_KP_Enter) {
auto previous_line_iter = iter;
while(previous_line_iter.backward_char() && !previous_line_iter.ends_line()) {
}
if(previous_line_iter.backward_char()) {
get_buffer()->remove_tag(spellcheck_error_tag, previous_line_iter, iter);
if(!is_code_iter(previous_line_iter)) {
if(is_spellcheck_iter(previous_line_iter)) {
auto word = get_word(previous_line_iter);
spellcheck_word(word.first, word.second);
}
@ -283,7 +283,7 @@ void Source::SpellCheckView::spellcheck() {
}
}
else {
bool spell_check = !is_code_iter(iter);
bool spell_check = is_spellcheck_iter(iter);
if(spell_check)
begin_spellcheck_iter = iter;
while(iter != get_buffer()->end()) {
@ -334,16 +334,16 @@ void Source::SpellCheckView::goto_next_spellcheck_error() {
Info::get().print("No spelling errors found in current buffer");
}
bool Source::SpellCheckView::is_code_iter(const Gtk::TextIter &iter) {
bool Source::SpellCheckView::is_spellcheck_iter(const Gtk::TextIter &iter) {
if(*iter == '\'') {
auto previous_iter = iter;
if(!iter.starts_line() && previous_iter.backward_char() && *previous_iter == '\'')
return false;
return true;
}
if(spellcheck_all) {
if(no_spell_check_tag) {
if(iter.has_tag(no_spell_check_tag) || iter.begins_tag(no_spell_check_tag) || iter.ends_tag(no_spell_check_tag))
return true;
return false;
// workaround for gtksourceview bug
if(iter.ends_line()) {
auto previous_iter = iter;
@ -352,7 +352,7 @@ bool Source::SpellCheckView::is_code_iter(const Gtk::TextIter &iter) {
auto next_iter = iter;
next_iter.forward_char();
if(next_iter.begins_tag(no_spell_check_tag) || next_iter.is_end())
return true;
return false;
}
}
}
@ -360,14 +360,14 @@ bool Source::SpellCheckView::is_code_iter(const Gtk::TextIter &iter) {
if(*iter == '\'' || *iter == '"') {
auto previous_iter = iter;
if(previous_iter.backward_char() && *previous_iter != '\'' && *previous_iter != '\"' && previous_iter.ends_tag(no_spell_check_tag))
return true;
return false;
}
}
return false;
return true;
}
if(comment_tag) {
if(iter.has_tag(comment_tag) && !iter.begins_tag(comment_tag))
return false;
return true;
//Exception at the end of /**/
else if(iter.ends_tag(comment_tag)) {
auto previous_iter = iter;
@ -379,32 +379,15 @@ bool Source::SpellCheckView::is_code_iter(const Gtk::TextIter &iter) {
}
auto next_iter = it;
if(it.begins_tag(comment_tag) && next_iter.forward_char() && *it == '/' && *next_iter == '*' && previous_iter != it)
return true;
}
}
return false;
}
}
if(string_tag) {
if(iter.has_tag(string_tag)) {
// When ending an open ''-string with ', the last '-iter is not correctly marked as end iter for string_tag
// For instance 'test, when inserting ' at end, would lead to spellcheck error of test'
if(*iter == '\'') {
long backslash_count = 0;
auto it = iter;
while(it.backward_char() && *it == '\\')
++backslash_count;
if(backslash_count % 2 == 0) {
auto it = iter;
while(!it.begins_tag(string_tag) && it.backward_to_tag_toggle(string_tag)) {
}
if(it.begins_tag(string_tag) && *it == '\'' && iter != it)
return true;
}
}
if(!iter.begins_tag(string_tag))
return false;
}
if(string_tag) {
if(iter.has_tag(string_tag) && !iter.begins_tag(string_tag))
return true;
// If iter is at the end of string_tag, with exception of after " and '
else if(iter.ends_tag(string_tag)) {
auto previous_iter = iter;
@ -419,17 +402,19 @@ bool Source::SpellCheckView::is_code_iter(const Gtk::TextIter &iter) {
while(!it.begins_tag(string_tag) && it.backward_to_tag_toggle(string_tag)) {
}
if(it.begins_tag(string_tag) && *previous_iter == *it && previous_iter != it)
return true;
return false;
}
}
return false;
return true;
}
}
}
return true;
return false;
}
bool Source::SpellCheckView::is_comment_iter(const Gtk::TextIter &iter) {
bool Source::SpellCheckView::is_code_iter(const Gtk::TextIter &iter) {
// Returns true, for instance for C++, if iter is at either characters of // or /*
const auto is_comment_iter = [this](const Gtk::TextIter &iter) {
if(!comment_tag)
return false;
if(iter.has_tag(comment_tag))
@ -445,6 +430,34 @@ bool Source::SpellCheckView::is_comment_iter(const Gtk::TextIter &iter) {
}
#endif
return false;
};
if(is_comment_iter(iter))
return false;
bool is_code_iter = !is_spellcheck_iter(iter);
// Treat closing " or ' as code iters
if(!is_code_iter && (*iter == '\'' || *iter == '"')) {
if(comment_tag && iter.ends_tag(comment_tag)) // ' or " at end of comments are not code iters
return false;
auto next_iter = iter;
next_iter.forward_char();
return !is_spellcheck_iter(next_iter);
}
if(is_bracket_language)
return is_code_iter;
// Non-bracket languages can have code iters inside (), [] and {}, while non-code iters outside of these brackets
// Do not threat these closing code brackets as code iters
if(is_code_iter && (*iter == ')' || *iter == ']' || *iter == '}')) {
auto next_iter = iter;
next_iter.forward_char();
return !is_spellcheck_iter(next_iter);
}
return is_code_iter;
}
bool Source::SpellCheckView::is_word_iter(const Gtk::TextIter &iter) {
@ -456,15 +469,8 @@ bool Source::SpellCheckView::is_word_iter(const Gtk::TextIter &iter) {
return false;
if(((*iter >= 'A' && *iter <= 'Z') || (*iter >= 'a' && *iter <= 'z') || *iter >= 128))
return true;
if(*iter == '\'') {
if(is_code_iter(iter))
return false;
auto next_iter = iter;
if(next_iter.forward_char() && is_code_iter(next_iter) &&
!(comment_tag && iter.ends_tag(comment_tag))) // additional check for end of line comment
return false;
return true;
}
if(*iter == '\'')
return !is_code_iter(iter);
return false;
}

8
src/source_spellcheck.h

@ -16,9 +16,13 @@ namespace Source {
void goto_next_spellcheck_error();
protected:
/// For instance, the iter before a closing " is a spellcheck iter, while an opening " is not a spellcheck iter.
/// Otherwise, strings and comments should return true.
bool is_spellcheck_iter(const Gtk::TextIter &iter);
/// For instance, both opening and closing " are code iters.
/// None of the comment characters, for instance //, are code iters.
/// Otherwise, strings and comments should return false.
bool is_code_iter(const Gtk::TextIter &iter);
/// Returns true, for instance for C++, if iter is at either characters of // or /*
bool is_comment_iter(const Gtk::TextIter &iter);
bool spellcheck_all = false;
guint last_keyval = 0;

40
tests/source_key_test.cc

@ -22,7 +22,6 @@ int main() {
auto language = language_manager->get_language("cpp");
Source::View view(source_file, language);
view.get_source_buffer()->set_highlight_syntax(true);
view.get_source_buffer()->set_language(language);
view.set_tab_char_and_size(' ', 2);
auto buffer = view.get_buffer();
event.keyval = GDK_KEY_Return;
@ -2004,7 +2003,6 @@ int main() {
auto language = language_manager->get_language("python");
Source::View view(source_file, language);
view.get_source_buffer()->set_highlight_syntax(true);
view.get_source_buffer()->set_language(language);
view.set_tab_char_and_size(' ', 2);
auto buffer = view.get_buffer();
event.keyval = GDK_KEY_Return;
@ -2022,7 +2020,6 @@ int main() {
auto language = language_manager->get_language("js");
Source::View view(source_file, language);
view.get_source_buffer()->set_highlight_syntax(true);
view.get_source_buffer()->set_language(language);
view.set_tab_char_and_size(' ', 2);
auto buffer = view.get_buffer();
event.keyval = GDK_KEY_Return;
@ -2274,4 +2271,41 @@ int main() {
g_assert(buffer->get_insert()->get_iter() == buffer->end());
}
}
{
auto language = language_manager->get_language("markdown");
Source::View view(source_file, language);
view.spellcheck_all = true;
view.get_source_buffer()->set_highlight_syntax(true);
view.set_tab_char_and_size(' ', 2);
auto buffer = view.get_buffer();
event.keyval = GDK_KEY_Return;
{
buffer->set_text("\n"
" * [test](https://test.org)\n");
while(Gtk::Main::events_pending())
Gtk::Main::iteration(false);
auto iter = buffer->get_iter_at_line(1);
iter.forward_to_line_end();
buffer->place_cursor(iter);
view.on_key_press_event(&event);
g_assert(buffer->get_text() == "\n"
" * [test](https://test.org)\n"
" \n");
iter = buffer->get_iter_at_line(2);
iter.forward_to_line_end();
g_assert(buffer->get_insert()->get_iter() == iter);
}
{
buffer->set_text("\n"
" * [test](https://test.org)");
while(Gtk::Main::events_pending())
Gtk::Main::iteration(false);
view.on_key_press_event(&event);
g_assert(buffer->get_text() == "\n"
" * [test](https://test.org)\n"
" ");
auto iter = buffer->end();
g_assert(buffer->get_insert()->get_iter() == iter);
}
}
}

Loading…
Cancel
Save