diff --git a/src/menu.cc b/src/menu.cc index daea9fa..585cbf0 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -275,7 +275,7 @@ const Glib::ustring menu_xml= R"RAW( app.source_comments_toggle - _Add _Documentation (not yet implemented) + _Add _Documentation app.source_comments_add_documentation diff --git a/src/source.cc b/src/source.cc index 6c88619..3522248 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1244,6 +1244,25 @@ std::string Source::View::get_token(Gtk::TextIter iter) { return get_buffer()->get_text(start, end); } +void Source::View::cleanup_whitespace_characters_on_return(const Gtk::TextIter &iter) { + 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()) {} + if(!start_blank_iter.starts_line()) { + start_blank_iter.backward_char(); + while((*start_blank_iter==' ' || *start_blank_iter=='\t') && + !start_blank_iter.starts_line() && start_blank_iter.backward_char()) {} + if(*start_blank_iter!=' ' && *start_blank_iter!='\t') + start_blank_iter.forward_char(); + } + + if(start_blank_iter.starts_line()) + get_buffer()->erase(iter, end_blank_iter); + else + get_buffer()->erase(start_blank_iter, end_blank_iter); +} + bool Source::View::on_key_press_event(GdkEventKey* key) { if(SelectionDialog::get() && SelectionDialog::get()->is_visible()) { if(SelectionDialog::get()->on_key_press(key)) @@ -1327,24 +1346,6 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { get_buffer()->end_user_action(); return true; } - - if(get_buffer()->get_has_selection()) { - auto return_value=on_key_press_event_basic(key); - get_buffer()->end_user_action(); - if(return_value) - return true; - else - return Gsv::View::on_key_press_event(key); - } - - if(!is_code_iter(get_buffer()->get_insert()->get_iter())) { - auto return_value=on_key_press_event_basic(key); - get_buffer()->end_user_action(); - if(return_value) - return true; - else - return Gsv::View::on_key_press_event(key); - } if(is_bracket_language && on_key_press_event_bracket_language(key)) { get_buffer()->end_user_action(); @@ -1363,23 +1364,10 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { //Basic indentation bool Source::View::on_key_press_event_basic(GdkEventKey* key) { auto iter=get_buffer()->get_insert()->get_iter(); + //Indent as in next or previous line if((key->keyval==GDK_KEY_Return || key->keyval==GDK_KEY_KP_Enter) && !get_buffer()->get_has_selection() && !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.starts_line() && start_blank_iter.backward_char()) {} - - if(start_blank_iter.starts_line() && (*start_blank_iter==' ' || *start_blank_iter=='\t')) - get_buffer()->erase(iter, end_blank_iter); - else { - start_blank_iter.forward_char(); - get_buffer()->erase(start_blank_iter, end_blank_iter); - } + cleanup_whitespace_characters_on_return(iter); iter=get_buffer()->get_insert()->get_iter(); auto tabs=get_line_before(get_tabs_end_iter(iter)); @@ -1595,22 +1583,39 @@ bool Source::View::on_key_press_event_basic(GdkEventKey* key) { //Bracket language indentation bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { auto iter=get_buffer()->get_insert()->get_iter(); + + if(get_buffer()->get_has_selection()) + return false; + + if(!is_code_iter(iter)) { + // Add * at start of line in comment blocks + 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(); + auto start_iter=get_tabs_end_iter(iter.get_line()); + auto end_iter=start_iter; + end_iter.forward_chars(2); + auto start_of_sentence=get_buffer()->get_text(start_iter, end_iter); + if(!start_of_sentence.empty()) { + if(start_of_sentence=="/*" || start_of_sentence[0]=='*') { + auto tabs=get_line_before(start_iter); + auto insert_str="\n"+tabs; + if(start_of_sentence[0]=='/') + insert_str+=' '; + insert_str+="* "; + + get_buffer()->insert_at_cursor(insert_str); + return true; + } + } + } + return false; + } + //Indent depending on if/else/etc and brackets if((key->keyval==GDK_KEY_Return || key->keyval==GDK_KEY_KP_Enter) && !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); + cleanup_whitespace_characters_on_return(iter); iter=get_buffer()->get_insert()->get_iter(); auto previous_iter=iter; @@ -1627,6 +1632,22 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) { else start_iter=get_tabs_end_iter(get_buffer()->get_iter_at_line(find_start_of_sentence(start_iter).get_line())); auto tabs=get_line_before(start_iter); + + /* + * Change tabs after ending comment block with an extra space (as in this case) + */ + if(tabs.size()%tab_size==1) { + iter=get_buffer()->get_insert()->get_iter(); + auto tabs_end_iter=get_tabs_end_iter(iter); + if(!tabs_end_iter.ends_line() && !is_code_iter(tabs_end_iter)) { + auto end_of_line_iter=tabs_end_iter; + end_of_line_iter.forward_to_line_end(); + auto line=get_buffer()->get_text(tabs_end_iter, end_of_line_iter); + if(!line.empty() && line.compare(0, 2, "*/")==0) + tabs.pop_back(); + } + } + if(*previous_iter=='{') { Gtk::TextIter found_iter; bool found_right_bracket=find_close_curly_bracket_forward(iter, found_iter); diff --git a/src/source.h b/src/source.h index f329231..e5787e5 100644 --- a/src/source.h +++ b/src/source.h @@ -77,7 +77,7 @@ namespace Source { std::function goto_next_diagnostic; std::function()> get_fix_its; std::function toggle_comments; - std::function add_documentation; + std::function()> get_documentation_template; std::function toggle_breakpoint; Gtk::TextIter get_iter_for_dialog(); @@ -136,6 +136,8 @@ namespace Source { std::string get_token(Gtk::TextIter iter); + void cleanup_whitespace_characters_on_return(const Gtk::TextIter &iter); + const static std::regex bracket_regex; const static std::regex no_bracket_statement_regex; const static std::regex no_bracket_no_para_statement_regex; diff --git a/src/source_clang.cc b/src/source_clang.cc index 69b8968..32c6e5f 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -1403,6 +1403,50 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file Info::get().print("No fix-its found in current buffer"); return fix_its; }; + + get_documentation_template=[this]() { + if(!parsed) { + Info::get().print("Buffer is parsing"); + return std::tuple(Source::Offset(), "", 0); + } + auto identifier=get_identifier(); + if(identifier) { + auto cursor=identifier.cursor.get_canonical(); + if(!clang_Range_isNull(clang_Cursor_getCommentRange(cursor.cx_cursor))) { + Info::get().print("Symbol is already documented"); + return std::tuple(Source::Offset(), "", 0); + } + auto clang_offsets=cursor.get_source_range().get_offsets(); + auto source_offset=Offset(clang_offsets.first.line-1, 0, cursor.get_source_location().get_path()); + std::string tabs; + for(size_t c=0;c(source_offset, documentation, iter_offset); + } + else { + Info::get().print("No symbol found at current cursor location"); + return std::tuple(Source::Offset(), "", 0); + } + }; } Source::ClangViewRefactor::Identifier Source::ClangViewRefactor::get_identifier() { diff --git a/src/window.cc b/src/window.cc index ead4f30..935e658 100644 --- a/src/window.cc +++ b/src/window.cc @@ -651,8 +651,23 @@ void Window::set_menu_actions() { }); menu.add_action("source_comments_add_documentation", [this]() { if(auto view=Notebook::get().get_current_view()) { - if(view->add_documentation) { - view->add_documentation(); + if(view->get_documentation_template) { + auto documentation_template=view->get_documentation_template(); + auto offset=std::get<0>(documentation_template); + if(offset) { + boost::system::error_code ec; + auto canonical_path=boost::filesystem::canonical(offset.file_path, ec); + if(ec) + return; + Notebook::get().open(canonical_path); + auto view=Notebook::get().get_current_view(); + auto iter=view->get_buffer()->get_iter_at_line_index(offset.line, offset.index); + view->get_buffer()->insert(iter, std::get<1>(documentation_template)); + iter=view->get_buffer()->get_iter_at_line_index(offset.line, offset.index); + iter.forward_chars(std::get<2>(documentation_template)); + view->get_buffer()->place_cursor(iter); + view->scroll_to_cursor_delayed(view, true, false); + } } } }); @@ -1174,18 +1189,18 @@ void Window::activate_menu_items() { menu.actions["source_goto_line"]->set_enabled(view); menu.actions["source_center_cursor"]->set_enabled(view); - menu.actions["source_indentation_auto_indent_buffer"]->set_enabled(view && static_cast(view->format_style)); - menu.actions["source_comments_toggle"]->set_enabled(view && static_cast(view->toggle_comments)); - menu.actions["source_comments_add_documentation"]->set_enabled(view && static_cast(view->add_documentation)); - menu.actions["source_find_documentation"]->set_enabled(view && static_cast(view->get_token_data)); - menu.actions["source_goto_declaration"]->set_enabled(view && static_cast(view->get_declaration_location)); - menu.actions["source_goto_implementation"]->set_enabled(view && static_cast(view->get_implementation_locations)); - menu.actions["source_goto_usage"]->set_enabled(view && static_cast(view->get_usages)); - menu.actions["source_goto_method"]->set_enabled(view && static_cast(view->get_methods)); - menu.actions["source_rename"]->set_enabled(view && static_cast(view->rename_similar_tokens)); - menu.actions["source_implement_method"]->set_enabled(view && static_cast(view->get_method)); - menu.actions["source_goto_next_diagnostic"]->set_enabled(view && static_cast(view->goto_next_diagnostic)); - menu.actions["source_apply_fix_its"]->set_enabled(view && static_cast(view->get_fix_its)); + menu.actions["source_indentation_auto_indent_buffer"]->set_enabled(view && view->format_style); + menu.actions["source_comments_toggle"]->set_enabled(view && view->toggle_comments); + menu.actions["source_comments_add_documentation"]->set_enabled(view && view->get_documentation_template); + menu.actions["source_find_documentation"]->set_enabled(view && view->get_token_data); + menu.actions["source_goto_declaration"]->set_enabled(view && view->get_declaration_location); + menu.actions["source_goto_implementation"]->set_enabled(view && view->get_implementation_locations); + menu.actions["source_goto_usage"]->set_enabled(view && view->get_usages); + menu.actions["source_goto_method"]->set_enabled(view && view->get_methods); + menu.actions["source_rename"]->set_enabled(view && view->rename_similar_tokens); + menu.actions["source_implement_method"]->set_enabled(view && view->get_method); + menu.actions["source_goto_next_diagnostic"]->set_enabled(view && view->goto_next_diagnostic); + menu.actions["source_apply_fix_its"]->set_enabled(view && view->get_fix_its); #ifdef JUCI_ENABLE_DEBUG Project::debug_activate_menu_items(); #endif