diff --git a/src/source.cc b/src/source.cc index a06b1d1..edc9616 100644 --- a/src/source.cc +++ b/src/source.cc @@ -293,9 +293,15 @@ Source::View::View(const boost::filesystem::path &file_path, const boost::filesy } set_tab_char_and_size(tab_char, tab_size); + bracket_regex=boost::regex("^([ \\t]*).*\\{ *$"); + no_bracket_statement_regex=boost::regex("^([ \\t]*)(if|for|else if|while) *\\(.*[^;}] *$"); + no_bracket_no_para_statement_regex=boost::regex("^([ \\t]*)(else) *$"); + if(language && (language->get_id()=="chdr" || language->get_id()=="cpphdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc" || language->get_id()=="java" || language->get_id()=="js" || language->get_id()=="ts" || language->get_id()=="proto")) { + is_bracket_language=true; + auto_indent=[this]() { auto command=Config::get().terminal.clang_format_command; bool use_style_file=false; @@ -1041,8 +1047,15 @@ bool Source::View::find_left_bracket_backward(Gtk::TextIter iter, Gtk::TextIter return false; } -//Basic indentation bool Source::View::on_key_press_event(GdkEventKey* key) { + if(is_bracket_language) + return on_key_press_event_bracket_language(key); + else + return on_key_press_event_basic(key); +} + +//Basic indentation +bool Source::View::on_key_press_event_basic(GdkEventKey* key) { if(spellcheck_suggestions_dialog && spellcheck_suggestions_dialog->shown) { if(spellcheck_suggestions_dialog->on_key_press(key)) return true; @@ -1270,6 +1283,215 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { return stop; } +//Bracket language indentation +bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { + if(spellcheck_suggestions_dialog && spellcheck_suggestions_dialog->shown) { + if(spellcheck_suggestions_dialog->on_key_press(key)) + return true; + } + + auto iter=get_buffer()->get_insert()->get_iter(); + if(iter.backward_char() && (get_source_buffer()->iter_has_context_class(iter, "comment") || get_source_buffer()->iter_has_context_class(iter, "string"))) + return on_key_press_event_basic(key); + + if(get_buffer()->get_has_selection()) { + return on_key_press_event_basic(key); + } + get_source_buffer()->begin_user_action(); + iter=get_buffer()->get_insert()->get_iter(); + //Indent depending on if/else/etc and brackets + if(key->keyval==GDK_KEY_Return && !iter.starts_line()) { + //First remove spaces or tabs around cursor + auto start_blank_iter=iter; + auto end_blank_iter=iter; + while((*end_blank_iter==' ' || *end_blank_iter=='\t') && + !end_blank_iter.ends_line() && end_blank_iter.forward_char()) {} + start_blank_iter.backward_char(); + while((*start_blank_iter==' ' || *start_blank_iter=='\t' || start_blank_iter.ends_line()) && + !start_blank_iter.starts_line() && start_blank_iter.backward_char()) {} + if(!start_blank_iter.starts_line()) { + start_blank_iter.forward_char(); + get_buffer()->erase(start_blank_iter, end_blank_iter); + } + else + get_buffer()->erase(iter, end_blank_iter); + iter=get_buffer()->get_insert()->get_iter(); + + Gtk::TextIter start_of_sentence_iter; + if(find_start_of_closed_expression(iter, start_of_sentence_iter)) { + auto start_sentence_tabs_end_iter=get_tabs_end_iter(start_of_sentence_iter); + auto tabs=get_line_before(start_sentence_tabs_end_iter); + + boost::smatch sm; + if(iter.backward_char() && *iter=='{') { + auto found_iter=iter; + bool found_right_bracket=find_right_bracket_forward(iter, found_iter); + + bool has_bracket=false; + if(found_right_bracket) { + auto tabs_end_iter=get_tabs_end_iter(found_iter); + auto line_tabs=get_line_before(tabs_end_iter); + if(tabs.size()==line_tabs.size()) + has_bracket=true; + } + if(*get_buffer()->get_insert()->get_iter()=='}') { + get_source_buffer()->insert_at_cursor("\n"+tabs+tab+"\n"+tabs); + auto insert_it = get_source_buffer()->get_insert()->get_iter(); + if(insert_it.backward_chars(tabs.size()+1)) { + scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->place_cursor(insert_it); + } + get_source_buffer()->end_user_action(); + return true; + } + else if(!has_bracket) { + //Insert new lines with bracket end + get_source_buffer()->insert_at_cursor("\n"+tabs+tab+"\n"+tabs+"}"); + auto insert_it = get_source_buffer()->get_insert()->get_iter(); + if(insert_it.backward_chars(tabs.size()+2)) { + scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->place_cursor(insert_it); + } + get_source_buffer()->end_user_action(); + return true; + } + else { + get_source_buffer()->insert_at_cursor("\n"+tabs+tab); + scroll_to(get_buffer()->get_insert()); + get_source_buffer()->end_user_action(); + return true; + } + } + auto line=get_line_before(); + iter=get_buffer()->get_insert()->get_iter(); + auto found_iter=iter; + if(find_open_expression_symbol(iter, start_of_sentence_iter, found_iter)) { + auto tabs_end_iter=get_tabs_end_iter(found_iter); + tabs=get_line_before(tabs_end_iter); + auto iter=tabs_end_iter; + while(iter<=found_iter) { + tabs+=' '; + iter.forward_char(); + } + } + else if(boost::regex_match(line, sm, no_bracket_statement_regex)) { + get_source_buffer()->insert_at_cursor("\n"+tabs+tab); + scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->end_user_action(); + return true; + } + else if(boost::regex_match(line, sm, no_bracket_no_para_statement_regex)) { + get_source_buffer()->insert_at_cursor("\n"+tabs+tab); + scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->end_user_action(); + return true; + } + //Indenting after for instance if(...)\n...;\n + else if(iter.backward_char() && *iter==';') { + boost::smatch sm2; + size_t line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); + if(line_nr>0 && tabs.size()>=tab_size) { + std::string previous_line=get_line(line_nr-1); + if(!boost::regex_match(previous_line, sm2, bracket_regex)) { + if(boost::regex_match(previous_line, sm2, no_bracket_statement_regex)) { + get_source_buffer()->insert_at_cursor("\n"+sm2[1].str()); + scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->end_user_action(); + return true; + } + else if(boost::regex_match(previous_line, sm2, no_bracket_no_para_statement_regex)) { + get_source_buffer()->insert_at_cursor("\n"+sm2[1].str()); + scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->end_user_action(); + return true; + } + } + } + } + //Indenting after ':' + else if(*iter==':') { + Gtk::TextIter left_bracket_iter; + if(find_left_bracket_backward(iter, left_bracket_iter)) { + if(!left_bracket_iter.ends_line()) + left_bracket_iter.forward_char(); + Gtk::TextIter start_of_left_bracket_sentence_iter; + if(find_start_of_closed_expression(left_bracket_iter, start_of_left_bracket_sentence_iter)) { + boost::smatch sm; + auto tabs_end_iter=get_tabs_end_iter(start_of_left_bracket_sentence_iter); + auto tabs_start_of_sentence=get_line_before(tabs_end_iter); + if(tabs.size()==(tabs_start_of_sentence.size()+tab_size)) { + auto start_line_iter=get_buffer()->get_iter_at_line(iter.get_line()); + auto start_line_plus_tab_size=start_line_iter; + for(size_t c=0;cerase(start_line_iter, start_line_plus_tab_size); + } + else { + get_source_buffer()->insert_at_cursor("\n"+tabs+tab); + scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->end_user_action(); + return true; + } + } + } + } + get_source_buffer()->insert_at_cursor("\n"+tabs); + scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->end_user_action(); + return true; + } + } + //Indent left when writing } on a new line + else if(key->keyval==GDK_KEY_braceright) { + std::string line=get_line_before(); + if(line.size()>=tab_size) { + for(auto c: line) { + if(c!=tab_char) { + get_source_buffer()->insert_at_cursor("}"); + get_source_buffer()->end_user_action(); + return true; + } + } + Gtk::TextIter insert_it = get_source_buffer()->get_insert()->get_iter(); + Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(insert_it.get_line()); + Gtk::TextIter line_plus_it=line_it; + line_plus_it.forward_chars(tab_size); + get_source_buffer()->erase(line_it, line_plus_it); + } + get_source_buffer()->insert_at_cursor("}"); + get_source_buffer()->end_user_action(); + return true; + } + //Indent left when writing { on a new line after for instance if(...)\n... + else if(key->keyval==GDK_KEY_braceleft) { + auto iter=get_buffer()->get_insert()->get_iter(); + auto tabs_end_iter=get_tabs_end_iter(); + auto tabs=get_line_before(tabs_end_iter); + size_t line_nr=iter.get_line(); + if(line_nr>0 && tabs.size()>=tab_size && iter==tabs_end_iter) { + std::string previous_line=get_line(line_nr-1); + boost::smatch sm; + if(!boost::regex_match(previous_line, sm, bracket_regex)) { + auto start_iter=iter; + start_iter.backward_chars(tab_size); + if(boost::regex_match(previous_line, sm, no_bracket_statement_regex) || + boost::regex_match(previous_line, sm, no_bracket_no_para_statement_regex)) { + if((tabs.size()-tab_size)==sm[1].str().size()) { + get_buffer()->erase(start_iter, iter); + get_buffer()->insert_at_cursor("{"); + scroll_to(get_buffer()->get_insert()); + get_buffer()->end_user_action(); + return true; + } + } + } + } + } + + get_source_buffer()->end_user_action(); + return on_key_press_event_basic(key); +} + bool Source::View::on_button_press_event(GdkEventButton *event) { if(event->type==GDK_2BUTTON_PRESS) { Gtk::TextIter start, end; diff --git a/src/source.h b/src/source.h index 2da18b5..e9050c3 100644 --- a/src/source.h +++ b/src/source.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "selectiondialog.h" #include "tooltips.h" @@ -136,7 +137,14 @@ namespace Source { bool find_right_bracket_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter); bool find_left_bracket_backward(Gtk::TextIter iter, Gtk::TextIter &found_iter); + boost::regex bracket_regex; + boost::regex no_bracket_statement_regex; + boost::regex no_bracket_no_para_statement_regex; + bool on_key_press_event(GdkEventKey* key) override; + bool on_key_press_event_basic(GdkEventKey* key); + bool on_key_press_event_bracket_language(GdkEventKey* key); + bool is_bracket_language=false; bool on_button_press_event(GdkEventButton *event) override; std::pair find_tab_char_and_size(); diff --git a/src/source_clang.cc b/src/source_clang.cc index 439aeb4..3454322 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -70,10 +70,6 @@ void Source::ClangViewParse::configure() { JINFO("Style " + item.second + " not found in " + scheme->get_name()); } } - - bracket_regex=boost::regex("^([ \\t]*).*\\{ *$"); - no_bracket_statement_regex=boost::regex("^([ \\t]*)(if|for|else if|while) *\\(.*[^;}] *$"); - no_bracket_no_para_statement_regex=boost::regex("^([ \\t]*)(else) *$"); } void Source::ClangViewParse::parse_initialize() { @@ -451,215 +447,6 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) //type_tooltips.show(rectangle); } -//Clang indentation. -bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { - if(spellcheck_suggestions_dialog && spellcheck_suggestions_dialog->shown) { - if(spellcheck_suggestions_dialog->on_key_press(key)) - return true; - } - - auto iter=get_buffer()->get_insert()->get_iter(); - if(iter.backward_char() && (get_source_buffer()->iter_has_context_class(iter, "comment") || get_source_buffer()->iter_has_context_class(iter, "string"))) - return Source::View::on_key_press_event(key); - - if(get_buffer()->get_has_selection()) { - return Source::View::on_key_press_event(key); - } - get_source_buffer()->begin_user_action(); - iter=get_buffer()->get_insert()->get_iter(); - //Indent depending on if/else/etc and brackets - if(key->keyval==GDK_KEY_Return && !iter.starts_line()) { - //First remove spaces or tabs around cursor - auto start_blank_iter=iter; - auto end_blank_iter=iter; - while((*end_blank_iter==' ' || *end_blank_iter=='\t') && - !end_blank_iter.ends_line() && end_blank_iter.forward_char()) {} - start_blank_iter.backward_char(); - while((*start_blank_iter==' ' || *start_blank_iter=='\t' || start_blank_iter.ends_line()) && - !start_blank_iter.starts_line() && start_blank_iter.backward_char()) {} - if(!start_blank_iter.starts_line()) { - start_blank_iter.forward_char(); - get_buffer()->erase(start_blank_iter, end_blank_iter); - } - else - get_buffer()->erase(iter, end_blank_iter); - iter=get_buffer()->get_insert()->get_iter(); - - Gtk::TextIter start_of_sentence_iter; - if(find_start_of_closed_expression(iter, start_of_sentence_iter)) { - auto start_sentence_tabs_end_iter=get_tabs_end_iter(start_of_sentence_iter); - auto tabs=get_line_before(start_sentence_tabs_end_iter); - - boost::smatch sm; - if(iter.backward_char() && *iter=='{') { - auto found_iter=iter; - bool found_right_bracket=find_right_bracket_forward(iter, found_iter); - - bool has_bracket=false; - if(found_right_bracket) { - auto tabs_end_iter=get_tabs_end_iter(found_iter); - auto line_tabs=get_line_before(tabs_end_iter); - if(tabs.size()==line_tabs.size()) - has_bracket=true; - } - if(*get_buffer()->get_insert()->get_iter()=='}') { - get_source_buffer()->insert_at_cursor("\n"+tabs+tab+"\n"+tabs); - auto insert_it = get_source_buffer()->get_insert()->get_iter(); - if(insert_it.backward_chars(tabs.size()+1)) { - scroll_to(get_source_buffer()->get_insert()); - get_source_buffer()->place_cursor(insert_it); - } - get_source_buffer()->end_user_action(); - return true; - } - else if(!has_bracket) { - //Insert new lines with bracket end - get_source_buffer()->insert_at_cursor("\n"+tabs+tab+"\n"+tabs+"}"); - auto insert_it = get_source_buffer()->get_insert()->get_iter(); - if(insert_it.backward_chars(tabs.size()+2)) { - scroll_to(get_source_buffer()->get_insert()); - get_source_buffer()->place_cursor(insert_it); - } - get_source_buffer()->end_user_action(); - return true; - } - else { - get_source_buffer()->insert_at_cursor("\n"+tabs+tab); - scroll_to(get_buffer()->get_insert()); - get_source_buffer()->end_user_action(); - return true; - } - } - auto line=get_line_before(); - iter=get_buffer()->get_insert()->get_iter(); - auto found_iter=iter; - if(find_open_expression_symbol(iter, start_of_sentence_iter, found_iter)) { - auto tabs_end_iter=get_tabs_end_iter(found_iter); - tabs=get_line_before(tabs_end_iter); - auto iter=tabs_end_iter; - while(iter<=found_iter) { - tabs+=' '; - iter.forward_char(); - } - } - else if(boost::regex_match(line, sm, no_bracket_statement_regex)) { - get_source_buffer()->insert_at_cursor("\n"+tabs+tab); - scroll_to(get_source_buffer()->get_insert()); - get_source_buffer()->end_user_action(); - return true; - } - else if(boost::regex_match(line, sm, no_bracket_no_para_statement_regex)) { - get_source_buffer()->insert_at_cursor("\n"+tabs+tab); - scroll_to(get_source_buffer()->get_insert()); - get_source_buffer()->end_user_action(); - return true; - } - //Indenting after for instance if(...)\n...;\n - else if(iter.backward_char() && *iter==';') { - boost::smatch sm2; - size_t line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); - if(line_nr>0 && tabs.size()>=tab_size) { - std::string previous_line=get_line(line_nr-1); - if(!boost::regex_match(previous_line, sm2, bracket_regex)) { - if(boost::regex_match(previous_line, sm2, no_bracket_statement_regex)) { - get_source_buffer()->insert_at_cursor("\n"+sm2[1].str()); - scroll_to(get_source_buffer()->get_insert()); - get_source_buffer()->end_user_action(); - return true; - } - else if(boost::regex_match(previous_line, sm2, no_bracket_no_para_statement_regex)) { - get_source_buffer()->insert_at_cursor("\n"+sm2[1].str()); - scroll_to(get_source_buffer()->get_insert()); - get_source_buffer()->end_user_action(); - return true; - } - } - } - } - //Indenting after ':' - else if(*iter==':') { - Gtk::TextIter left_bracket_iter; - if(find_left_bracket_backward(iter, left_bracket_iter)) { - if(!left_bracket_iter.ends_line()) - left_bracket_iter.forward_char(); - Gtk::TextIter start_of_left_bracket_sentence_iter; - if(find_start_of_closed_expression(left_bracket_iter, start_of_left_bracket_sentence_iter)) { - boost::smatch sm; - auto tabs_end_iter=get_tabs_end_iter(start_of_left_bracket_sentence_iter); - auto tabs_start_of_sentence=get_line_before(tabs_end_iter); - if(tabs.size()==(tabs_start_of_sentence.size()+tab_size)) { - auto start_line_iter=get_buffer()->get_iter_at_line(iter.get_line()); - auto start_line_plus_tab_size=start_line_iter; - for(size_t c=0;cerase(start_line_iter, start_line_plus_tab_size); - } - else { - get_source_buffer()->insert_at_cursor("\n"+tabs+tab); - scroll_to(get_source_buffer()->get_insert()); - get_source_buffer()->end_user_action(); - return true; - } - } - } - } - get_source_buffer()->insert_at_cursor("\n"+tabs); - scroll_to(get_source_buffer()->get_insert()); - get_source_buffer()->end_user_action(); - return true; - } - } - //Indent left when writing } on a new line - else if(key->keyval==GDK_KEY_braceright) { - std::string line=get_line_before(); - if(line.size()>=tab_size) { - for(auto c: line) { - if(c!=tab_char) { - get_source_buffer()->insert_at_cursor("}"); - get_source_buffer()->end_user_action(); - return true; - } - } - Gtk::TextIter insert_it = get_source_buffer()->get_insert()->get_iter(); - Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(insert_it.get_line()); - Gtk::TextIter line_plus_it=line_it; - line_plus_it.forward_chars(tab_size); - get_source_buffer()->erase(line_it, line_plus_it); - } - get_source_buffer()->insert_at_cursor("}"); - get_source_buffer()->end_user_action(); - return true; - } - //Indent left when writing { on a new line after for instance if(...)\n... - else if(key->keyval==GDK_KEY_braceleft) { - auto iter=get_buffer()->get_insert()->get_iter(); - auto tabs_end_iter=get_tabs_end_iter(); - auto tabs=get_line_before(tabs_end_iter); - size_t line_nr=iter.get_line(); - if(line_nr>0 && tabs.size()>=tab_size && iter==tabs_end_iter) { - std::string previous_line=get_line(line_nr-1); - boost::smatch sm; - if(!boost::regex_match(previous_line, sm, bracket_regex)) { - auto start_iter=iter; - start_iter.backward_chars(tab_size); - if(boost::regex_match(previous_line, sm, no_bracket_statement_regex) || - boost::regex_match(previous_line, sm, no_bracket_no_para_statement_regex)) { - if((tabs.size()-tab_size)==sm[1].str().size()) { - get_buffer()->erase(start_iter, iter); - get_buffer()->insert_at_cursor("{"); - scroll_to(get_buffer()->get_insert()); - get_buffer()->end_user_action(); - return true; - } - } - } - } - } - - get_source_buffer()->end_user_action(); - return Source::View::on_key_press_event(key); -} - ////////////////////////////// //// ClangViewAutocomplete /// ////////////////////////////// @@ -720,7 +507,7 @@ bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { if(autocomplete_dialog->on_key_press(key)) return true; } - return ClangViewParse::on_key_press_event(key); + return View::on_key_press_event(key); } void Source::ClangViewAutocomplete::autocomplete_dialog_setup() { diff --git a/src/source_clang.h b/src/source_clang.h index c29d863..18c9690 100644 --- a/src/source_clang.h +++ b/src/source_clang.h @@ -5,7 +5,6 @@ #include #include #include -#include #include "clangmm.h" #include "source.h" #include "terminal.h" @@ -42,12 +41,6 @@ namespace Source { void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle) override; void show_type_tooltips(const Gdk::Rectangle &rectangle) override; - bool on_key_press_event(GdkEventKey* key) override; - - boost::regex bracket_regex; - boost::regex no_bracket_statement_regex; - boost::regex no_bracket_no_para_statement_regex; - std::set diagnostic_offsets; std::vector fix_its;