diff --git a/src/source.cc b/src/source.cc index fbecfc9..7c73e9d 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1270,8 +1270,11 @@ Gtk::TextIter Source::View::find_start_of_sentence(Gtk::TextIter iter) { square_count--; else if(*iter=='{' && is_code_iter(iter)) curly_count++; - else if(*iter=='}' && is_code_iter(iter)) + else if(*iter=='}' && is_code_iter(iter)) { curly_count--; + if(iter.starts_line()) + break; + } if(curly_count>0) break; @@ -1334,18 +1337,18 @@ bool Source::View::find_open_curly_bracket_backward(Gtk::TextIter iter, Gtk::Tex return false; } -bool Source::View::find_close_curly_bracket_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter) { +bool Source::View::find_close_symbol_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter, unsigned int positive_char, unsigned int negative_char) { long count=0; do { - if(*iter=='}' && is_code_iter(iter)) { + if(*iter==negative_char && is_code_iter(iter)) { if(count==0) { found_iter=iter; return true; } count--; } - else if(*iter=='{' && is_code_iter(iter)) + else if(*iter==positive_char && is_code_iter(iter)) count++; } while(iter.forward_char()); return false; @@ -1875,7 +1878,7 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { return false; } - // get iter for if expressions below, which is moved backwards past any comment + // Get iter for if expressions below, which is moved backwards past any comment auto get_condition_iter=[this](const Gtk::TextIter &iter) { auto condition_iter=iter; condition_iter.backward_char(); @@ -1892,7 +1895,7 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { return condition_iter; }; - //Indent depending on if/else/etc and brackets + // Indent depending on if/else/etc and brackets if((key->keyval==GDK_KEY_Return || key->keyval==GDK_KEY_KP_Enter) && !iter.starts_line()) { cleanup_whitespace_characters_on_return(iter); iter=get_buffer()->get_insert()->get_iter(); @@ -1930,14 +1933,14 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { Gtk::TextIter found_iter; // Check if an '}' is needed bool has_right_curly_bracket=false; - bool found_right_bracket=find_close_curly_bracket_forward(iter, found_iter); + bool found_right_bracket=find_close_symbol_forward(iter, found_iter, '{', '}'); 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_right_curly_bracket=true; } - // special case for functions and classes with no indentation after: namespace { + // Special case for functions and classes with no indentation after: namespace { if(tabs.empty() && has_right_curly_bracket) has_right_curly_bracket=symbol_count(iter, '{', '}')!=1; @@ -2016,12 +2019,76 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { return true; } } + // Special indentation of [ and ( for JavaScript and JSON + if(language && (language->get_id()=="js" || language->get_id()=="json")) { + unsigned int open_symbol=0, close_symbol=0; + if(*condition_iter=='[') { + open_symbol='['; + close_symbol=']'; + } + else if(*condition_iter=='(') { + open_symbol='('; + close_symbol=')'; + } + if(open_symbol!=0 && is_code_iter(condition_iter)) { + Gtk::TextIter found_iter; + // Check if an ']' is needed + bool has_right_bracket=false; + bool found_right_bracket=find_close_symbol_forward(iter, found_iter, open_symbol, close_symbol); + 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_right_bracket=true; + } + + if(*get_buffer()->get_insert()->get_iter()==close_symbol) { + get_buffer()->insert_at_cursor("\n"+tabs+tab+"\n"+tabs); + auto insert_it = get_buffer()->get_insert()->get_iter(); + if(insert_it.backward_chars(tabs.size()+1)) { + scroll_to(get_buffer()->get_insert()); + get_buffer()->place_cursor(insert_it); + } + return true; + } + else if(!has_right_bracket) { + //Insert new lines with bracket end + get_buffer()->insert_at_cursor("\n"+tabs+tab+"\n"+tabs+static_cast(close_symbol)); + auto insert_it = get_buffer()->get_insert()->get_iter(); + if(insert_it.backward_chars(tabs.size()+2)) { + scroll_to(get_buffer()->get_insert()); + get_buffer()->place_cursor(insert_it); + } + return true; + } + else { + get_buffer()->insert_at_cursor("\n"+tabs+tab); + scroll_to(get_buffer()->get_insert()); + return true; + } + } + + // JavaScript: simplified indentations inside brackets, after for example: + // [\n 1, 2, 3,\n + // return (\n + // ReactDOM.render(\n
\n + if(open_non_curly_bracket_iter_found && (*open_non_curly_bracket_iter=='[' || *open_non_curly_bracket_iter=='(')) { + if(condition_iter.get_line()==open_non_curly_bracket_iter.get_line()) + tabs=get_line_before(start_iter)+tab; + else { + start_iter=get_tabs_end_iter(get_buffer()->get_iter_at_line(condition_iter.get_line())); + tabs=get_line_before(start_iter); + } + get_buffer()->insert_at_cursor("\n"+tabs); + scroll_to(get_buffer()->get_insert()); + return true; + } + } - //Indent multiline expressions + // Indent multiline expressions if(open_non_curly_bracket_iter_found) { - auto tabs_end_iter=get_tabs_end_iter(open_non_curly_bracket_iter); - auto tabs=get_line_before(get_tabs_end_iter(open_non_curly_bracket_iter)); - auto iter=tabs_end_iter; + auto iter=get_tabs_end_iter(open_non_curly_bracket_iter); + auto tabs=get_line_before(iter); while(iter<=open_non_curly_bracket_iter) { tabs+=' '; iter.forward_char(); @@ -2030,16 +2097,18 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { scroll_to(get_buffer()->get_insert()); return true; } + auto after_condition_iter=condition_iter; after_condition_iter.forward_char(); std::string sentence=get_buffer()->get_text(start_iter, after_condition_iter); std::smatch sm; + // Indenting after for instance: if(...)\n if(std::regex_match(sentence, sm, no_bracket_statement_regex)) { get_buffer()->insert_at_cursor("\n"+tabs+tab); scroll_to(get_buffer()->get_insert()); return true; } - //Indenting after for instance if(...)\n...;\n + // Indenting after for instance: if(...)\n...;\n else if(*condition_iter==';' && condition_iter.get_line()>0 && is_code_iter(condition_iter)) { auto previous_end_iter=start_iter; while(previous_end_iter.backward_char() && !previous_end_iter.ends_line()) {} @@ -2056,7 +2125,7 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { return true; } } - //Indenting after ':' + // Indenting after ':' else if(*condition_iter==':' && is_code_iter(condition_iter)) { bool perform_indent=true; auto iter=condition_iter; @@ -2090,7 +2159,7 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { scroll_to(get_buffer()->get_insert()); return true; } - //Indent left when writing } on a new line + // 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 && iter.ends_line()) { @@ -2112,7 +2181,7 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { } } } - //Indent left when writing { on a new line after for instance if(...)\n... + // Indent left when writing { on a new line after for instance if(...)\n... else if(key->keyval==GDK_KEY_braceleft) { auto tabs_end_iter=get_tabs_end_iter(); auto tabs=get_line_before(tabs_end_iter); diff --git a/src/source.h b/src/source.h index d4493ec..db6e8e6 100644 --- a/src/source.h +++ b/src/source.h @@ -117,7 +117,7 @@ namespace Source { Gtk::TextIter find_start_of_sentence(Gtk::TextIter iter); bool find_open_non_curly_bracket_backward(Gtk::TextIter iter, Gtk::TextIter &found_iter); bool find_open_curly_bracket_backward(Gtk::TextIter iter, Gtk::TextIter &found_iter); - bool find_close_curly_bracket_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter); + bool find_close_symbol_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter, unsigned int positive_char, unsigned int negative_char); long symbol_count(Gtk::TextIter iter, unsigned int positive_char, unsigned int negative_char); bool is_templated_function(Gtk::TextIter iter, Gtk::TextIter &parenthesis_end_iter);