diff --git a/src/config.cc b/src/config.cc index 7a433fb..f41feb4 100644 --- a/src/config.cc +++ b/src/config.cc @@ -45,10 +45,9 @@ void MainConfig::GenerateSource() { auto source_cfg = Singleton::Config::source(); auto source_json = cfg.get_child("source"); - source_cfg->tab_size = source_json.get("tab_size"); - source_cfg->tab_char = source_json.get("tab_char"); - for(unsigned c=0;ctab_size;c++) - source_cfg->tab+=source_cfg->tab_char; + source_cfg->default_tab_char = source_json.get("default_tab_char"); + source_cfg->default_tab_size = source_json.get("default_tab_size"); + source_cfg->auto_tab_char_and_size = source_json.get("auto_tab_char_and_size"); source_cfg->highlight_current_line = source_json.get_value("highlight_current_line"); source_cfg->show_line_numbers = source_json.get_value("show_line_numbers"); diff --git a/src/files.h b/src/files.h index eea021b..1370fa9 100644 --- a/src/files.h +++ b/src/files.h @@ -23,8 +23,9 @@ const std::string configjson = " \"702\": \"def:statement\",\n" " \"705\": \"def:comment\"\n" " },\n" -" \"tab_size\": 2,\n" -" \"tab_char\": \" \", //Use \"\\t\" for regular tab\n" +" \"auto_tab_char_and_size\": true, //Use false to always use default tab char and size\n" +" \"default_tab_char\": \" \", //Use \"\\t\" for regular tab\n" +" \"default_tab_size\": 2,\n" " \"highlight_current_line\": true,\n" " \"show_line_numbers\": true\n" " },\n" diff --git a/src/source.cc b/src/source.cc index 1948282..06672c8 100644 --- a/src/source.cc +++ b/src/source.cc @@ -4,7 +4,6 @@ #include #include "logging.h" #include -#include #include "singletons.h" #include #include @@ -75,6 +74,29 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat property_show_line_numbers() = Singleton::Config::source()->show_line_numbers; if(Singleton::Config::source()->font.size()>0) override_font(Pango::FontDescription(Singleton::Config::source()->font)); + + tab_char=Singleton::Config::source()->default_tab_char; + tab_size=Singleton::Config::source()->default_tab_size; + if(Singleton::Config::source()->auto_tab_char_and_size) { + auto tab_char_and_size=find_tab_char_and_size(); + if(tab_char_and_size.first!=0) { + if(tab_char!=tab_char_and_size.first || tab_size!=tab_char_and_size.second) { + std::string tab_str; + if(tab_char_and_size.first==' ') + tab_str=""; + else + tab_str=""; + Singleton::terminal()->print("Tab char and size for file "+file_path.string()+" set to: "+tab_str+", "+boost::lexical_cast(tab_char_and_size.second)+".\n"); + } + + tab_char=tab_char_and_size.first; + tab_size=tab_char_and_size.second; + } + } + for(unsigned c=0;crequest_text([this](const Glib::ustring& text){ - const std::regex spaces_regex(std::string("^(")+Singleton::Config::source()->tab_char+"*)(.*)$"); auto line=get_line_before_insert(); std::smatch sm; std::string prefix_tabs; - if(!get_buffer()->get_has_selection() && std::regex_match(line, sm, spaces_regex) && sm[2].str().size()==0) { + if(!get_buffer()->get_has_selection() && std::regex_match(line, sm, tabs_regex) && sm[2].str().size()==0) { prefix_tabs=sm[1].str(); Glib::ustring::size_type start_line=0; @@ -177,7 +198,7 @@ void Source::View::paste() { std::string line=text.substr(start_line, end_line-start_line); size_t tabs=0; for(auto chr: line) { - if(chr==Singleton::Config::source()->tab_char) + if(chr==tab_char) tabs++; else break; @@ -260,21 +281,19 @@ string Source::View::get_line_before_insert() { //Basic indentation bool Source::View::on_key_press_event(GdkEventKey* key) { get_source_buffer()->begin_user_action(); - auto config=Singleton::Config::source(); - const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$"); //Indent as in next or previous line if(key->keyval==GDK_KEY_Return && key->state==0 && !get_buffer()->get_has_selection()) { auto insert_it=get_buffer()->get_insert()->get_iter(); int line_nr=insert_it.get_line(); auto line=get_line_before_insert(); std::smatch sm; - if(std::regex_match(line, sm, spaces_regex)) { + if(std::regex_match(line, sm, tabs_regex)) { if((line_nr+1)get_line_count()) { string next_line=get_line(line_nr+1); auto line_end_iter=get_buffer()->get_iter_at_line(line_nr+1); line_end_iter--; std::smatch sm2; - if(insert_it==line_end_iter && std::regex_match(next_line, sm2, spaces_regex)) { + if(insert_it==line_end_iter && std::regex_match(next_line, sm2, tabs_regex)) { if(sm2[1].str().size()>sm[1].str().size()) { get_source_buffer()->insert_at_cursor("\n"+sm2[1].str()); scroll_to(get_source_buffer()->get_insert()); @@ -297,7 +316,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { int line_end=selection_end.get_line(); for(int line=line_start;line<=line_end;line++) { Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line); - get_source_buffer()->insert(line_it, config->tab); + get_source_buffer()->insert(line_it, tab); } get_source_buffer()->end_user_action(); return true; @@ -309,11 +328,11 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { int line_start=selection_start.get_line(); int line_end=selection_end.get_line(); - unsigned indent_left_steps=config->tab_size; + unsigned indent_left_steps=tab_size; for(int line_nr=line_start;line_nr<=line_end;line_nr++) { string line=get_line(line_nr); std::smatch sm; - if(std::regex_match(line, sm, spaces_regex) && sm[1].str().size()>0) { + if(std::regex_match(line, sm, tabs_regex) && sm[1].str().size()>0) { indent_left_steps=std::min(indent_left_steps, (unsigned)sm[1].str().size()); } else { @@ -339,12 +358,12 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { int line_nr=insert_it.get_line(); auto line=get_line_before_insert(); std::smatch sm; - if(std::regex_match(line, sm, spaces_regex) && sm[1].str().size()==line.size()) { + if(std::regex_match(line, sm, tabs_regex) && sm[1].str().size()==line.size()) { if((line_nr-1)>=0) { string previous_line=get_line(line_nr-1); std::smatch sm2; - if(std::regex_match(previous_line, sm2, spaces_regex)) { - if(line.size()==sm2[1].str().size() || line.size()==sm2[1].str().size()+config->tab_size || line.size()==sm2[1].str().size()-config->tab_size) { + if(std::regex_match(previous_line, sm2, tabs_regex)) { + if(line.size()==sm2[1].str().size() || line.size()==sm2[1].str().size()+tab_size || line.size()==sm2[1].str().size()-tab_size) { auto previous_line_end_it=insert_it; for(unsigned c=0;c=config->tab_size) { + if(line.size()>=tab_size) { auto insert_minus_tab_it=insert_it; - for(unsigned c=0;ctab_size;c++) + for(unsigned c=0;cerase(insert_minus_tab_it, insert_it); get_source_buffer()->end_user_action(); @@ -371,6 +390,58 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { return stop; } +std::pair Source::View::find_tab_char_and_size() { + const std::regex indent_regex("^([ \t]+).*$"); + auto size=get_buffer()->get_line_count(); + std::unordered_map tab_chars; + std::unordered_map tab_sizes; + unsigned last_tab_size=0; + for(int c=0;c(str.size()-last_tab_size)); + if(tab_diff>0) { + unsigned tab_diff_unsigned=static_cast(tab_diff); + auto it_size=tab_sizes.find(tab_diff_unsigned); + if(it_size!=tab_sizes.end()) + it_size->second++; + else + tab_sizes[tab_diff_unsigned]=1; + } + + last_tab_size=str.size(); + + if(str.size()>0) { + auto it_char=tab_chars.find(str[0]); + if(it_char!=tab_chars.end()) + it_char->second++; + else + tab_chars[str[0]]=1; + } + } + } + char found_tab_char=0; + size_t occurences=0; + for(auto &tab_char: tab_chars) { + if(tab_char.second>occurences) { + found_tab_char=tab_char.first; + occurences=tab_char.second; + } + } + unsigned found_tab_size=0; + occurences=0; + for(auto &tab_size: tab_sizes) { + if(tab_size.second>occurences) { + found_tab_size=tab_size.first; + occurences=tab_size.second; + } + } + return {found_tab_char, found_tab_size}; +} + ///////////////////// //// GenericView //// ///////////////////// @@ -509,6 +580,10 @@ Source::View(file_path), project_path(project_path) { }); get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangViewParse::on_mark_set), false); + + bracket_regex=std::regex(std::string("^(")+tab_char+"*).*\\{ *$"); + no_bracket_statement_regex=std::regex(std::string("^(")+tab_char+"*)(if|for|else if|catch|while) *\\(.*[^;}] *$"); + no_bracket_no_para_statement_regex=std::regex(std::string("^(")+tab_char+"*)(else|try|do) *$"); } void Source::ClangViewParse::init_parse() { @@ -781,11 +856,6 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { return Source::View::on_key_press_event(key); } get_source_buffer()->begin_user_action(); - auto config=Singleton::Config::source(); - const std::regex bracket_regex(std::string("^(")+config->tab_char+"*).*\\{ *$"); - const std::regex no_bracket_statement_regex(std::string("^(")+config->tab_char+"*)(if|for|else if|catch|while) *\\(.*[^;}] *$"); - const std::regex no_bracket_no_para_statement_regex(std::string("^(")+config->tab_char+"*)(else|try|do) *$"); - const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$"); //Indent depending on if/else/etc and brackets if(key->keyval==GDK_KEY_Return && key->state==0) { @@ -796,18 +866,18 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { if((line_nr+1)get_line_count()) { string next_line=get_line(line_nr+1); std::smatch sm2; - if(std::regex_match(next_line, sm2, spaces_regex)) { - if(sm2[1].str()==sm[1].str()+config->tab) { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); + if(std::regex_match(next_line, sm2, tabs_regex)) { + if(sm2[1].str()==sm[1].str()+tab) { + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->end_user_action(); return true; } } if(next_line!=sm[1].str()+"}") { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab+"\n"+sm[1].str()+"}"); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab+"\n"+sm[1].str()+"}"); auto insert_it = get_source_buffer()->get_insert()->get_iter(); - for(size_t c=0;ctab_size+sm[1].str().size();c++) + for(size_t c=0;cget_insert()); get_source_buffer()->place_cursor(insert_it); @@ -815,7 +885,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { return true; } else { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->end_user_action(); return true; @@ -823,21 +893,21 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { } } else if(std::regex_match(line, sm, no_bracket_statement_regex)) { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->end_user_action(); return true; } else if(std::regex_match(line, sm, no_bracket_no_para_statement_regex)) { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->end_user_action(); return true; } - else if(std::regex_match(line, sm, spaces_regex)) { + else if(std::regex_match(line, sm, tabs_regex)) { std::smatch sm2; size_t line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); - if(line_nr>0 && sm[1].str().size()>=config->tab_size) { + if(line_nr>0 && sm[1].str().size()>=tab_size) { string previous_line=get_line(line_nr-1); if(!std::regex_match(previous_line, sm2, bracket_regex)) { if(std::regex_match(previous_line, sm2, no_bracket_statement_regex)) { @@ -859,9 +929,9 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { //Indent left when writing } on a new line else if(key->keyval==GDK_KEY_braceright) { string line=get_line_before_insert(); - if(line.size()>=config->tab_size) { + if(line.size()>=tab_size) { for(auto c: line) { - if(c!=config->tab_char) { + if(c!=tab_char) { get_source_buffer()->insert_at_cursor("}"); get_source_buffer()->end_user_action(); return true; @@ -870,7 +940,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { 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; - for(unsigned c=0;ctab_size;c++) + for(unsigned c=0;cerase(line_it, line_plus_it); diff --git a/src/source.h b/src/source.h index e76fb1e..ee4a4ec 100644 --- a/src/source.h +++ b/src/source.h @@ -14,6 +14,7 @@ #include "tooltips.h" #include "selectiondialog.h" #include +#include namespace Source { Glib::RefPtr guess_language(const boost::filesystem::path &file_path); @@ -22,9 +23,9 @@ namespace Source { public: std::string style; std::string font; - unsigned tab_size; - char tab_char; - std::string tab; + bool auto_tab_char_and_size; + char default_tab_char; + unsigned default_tab_size; bool highlight_current_line; bool show_line_numbers; std::unordered_map clang_types; @@ -79,6 +80,12 @@ namespace Source { std::string get_line_before_insert(); bool on_key_press_event(GdkEventKey* key); + + std::pair find_tab_char_and_size(); + unsigned tab_size; + char tab_char; + std::string tab; + std::regex tabs_regex; private: GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; @@ -109,6 +116,10 @@ namespace Source { std::shared_ptr parsing_in_progress; std::thread parse_thread; std::atomic parse_thread_stop; + + std::regex bracket_regex; + std::regex no_bracket_statement_regex; + std::regex no_bracket_no_para_statement_regex; private: std::map get_buffer_map() const; // inits the syntax highligthing on file open