From 32a27c91b111f85d7deefffc86b9909408e866fe Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 1 Sep 2015 13:19:26 +0200 Subject: [PATCH 01/37] Trying to find where juci crashes about once a day on OS X. Also fixed tooltip-newlines. --- src/directories.cc | 10 +++++++ src/notebook.cc | 18 ++++++------ src/selectiondialog.cc | 9 ++++-- src/source.cc | 62 +++++++++++++++++++----------------------- src/sourcefile.cc | 4 +-- src/terminal.cc | 9 +++--- src/tooltips.cc | 23 ++++++++-------- src/window.cc | 6 ++-- 8 files changed, 75 insertions(+), 66 deletions(-) diff --git a/src/directories.cc b/src/directories.cc index 00332cc..8bfbdda 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -68,6 +68,7 @@ Directories::Directories() : stop_update_thread(false) { }); update_dispatcher.connect([this](){ + DEBUG("start"); update_mutex.lock(); for(auto &path: update_paths) { if(last_write_times.count(path)>0) @@ -75,11 +76,13 @@ Directories::Directories() : stop_update_thread(false) { } update_paths.clear(); update_mutex.unlock(); + DEBUG("end"); }); update_thread=std::thread([this](){ while(!stop_update_thread) { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + DEBUG("start"); update_mutex.lock(); if(update_paths.size()==0) { for(auto it=last_write_times.begin();it!=last_write_times.end();) { @@ -101,6 +104,7 @@ Directories::Directories() : stop_update_thread(false) { update_dispatcher(); } update_mutex.unlock(); + DEBUG("end"); } }); } @@ -138,14 +142,17 @@ void Directories::open(const boost::filesystem::path& dir_path) { } void Directories::update() { + DEBUG("start"); update_mutex.lock(); for(auto &last_write_time: last_write_times) { add_path(last_write_time.first, last_write_time.second.first); } update_mutex.unlock(); + DEBUG("end"); } void Directories::select(const boost::filesystem::path &path) { + DEBUG("start"); if(current_path=="") return; @@ -185,6 +192,7 @@ void Directories::select(const boost::filesystem::path &path) { } return false; }); + DEBUG("end"); } bool Directories::ignored(std::string path) { @@ -204,6 +212,7 @@ bool Directories::ignored(std::string path) { } void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) { + DEBUG("start"); last_write_times[dir_path.string()]={parent, boost::filesystem::last_write_time(dir_path)}; std::unique_ptr children; //Gtk::TreeNodeChildren is missing default constructor... if(parent) @@ -257,4 +266,5 @@ void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::T auto child=tree_store->append(*children); child->set_value(column_record.name, std::string("(empty)")); } + DEBUG("end"); } diff --git a/src/notebook.cc b/src/notebook.cc index 4462d69..a733cd9 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -28,15 +28,11 @@ int Notebook::size() { } Source::View* Notebook::get_view(int page) { - if(page>=size()) - return nullptr; return source_views.at(page); } Source::View* Notebook::get_current_view() { INFO("Getting sourceview"); - if(get_current_page()==-1) - return nullptr; return get_view(get_current_page()); } @@ -163,25 +159,29 @@ bool Notebook::save_current() { } bool Notebook::close_current_page() { + DEBUG("start"); INFO("Notebook close page"); - if (size() != 0) { + if (get_current_page()!=-1) { if(get_current_view()->get_buffer()->get_modified()){ - if(!save_modified_dialog()) + if(!save_modified_dialog()) { + DEBUG("end false"); return false; + } } int page = get_current_page(); remove_page(page); if(get_current_page()==-1) Singleton::status()->set_text(""); auto source_view=source_views.at(page); - source_views.erase(source_views.begin()+ page); - scrolled_windows.erase(scrolled_windows.begin()+page); - hboxes.erase(hboxes.begin()+page); if(auto source_clang_view=dynamic_cast(source_view)) source_clang_view->async_delete(); else delete source_view; + source_views.erase(source_views.begin()+ page); + scrolled_windows.erase(scrolled_windows.begin()+page); + hboxes.erase(hboxes.begin()+page); } + DEBUG("end true"); return true; } diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index 816041a..e6742e9 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -210,7 +210,8 @@ void SelectionDialog::show() { else { auto last_it=list_view_text.get_model()->children().end(); last_it--; - list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); + if(last_it) + list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); } return true; } @@ -269,7 +270,8 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { else { auto last_it=list_view_text.get_model()->children().end(); last_it--; - list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); + if(last_it) + list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); } return true; } @@ -418,7 +420,8 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) { else { auto last_it=list_view_text.get_model()->children().end(); last_it--; - list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); + if(last_it) + list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); } select(false); update_tooltips(); diff --git a/src/source.cc b/src/source.cc index 41d9fbf..abcd2dc 100644 --- a/src/source.cc +++ b/src/source.cc @@ -485,8 +485,7 @@ void Source::View::set_status(const std::string &status) { string Source::View::get_line(size_t line_number) { Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_number); Gtk::TextIter line_end_it = line_it; - while(!line_end_it.ends_line()) - line_end_it++; + while(!line_end_it.ends_line() && line_end_it.forward_char()) {} std::string line(get_source_buffer()->get_text(line_it, line_end_it)); return line; } @@ -516,14 +515,15 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { 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, 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()); - get_source_buffer()->end_user_action(); - return true; + if(line_end_iter.backward_char()) { + std::smatch sm2; + 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()); + get_source_buffer()->end_user_action(); + return true; + } } } } @@ -570,9 +570,8 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr); Gtk::TextIter line_plus_it=line_it; - for(unsigned c=0;cerase(line_it, line_plus_it); + if(indent_left_steps==0 || line_plus_it.forward_chars(indent_left_steps)) + get_source_buffer()->erase(line_it, line_plus_it); } get_source_buffer()->end_user_action(); return true; @@ -590,10 +589,8 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { 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;cerase(previous_line_end_it, insert_it); + if(previous_line_end_it.backward_chars(line.size()+1)) + get_source_buffer()->erase(previous_line_end_it, insert_it); get_source_buffer()->end_user_action(); return true; } @@ -601,9 +598,8 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { } if(line.size()>=tab_size) { auto insert_minus_tab_it=insert_it; - for(unsigned c=0;cerase(insert_minus_tab_it, insert_it); + if(tab_size==0 || insert_minus_tab_it.backward_chars(tab_size)) + get_source_buffer()->erase(insert_minus_tab_it, insert_it); get_source_buffer()->end_user_action(); return true; } @@ -1097,20 +1093,20 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { if(next_char!='}' && next_line.substr(0, next_line_with_end_bracket.size())!=next_line_with_end_bracket) { 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;cget_insert()); - get_source_buffer()->place_cursor(insert_it); + if(insert_it.backward_chars(sm[1].str().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 if(next_char=='}') { 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;cget_insert()); - get_source_buffer()->place_cursor(insert_it); + if(insert_it.backward_chars(sm[1].str().size()+1)) { + scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->place_cursor(insert_it); + } get_source_buffer()->end_user_action(); return true; } @@ -1170,10 +1166,8 @@ 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;cerase(line_it, line_plus_it); + if(tab_size==0 || 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(); @@ -1285,8 +1279,8 @@ void Source::ClangViewAutocomplete::autocomplete() { autocomplete_starting=false; if(!autocomplete_cancel_starting) { auto start_iter=get_buffer()->get_insert()->get_iter(); - for(size_t c=0;c0 && !start_iter.backward_chars(prefix.size())) + return; completion_dialog=std::unique_ptr(new CompletionDialog(*this, get_buffer()->create_mark(start_iter))); auto rows=std::make_shared >(); completion_dialog->on_hide=[this](){ diff --git a/src/sourcefile.cc b/src/sourcefile.cc index 260a5fb..b853796 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -70,9 +70,7 @@ bool juci::filesystem::write(const std::string &path, Glib::RefPtrinsert_with_tag(get_buffer()->end(), message, bold_tag); else @@ -293,15 +293,16 @@ int Terminal::print(const std::string &message, bool bold){ get_buffer()->delete_mark(mark); } + DEBUG("end"); return get_buffer()->end().get_line(); } void Terminal::print(int line_nr, const std::string &message){ - INFO("Terminal: PrintMessage at line " << line_nr); + DEBUG("start"); auto iter=get_buffer()->get_iter_at_line(line_nr); - while(!iter.ends_line()) - iter++; + while(!iter.ends_line() && iter.forward_char()) {} get_buffer()->insert(iter, message); + DEBUG("end"); } std::shared_ptr Terminal::print_in_progress(std::string start_msg) { diff --git a/src/tooltips.cc b/src/tooltips.cc index 21696ef..20d2dcb 100644 --- a/src/tooltips.cc +++ b/src/tooltips.cc @@ -1,6 +1,9 @@ #include "tooltips.h" #include "singletons.h" +#include +using namespace std; + namespace sigc { template struct functor_trait { @@ -28,12 +31,10 @@ void Tooltip::update() { auto end_iter=end_mark->get_iter(); text_view.get_iter_location(iter, activation_rectangle); if(iter.get_offset() text_buffer) { last_space=iter; if(*iter=='\n') { end=true; - iter++; + iter.forward_char(); break; } - iter++; + iter.forward_char(); } if(!end) { while(!last_space && iter) { //If no space (word longer than 80) - iter++; + iter.forward_char(); if(iter && *iter==' ') last_space=iter; } if(iter && last_space) { auto mark=text_buffer->create_mark(last_space); - auto iter_mark=text_buffer->create_mark(iter); - auto last_space_p=last_space++; - text_buffer->erase(last_space, last_space_p); + auto last_space_p=last_space; + last_space.forward_char(); + text_buffer->erase(last_space_p, last_space); text_buffer->insert(mark->get_iter(), "\n"); - iter=iter_mark->get_iter(); + iter=mark->get_iter(); + iter.forward_char(); text_buffer->delete_mark(mark); - text_buffer->delete_mark(iter_mark); } } } diff --git a/src/window.cc b/src/window.cc index f831b51..188defb 100644 --- a/src/window.cc +++ b/src/window.cc @@ -214,7 +214,8 @@ void Window::create_menu() { if(notebook.get_current_page()!=-1) { while(gtk_events_pending()) gtk_main_iteration(); - notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5); } }); menu.action_group->add(Gtk::Action::create("SourceGotoDeclaration", "Go to Declaration"), Gtk::AccelKey(menu.key_map["source_goto_declaration"]), [this]() { @@ -226,7 +227,8 @@ void Window::create_menu() { notebook.get_current_view()->get_buffer()->place_cursor(notebook.get_current_view()->get_buffer()->get_iter_at_line_index(location.second.line-1, location.second.index-1)); while(gtk_events_pending()) gtk_main_iteration(); - notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5); } } } From 72cb162ba125be44fbb318de1dd3494ba06fbecf Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Tue, 1 Sep 2015 13:50:36 +0200 Subject: [PATCH 02/37] Added check after going through gtk_events. --- src/window.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/window.cc b/src/window.cc index 188defb..2fea9b4 100644 --- a/src/window.cc +++ b/src/window.cc @@ -650,7 +650,8 @@ void Window::goto_line_entry() { buffer->place_cursor(buffer->get_iter_at_line(line)); while(gtk_events_pending()) gtk_main_iteration(); - notebook.get_current_view()->scroll_to(buffer->get_insert(), 0.0, 1.0, 0.5); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->scroll_to(buffer->get_insert(), 0.0, 1.0, 0.5); } } catch(const std::exception &e) {} From f14332eac47cb632376277bff634e0d1c6855931 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Tue, 1 Sep 2015 14:08:01 +0200 Subject: [PATCH 03/37] Fixed the elusive crash. --- src/notebook.cc | 4 +++- src/window.cc | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/notebook.cc b/src/notebook.cc index a733cd9..27addd0 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -104,8 +104,10 @@ void Notebook::open(const boost::filesystem::path &file_path) { }); get_current_view()->on_update_status=[this](Source::View* view, const std::string &status) { - if(get_current_view()==view) + if(get_current_page()!=-1 && get_current_view()==view) Singleton::status()->set_text(status); + else + Singleton::status()->set_text(""); }; } diff --git a/src/window.cc b/src/window.cc index 2fea9b4..1f3fcca 100644 --- a/src/window.cc +++ b/src/window.cc @@ -80,6 +80,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil }); notebook.signal_switch_page().connect([this](Gtk::Widget* page, guint page_num) { + DEBUG("start"); if(notebook.get_current_page()!=-1) { if(search_entry_shown && entry_box.labels.size()>0) { notebook.get_current_view()->update_search_occurrences=[this](int number){ @@ -108,6 +109,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil Singleton::status()->set_text(notebook.get_current_view()->status); } + DEBUG("end"); }); notebook.signal_page_removed().connect([this](Gtk::Widget* page, guint page_num) { entry_box.hide(); From e45b0b121191eaccc5242c0516c3c99e71a335cf Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 1 Sep 2015 14:16:24 +0200 Subject: [PATCH 04/37] Now updating status field when closing tabs. --- src/window.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/window.cc b/src/window.cc index 1f3fcca..e7004eb 100644 --- a/src/window.cc +++ b/src/window.cc @@ -325,6 +325,8 @@ void Window::create_menu() { }); menu.action_group->add(Gtk::Action::create("WindowCloseTab", "Close Tab"), Gtk::AccelKey(menu.key_map["close_tab"]), [this]() { notebook.close_current_page(); + if(notebook.get_current_page()!=-1) + Singleton::status()->set_text(notebook.get_current_view()->status); }); menu.action_group->add(Gtk::Action::create("HelpAbout", "About"), [this] () { about.show(); From 594a926dcddc101aa972c5ec0287d5cf555b5610 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 1 Sep 2015 14:27:13 +0200 Subject: [PATCH 05/37] More fixes to status. --- src/notebook.cc | 2 -- src/window.cc | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/notebook.cc b/src/notebook.cc index 27addd0..84dd2a9 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -172,8 +172,6 @@ bool Notebook::close_current_page() { } int page = get_current_page(); remove_page(page); - if(get_current_page()==-1) - Singleton::status()->set_text(""); auto source_view=source_views.at(page); if(auto source_clang_view=dynamic_cast(source_view)) source_clang_view->async_delete(); diff --git a/src/window.cc b/src/window.cc index e7004eb..6ae39b2 100644 --- a/src/window.cc +++ b/src/window.cc @@ -327,6 +327,8 @@ void Window::create_menu() { notebook.close_current_page(); if(notebook.get_current_page()!=-1) Singleton::status()->set_text(notebook.get_current_view()->status); + else + Singleton::status()->set_text(""); }); menu.action_group->add(Gtk::Action::create("HelpAbout", "About"), [this] () { about.show(); From 242a6ca963af4e3927c7c02059c2447516f05f87 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 2 Sep 2015 07:54:59 +0200 Subject: [PATCH 06/37] Fixed crash when closing a tab real quick after moving cursor. --- src/directories.cc | 15 +++------------ src/notebook.cc | 18 ++++++++---------- src/selectiondialog.cc | 3 --- src/source.cc | 24 ++++++++++++++---------- src/source.h | 2 ++ src/terminal.cc | 11 +++++------ src/tooltips.cc | 1 - src/window.cc | 13 ++----------- 8 files changed, 34 insertions(+), 53 deletions(-) diff --git a/src/directories.cc b/src/directories.cc index 8bfbdda..50ae0ee 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -19,7 +19,7 @@ namespace sigc { } Directories::Directories() : stop_update_thread(false) { - DEBUG("adding treeview to scrolledwindow"); + DEBUG("start"); add(tree_view); set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); tree_store = Gtk::TreeStore::create(column_record); @@ -30,7 +30,6 @@ Directories::Directories() : stop_update_thread(false) { tree_view.set_search_column(column_record.name); tree_view.signal_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column){ - INFO("Directory navigation"); auto iter = tree_store->get_iter(path); if (iter) { auto path_str=iter->get_value(column_record.path); @@ -68,7 +67,6 @@ Directories::Directories() : stop_update_thread(false) { }); update_dispatcher.connect([this](){ - DEBUG("start"); update_mutex.lock(); for(auto &path: update_paths) { if(last_write_times.count(path)>0) @@ -76,13 +74,11 @@ Directories::Directories() : stop_update_thread(false) { } update_paths.clear(); update_mutex.unlock(); - DEBUG("end"); }); update_thread=std::thread([this](){ while(!stop_update_thread) { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - DEBUG("start"); update_mutex.lock(); if(update_paths.size()==0) { for(auto it=last_write_times.begin();it!=last_write_times.end();) { @@ -104,7 +100,6 @@ Directories::Directories() : stop_update_thread(false) { update_dispatcher(); } update_mutex.unlock(); - DEBUG("end"); } }); } @@ -115,11 +110,10 @@ Directories::~Directories() { } void Directories::open(const boost::filesystem::path& dir_path) { + DEBUG("start"); if(dir_path=="") return; - INFO("Open folder"); - tree_store->clear(); update_mutex.lock(); last_write_times.clear(); @@ -138,7 +132,7 @@ void Directories::open(const boost::filesystem::path& dir_path) { current_path=dir_path; - DEBUG("Folder opened"); + DEBUG("end"); } void Directories::update() { @@ -196,7 +190,6 @@ void Directories::select(const boost::filesystem::path &path) { } bool Directories::ignored(std::string path) { - DEBUG("Checking if file-/directory is filtered"); std::transform(path.begin(), path.end(), path.begin(), ::tolower); for(std::string &i : Singleton::Config::directories()->exceptions) { @@ -212,7 +205,6 @@ bool Directories::ignored(std::string path) { } void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) { - DEBUG("start"); last_write_times[dir_path.string()]={parent, boost::filesystem::last_write_time(dir_path)}; std::unique_ptr children; //Gtk::TreeNodeChildren is missing default constructor... if(parent) @@ -266,5 +258,4 @@ void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::T auto child=tree_store->append(*children); child->set_value(column_record.name, std::string("(empty)")); } - DEBUG("end"); } diff --git a/src/notebook.cc b/src/notebook.cc index 84dd2a9..6a72c55 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -32,13 +32,11 @@ Source::View* Notebook::get_view(int page) { } Source::View* Notebook::get_current_view() { - INFO("Getting sourceview"); return get_view(get_current_page()); } void Notebook::open(const boost::filesystem::path &file_path) { - INFO("Notebook open file"); - INFO("Notebook create page"); + DEBUG("start"); for(int c=0;cfile_path) { set_current_page(c); @@ -106,14 +104,16 @@ void Notebook::open(const boost::filesystem::path &file_path) { get_current_view()->on_update_status=[this](Source::View* view, const std::string &status) { if(get_current_page()!=-1 && get_current_view()==view) Singleton::status()->set_text(status); - else - Singleton::status()->set_text(""); }; + DEBUG("end"); } bool Notebook::save(int page) { - if(page>=size()) + DEBUG("start"); + if(page>=size()) { + DEBUG("end false"); return false; + } auto view=get_view(page); if (view->file_path != "" && view->get_buffer()->get_modified()) { if(juci::filesystem::write(view->file_path, view->get_buffer())) { @@ -145,16 +145,16 @@ bool Notebook::save(int page) { } } } - + DEBUG("end true"); return true; } Singleton::terminal()->print("Error: could not save file " +view->file_path.string()+"\n"); } + DEBUG("end false"); return false; } bool Notebook::save_current() { - INFO("Notebook save current file"); if(get_current_page()==-1) return false; return save(get_current_page()); @@ -162,7 +162,6 @@ bool Notebook::save_current() { bool Notebook::close_current_page() { DEBUG("start"); - INFO("Notebook close page"); if (get_current_page()!=-1) { if(get_current_view()->get_buffer()->get_modified()){ if(!save_modified_dialog()) { @@ -186,7 +185,6 @@ bool Notebook::close_current_page() { } bool Notebook::save_modified_dialog() { - INFO("Notebook::save_modified_dialog"); Gtk::MessageDialog dialog((Gtk::Window&)(*get_toplevel()), "Save file!", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO); dialog.set_secondary_text("Do you want to save: " + get_current_view()->file_path.string()+" ?"); int result = dialog.run(); diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index e6742e9..f55fdaa 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -117,7 +117,6 @@ void SelectionDialogBase::update_tooltips() { } void SelectionDialogBase::move() { - INFO("SelectionDialog set position"); Gdk::Rectangle rectangle; text_view.get_iter_location(start_mark->get_iter(), rectangle); int buffer_x=rectangle.get_x(); @@ -130,8 +129,6 @@ void SelectionDialogBase::move() { } void SelectionDialogBase::resize() { - INFO("SelectionDialog set size"); - if(list_view_text.get_realized()) { int row_width=0, row_height; Gdk::Rectangle rect; diff --git a/src/source.cc b/src/source.cc index abcd2dc..4a1502a 100644 --- a/src/source.cc +++ b/src/source.cc @@ -326,6 +326,9 @@ Source::View::~View() { g_clear_object(&search_context); g_clear_object(&search_settings); + delayed_tooltips_connection.disconnect(); + delayed_spellcheck_suggestions_connection.disconnect(); + if(spellcheck_checker!=NULL) delete_aspell_speller(spellcheck_checker); } @@ -755,6 +758,7 @@ clang::Index Source::ClangViewParse::clang_index(0, 0); Source::ClangViewParse::ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path): Source::View(file_path), project_path(project_path) { + DEBUG("start"); auto scheme = get_source_buffer()->get_style_scheme(); auto tag_table=get_buffer()->get_tag_table(); for (auto &item : Singleton::Config::source()->clang_types) { @@ -762,7 +766,6 @@ Source::View(file_path), project_path(project_path) { auto style = scheme->get_style(item.second); auto tag = get_source_buffer()->create_tag(item.second); if (style) { - DEBUG("Style " + item.second + " found in style " + scheme->get_name()); if (style->property_foreground_set()) tag->property_foreground() = style->property_foreground(); if (style->property_background_set()) @@ -774,10 +777,9 @@ Source::View(file_path), project_path(project_path) { // // if (style->property_line_background_set()) tag->property_line_background() = style->property_line_background(); // // if (style->property_underline_set()) tag->property_underline() = style->property_underline(); } else - DEBUG("Style " + item.second + " not found in " + scheme->get_name()); + INFO("Style " + item.second + " not found in " + scheme->get_name()); } } - INFO("Tagtable filled"); parsing_in_progress=Singleton::terminal()->print_in_progress("Parsing "+file_path.string()); //GTK-calls must happen in main thread, so the parse_thread @@ -793,14 +795,12 @@ Source::View(file_path), project_path(project_path) { parse_done.connect([this](){ if(parse_thread_mapped) { if(parsing_mutex.try_lock()) { - INFO("Updating syntax"); update_syntax(); update_diagnostics(); update_types(); source_readable=true; set_status(""); parsing_mutex.unlock(); - INFO("Syntax updated"); } parsing_in_progress->done("done"); } @@ -819,12 +819,16 @@ Source::View(file_path), project_path(project_path) { 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) *$"); + DEBUG("end"); +} + +Source::ClangViewParse::~ClangViewParse() { + delayed_reparse_connection.disconnect(); } void Source::ClangViewParse::init_parse() { type_tooltips.hide(); diagnostic_tooltips.hide(); - get_buffer()->remove_all_tags(get_buffer()->begin(), get_buffer()->end()); source_readable=false; parse_thread_go=true; parse_thread_mapped=false; @@ -1272,7 +1276,6 @@ void Source::ClangViewAutocomplete::autocomplete() { if(!autocomplete_starting) { autocomplete_starting=true; autocomplete_cancel_starting=false; - INFO("Source::ClangViewAutocomplete::autocomplete getting autocompletions"); std::shared_ptr > ac_data=std::make_shared >(); autocomplete_done_connection.disconnect(); autocomplete_done_connection=autocomplete_done.connect([this, ac_data](){ @@ -1368,7 +1371,6 @@ void Source::ClangViewAutocomplete::autocomplete() { std::vector Source::ClangViewAutocomplete:: get_autocomplete_suggestions(int line_number, int column, std::map& buffer_map) { - INFO("Getting auto complete suggestions"); std::vector suggestions; auto results=clang_tu->get_code_completions(buffer_map, line_number, column); if(!autocomplete_cancel_starting) { @@ -1394,8 +1396,6 @@ get_autocomplete_suggestions(int line_number, int column, std::map language): ClangViewRefactor(file_path, project_path) { if(language) { get_source_buffer()->set_highlight_syntax(true); diff --git a/src/source.h b/src/source.h index 3abf39b..c89b365 100644 --- a/src/source.h +++ b/src/source.h @@ -124,6 +124,7 @@ namespace Source { class ClangViewParse : public View { public: ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); + ~ClangViewParse(); boost::filesystem::path project_path; void start_reparse(); bool start_reparse_needed=false; @@ -187,6 +188,7 @@ namespace Source { class ClangViewRefactor : public ClangViewAutocomplete { public: ClangViewRefactor(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); + ~ClangViewRefactor(); private: Glib::RefPtr similar_tokens_tag; std::string last_similar_tokens_tagged; diff --git a/src/terminal.cc b/src/terminal.cc index bdeb66b..addce65 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -154,6 +154,7 @@ Terminal::Terminal() { } int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { + DEBUG("start"); int stdin_fd, stdout_fd, stderr_fd; auto pid=popen3(command, path.string(), &stdin_fd, &stdout_fd, &stderr_fd); @@ -176,7 +177,6 @@ int Terminal::execute(const std::string &command, const boost::filesystem::path std::thread stdout_thread([this, stdout_fd](){ char buffer[1024]; ssize_t n; - INFO("read"); while ((n=read(stdout_fd, buffer, 1024)) > 0) { std::string message; for(ssize_t c=0;c callback) { std::thread async_execute_thread([this, command, path, callback](){ + DEBUG("start"); int stdin_fd, stdout_fd, stderr_fd; async_executes_mutex.lock(); stdin_buffer.clear(); @@ -225,7 +227,6 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem std::thread stdout_thread([this, stdout_fd](){ char buffer[1024]; ssize_t n; - INFO("read"); while ((n=read(stdout_fd, buffer, 1024)) > 0) { std::string message; for(ssize_t c=0;cinsert_with_tag(get_buffer()->end(), message, bold_tag); else @@ -293,16 +295,13 @@ int Terminal::print(const std::string &message, bool bold){ get_buffer()->delete_mark(mark); } - DEBUG("end"); return get_buffer()->end().get_line(); } void Terminal::print(int line_nr, const std::string &message){ - DEBUG("start"); auto iter=get_buffer()->get_iter_at_line(line_nr); while(!iter.ends_line() && iter.forward_char()) {} get_buffer()->insert(iter, message); - DEBUG("end"); } std::shared_ptr Terminal::print_in_progress(std::string start_msg) { diff --git a/src/tooltips.cc b/src/tooltips.cc index 20d2dcb..904af36 100644 --- a/src/tooltips.cc +++ b/src/tooltips.cc @@ -93,7 +93,6 @@ void Tooltip::adjust(bool disregard_drawn) { } void Tooltip::wrap_lines(Glib::RefPtr text_buffer) { - INFO("Tooltip::wrap_lines"); auto iter=text_buffer->begin(); while(iter) { diff --git a/src/window.cc b/src/window.cc index 6ae39b2..b6d1b1f 100644 --- a/src/window.cc +++ b/src/window.cc @@ -29,7 +29,7 @@ void Window::generate_keybindings() { } Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compiling(false) { - INFO("Create Window"); + DEBUG("start"); set_title("juCi++"); set_default_size(600, 400); set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK); @@ -80,7 +80,6 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil }); notebook.signal_switch_page().connect([this](Gtk::Widget* page, guint page_num) { - DEBUG("start"); if(notebook.get_current_page()!=-1) { if(search_entry_shown && entry_box.labels.size()>0) { notebook.get_current_view()->update_search_occurrences=[this](int number){ @@ -109,7 +108,6 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil Singleton::status()->set_text(notebook.get_current_view()->status); } - DEBUG("end"); }); notebook.signal_page_removed().connect([this](Gtk::Widget* page, guint page_num) { entry_box.hide(); @@ -130,11 +128,10 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil about.set_comments("This is an open source IDE with high-end features to make your programming experience juicy"); about.set_license_type(Gtk::License::LICENSE_MIT_X11); about.set_transient_for(*this); - INFO("Window created"); + DEBUG("end"); } // Window constructor void Window::create_menu() { - INFO("Adding actions to menu"); menu.action_group->add(Gtk::Action::create("FileQuit", "Quit juCi++"), Gtk::AccelKey(menu.key_map["quit"]), [this]() { hide(); }); @@ -187,7 +184,6 @@ void Window::create_menu() { search_and_replace_entry(); }); menu.action_group->add(Gtk::Action::create("EditUndo", "Undo"), Gtk::AccelKey(menu.key_map["edit_undo"]), [this]() { - INFO("On undo"); if(notebook.get_current_page()!=-1) { auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); if (undo_manager->can_undo()) { @@ -195,10 +191,8 @@ void Window::create_menu() { notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert()); } } - INFO("Done undo"); }); menu.action_group->add(Gtk::Action::create("EditRedo", "Redo"), Gtk::AccelKey(menu.key_map["edit_redo"]), [this]() { - INFO("On Redo"); if(notebook.get_current_page()!=-1) { auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); if(undo_manager->can_redo()) { @@ -206,7 +200,6 @@ void Window::create_menu() { notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert()); } } - INFO("Done Redo"); }); menu.action_group->add(Gtk::Action::create("SourceGotoLine", "Go to Line"), Gtk::AccelKey(menu.key_map["source_goto_line"]), [this]() { @@ -336,7 +329,6 @@ void Window::create_menu() { }); add_accel_group(menu.ui_manager->get_accel_group()); menu.build(); - INFO("Menu build") } bool Window::on_key_press_event(GdkEventKey *event) { @@ -530,7 +522,6 @@ void Window::open_file_dialog() { void Window::save_file_dialog() { if(notebook.get_current_page()==-1) return; - INFO("Save file dialog"); Gtk::FileChooserDialog dialog(*this, "Please choose a file", Gtk::FILE_CHOOSER_ACTION_SAVE); gtk_file_chooser_set_filename((GtkFileChooser*)dialog.gobj(), notebook.get_current_view()->file_path.string().c_str()); dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); From b12a04951330ca57939c6212c38b519f4307369b Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 2 Sep 2015 08:40:30 +0200 Subject: [PATCH 07/37] Now reparses after for instance #include <...>. --- src/juci.cc | 6 +++--- src/logging.h | 2 -- src/menu.cc | 4 +--- src/source.cc | 10 ++++++++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/juci.cc b/src/juci.cc index 6390d3d..a97b8ee 100644 --- a/src/juci.cc +++ b/src/juci.cc @@ -6,9 +6,9 @@ using namespace std; //TODO: remove void init_logging() { - add_common_attributes(); - add_file_log(keywords::file_name = Singleton::log_dir() + "juci.log", - keywords::auto_flush = true); + boost::log::add_common_attributes(); + boost::log::add_file_log(boost::log::keywords::file_name = Singleton::log_dir() + "juci.log", + boost::log::keywords::auto_flush = true); INFO("Logging initalized"); } diff --git a/src/logging.h b/src/logging.h index c00f0d2..fbd9f89 100644 --- a/src/logging.h +++ b/src/logging.h @@ -10,8 +10,6 @@ #include #include -using namespace boost::log; - #define TRACE_VAR(x) BOOST_LOG_TRIVIAL(trace) << "** Trace: " << __FILE__ << "@" << __func__ << "(" << __LINE__ << "): " << #x << "=<" << x << ">"; #define DEBUG_VAR(x) BOOST_LOG_TRIVIAL(debug) << "** Debug: " << __FILE__ << "@" << __func__ << "(" << __LINE__ << "): " << #x << "=<" << x << ">"; #define INFO_VAR(x) BOOST_LOG_TRIVIAL(info) << "** Info: " << __FILE__ << "@" << __func__ << "(" << __LINE__ << "): " << #x << "=<" << x << ">"; diff --git a/src/menu.cc b/src/menu.cc index 1cb122c..10daca9 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -1,8 +1,7 @@ #include "menu.h" -#include "logging.h" +#include Menu::Menu() : box(Gtk::ORIENTATION_VERTICAL) { - INFO("Creating menu"); action_group = Gtk::ActionGroup::create(); ui_manager = Gtk::UIManager::create(); @@ -15,7 +14,6 @@ Menu::Menu() : box(Gtk::ORIENTATION_VERTICAL) { action_group->add(Gtk::Action::create("SourceMenu", "_Source")); action_group->add(Gtk::Action::create("PluginMenu", "_Plugins")); action_group->add(Gtk::Action::create("HelpMenu", "Help")); - INFO("Menu created"); } Gtk::Widget& Menu::get_widget() { diff --git a/src/source.cc b/src/source.cc index 61bc789..e19d847 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1229,7 +1229,12 @@ Source::ClangViewParse(file_path, project_path), autocomplete_cancel_starting(fa } bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { - last_keyval=key->keyval; + if(key->keyval>=32 && key->keyval<=126) { + if(key->keyval=='>' && last_keyval=='-') + last_keyval=127; + else + last_keyval=key->keyval; + } if(completion_dialog_shown) { if(completion_dialog->on_key_press(key)) return true; @@ -1240,9 +1245,10 @@ bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { void Source::ClangViewAutocomplete::start_autocomplete() { if(!has_focus()) return; + cout << (int)last_keyval << endl; if(!((last_keyval>='0' && last_keyval<='9') || (last_keyval>='a' && last_keyval<='z') || (last_keyval>='A' && last_keyval<='Z') || - last_keyval=='_' || last_keyval=='>' || last_keyval=='.' || last_keyval==':')) { + last_keyval=='_' || last_keyval==127 || last_keyval=='.' || last_keyval==':')) { autocomplete_cancel_starting=true; return; } From afad339cfeb621604d96aed127d0b4413e940b33 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 2 Sep 2015 08:56:22 +0200 Subject: [PATCH 08/37] Added default save response to yes, and remove a debug cout. --- src/notebook.cc | 1 + src/source.cc | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/notebook.cc b/src/notebook.cc index 4dc4281..3d1ff49 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -190,6 +190,7 @@ bool Notebook::close_current_page() { bool Notebook::save_modified_dialog() { Gtk::MessageDialog dialog((Gtk::Window&)(*get_toplevel()), "Save file!", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO); + dialog.set_default_response(Gtk::RESPONSE_YES); dialog.set_secondary_text("Do you want to save: " + get_current_view()->file_path.string()+" ?"); int result = dialog.run(); if(result==Gtk::RESPONSE_YES) { diff --git a/src/source.cc b/src/source.cc index e19d847..904fdc7 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1245,7 +1245,6 @@ bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { void Source::ClangViewAutocomplete::start_autocomplete() { if(!has_focus()) return; - cout << (int)last_keyval << endl; if(!((last_keyval>='0' && last_keyval<='9') || (last_keyval>='a' && last_keyval<='z') || (last_keyval>='A' && last_keyval<='Z') || last_keyval=='_' || last_keyval==127 || last_keyval=='.' || last_keyval==':')) { From e9ce9446a88001ce8c69d2326893208548913916 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 2 Sep 2015 09:09:10 +0200 Subject: [PATCH 09/37] Now places warning and error underlines more correctly. --- src/source.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/source.cc b/src/source.cc index 904fdc7..62ff411 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1021,11 +1021,11 @@ void Source::ClangViewParse::update_diagnostics() { } auto end_line=get_line(diagnostic.offsets.second.line-1); //index is sometimes off the line auto end_line_index=diagnostic.offsets.second.index-1; - if(end_line_index>=end_line.size()) { + if(end_line_index>end_line.size()) { if(end_line.size()==0) end_line_index=0; else - end_line_index=end_line.size()-1; + end_line_index=end_line.size(); } auto start=get_buffer()->get_iter_at_line_index(diagnostic.offsets.first.line-1, start_line_index); auto end=get_buffer()->get_iter_at_line_index(diagnostic.offsets.second.line-1, end_line_index); From a633f1611e87c86f8b6b811872c7cac086c24063 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 2 Sep 2015 10:46:13 +0200 Subject: [PATCH 10/37] Fixes: spellcheck when using backspace, diagnostics underlines, and tooltips area of activation. --- src/source.cc | 11 ++++++++--- src/source.h | 1 + src/tooltips.cc | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/source.cc b/src/source.cc index 62ff411..f633935 100644 --- a/src/source.cc +++ b/src/source.cc @@ -186,10 +186,11 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat delayed_spellcheck_suggestions_connection.disconnect(); auto iter=get_buffer()->get_insert()->get_iter(); - if(iter.backward_char()) { + if(last_keyval_is_backspace || iter.backward_char()) { auto context_iter=iter; if(context_iter.backward_char()) { if((spellcheck_all && !get_source_buffer()->iter_has_context_class(context_iter, "no-spell-check")) || get_source_buffer()->iter_has_context_class(context_iter, "comment") || get_source_buffer()->iter_has_context_class(context_iter, "string")) { + cout << (char)*iter << endl; if(*iter==32 || *iter==45) { //Might have used space or - to split two words auto first=iter; auto second=iter; @@ -510,6 +511,10 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { if(spellcheck_suggestions_dialog->on_key_press(key)) return true; } + if(key->keyval==GDK_KEY_BackSpace) + last_keyval_is_backspace=true; + else + last_keyval_is_backspace=false; get_source_buffer()->begin_user_action(); //Indent as in next or previous line @@ -1013,11 +1018,11 @@ void Source::ClangViewParse::update_diagnostics() { if(diagnostic.path==file_path.string()) { auto start_line=get_line(diagnostic.offsets.first.line-1); //index is sometimes off the line auto start_line_index=diagnostic.offsets.first.index-1; - if(start_line_index>=start_line.size()) { + if(start_line_index>start_line.size()) { if(start_line.size()==0) start_line_index=0; else - start_line_index=start_line.size()-1; + start_line_index=start_line.size(); } auto end_line=get_line(diagnostic.offsets.second.line-1); //index is sometimes off the line auto end_line_index=diagnostic.offsets.second.index-1; diff --git a/src/source.h b/src/source.h index c89b365..6480d6b 100644 --- a/src/source.h +++ b/src/source.h @@ -114,6 +114,7 @@ namespace Source { std::unique_ptr spellcheck_suggestions_dialog; bool spellcheck_suggestions_dialog_shown=false; sigc::connection delayed_spellcheck_suggestions_connection; + bool last_keyval_is_backspace=false; }; class GenericView : public View { diff --git a/src/tooltips.cc b/src/tooltips.cc index 9ac2fb5..113ce64 100644 --- a/src/tooltips.cc +++ b/src/tooltips.cc @@ -35,7 +35,7 @@ void Tooltip::update() { auto end_iter=end_mark->get_iter(); text_view.get_iter_location(iter, activation_rectangle); if(iter.get_offset() Date: Wed, 2 Sep 2015 11:10:13 +0200 Subject: [PATCH 11/37] improved tab and shift-tab indentation. --- src/source.cc | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/source.cc b/src/source.cc index f633935..fa48bf6 100644 --- a/src/source.cc +++ b/src/source.cc @@ -190,7 +190,6 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat auto context_iter=iter; if(context_iter.backward_char()) { if((spellcheck_all && !get_source_buffer()->iter_has_context_class(context_iter, "no-spell-check")) || get_source_buffer()->iter_has_context_class(context_iter, "comment") || get_source_buffer()->iter_has_context_class(context_iter, "string")) { - cout << (char)*iter << endl; if(*iter==32 || *iter==45) { //Might have used space or - to split two words auto first=iter; auto second=iter; @@ -553,7 +552,8 @@ 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, tab); + if(!get_buffer()->get_has_selection() || line_it!=selection_end) + get_source_buffer()->insert(line_it, tab); } get_source_buffer()->end_user_action(); return true; @@ -567,23 +567,27 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { 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, tabs_regex) && sm[1].str().size()>0) { - indent_left_steps=std::min(indent_left_steps, (unsigned)sm[1].str().size()); - } - else { - get_source_buffer()->end_user_action(); - return true; + auto line_it = get_source_buffer()->get_iter_at_line(line_nr); + if(!get_buffer()->get_has_selection() || line_it!=selection_end) { + string line=get_line(line_nr); + std::smatch sm; + 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 { + get_source_buffer()->end_user_action(); + return true; + } } } for(int line_nr=line_start;line_nr<=line_end;line_nr++) { Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr); Gtk::TextIter line_plus_it=line_it; - - if(indent_left_steps==0 || line_plus_it.forward_chars(indent_left_steps)) - get_source_buffer()->erase(line_it, line_plus_it); + if(!get_buffer()->get_has_selection() || line_it!=selection_end) { + if(indent_left_steps==0 || line_plus_it.forward_chars(indent_left_steps)) + get_source_buffer()->erase(line_it, line_plus_it); + } } get_source_buffer()->end_user_action(); return true; @@ -1046,7 +1050,6 @@ void Source::ClangViewParse::update_diagnostics() { auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), severity_spelling, diagnostic_tag_name); tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), ":\n"+spelling, "def:note"); - //TODO: Insert newlines to clang_tu->diagnostics[c].spelling (use 80 chars, then newline?) return tooltip_buffer; }; diagnostic_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); From 564a31f571fe24343d3716a6a2e132e334fa4543 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 2 Sep 2015 12:16:53 +0200 Subject: [PATCH 12/37] Fixed some crashes and issues with binary output and files, and can now open binary files where non-utf-8 chars are replaced with '?'. --- src/sourcefile.cc | 45 ++++++++++++++++++++++++++++++++------------- src/terminal.cc | 32 ++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/sourcefile.cc b/src/sourcefile.cc index b853796..e1434e5 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -17,23 +17,42 @@ std::string juci::filesystem::read(const std::string &path) { bool juci::filesystem::read(const std::string &path, Glib::RefPtr text_buffer) { std::ifstream input(path, std::ofstream::binary); + if(input) { - std::vector buffer(buffer_size); + //need to read the whole file to make this work... + std::stringstream ss; + ss << input.rdbuf(); + Glib::ustring ustr=std::move(ss.str()); + + Glib::ustring::iterator iter; + while(!ustr.validate(iter)) { + auto next_char_iter=iter; + next_char_iter++; + ustr.replace(iter, next_char_iter, "?"); + } + + text_buffer->insert_at_cursor(ustr); + + //TODO: maybe correct this, emphasis on maybe: + /*std::vector buffer(buffer_size); size_t read_length; - std::string buffer_str; while((read_length=input.read(&buffer[0], buffer_size).gcount())>0) { - buffer_str+=std::string(&buffer[0], read_length); - if(buffer_str.back()>=0) { - auto ustr=Glib::ustring(buffer_str); - buffer_str=""; - if(ustr.validate()) - text_buffer->insert_at_cursor(ustr); - else { - input.close(); - return false; - } + //auto ustr=Glib::ustring(std::string(&buffer[0], read_length)); //this works... + + //this does not work: + Glib::ustring ustr; + ustr.resize(read_length); + ustr.replace(0, read_length, &buffer[0]); + + Glib::ustring::iterator iter; + while(!ustr.validate(iter)) { + auto next_char_iter=iter; + next_char_iter++; + ustr.replace(iter, next_char_iter, "?"); } - } + + text_buffer->insert_at_cursor(ustr); //What if insert happens in the middle of an UTF-8 char??? + }*/ input.close(); return true; } diff --git a/src/terminal.cc b/src/terminal.cc index addce65..eb96fcf 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -283,14 +283,22 @@ void Terminal::kill_async_executes(bool force) { } int Terminal::print(const std::string &message, bool bold){ + Glib::ustring umessage=message; + Glib::ustring::iterator iter; + while(!umessage.validate(iter)) { + auto next_char_iter=iter; + next_char_iter++; + umessage.replace(iter, next_char_iter, "?"); + } + if(bold) - get_buffer()->insert_with_tag(get_buffer()->end(), message, bold_tag); + get_buffer()->insert_with_tag(get_buffer()->end(), umessage, bold_tag); else - get_buffer()->insert(get_buffer()->end(), message); + get_buffer()->insert(get_buffer()->end(), umessage); - auto iter=get_buffer()->end(); - if(iter.backward_char()) { - auto mark=get_buffer()->create_mark(iter); + auto end_iter=get_buffer()->end(); + if(end_iter.backward_char()) { + auto mark=get_buffer()->create_mark(end_iter); scroll_to(mark, 0.0, 1.0, 1.0); get_buffer()->delete_mark(mark); } @@ -299,9 +307,17 @@ int Terminal::print(const std::string &message, bool bold){ } void Terminal::print(int line_nr, const std::string &message){ - auto iter=get_buffer()->get_iter_at_line(line_nr); - while(!iter.ends_line() && iter.forward_char()) {} - get_buffer()->insert(iter, message); + Glib::ustring umessage=message; + Glib::ustring::iterator iter; + while(!umessage.validate(iter)) { + auto next_char_iter=iter; + next_char_iter++; + umessage.replace(iter, next_char_iter, "?"); + } + + auto end_line_iter=get_buffer()->get_iter_at_line(line_nr); + while(!end_line_iter.ends_line() && end_line_iter.forward_char()) {} + get_buffer()->insert(end_line_iter, umessage); } std::shared_ptr Terminal::print_in_progress(std::string start_msg) { From bf0cd8d08e48883a22efeafb820e86dd8c875060 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 2 Sep 2015 12:35:22 +0200 Subject: [PATCH 13/37] Now gives warning when opened file is not a valid UTF-8 file. --- src/source.cc | 4 ++-- src/sourcefile.cc | 12 +++++++++--- src/sourcefile.h | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/source.cc b/src/source.cc index fa48bf6..adb8d1f 100644 --- a/src/source.cc +++ b/src/source.cc @@ -51,8 +51,8 @@ AspellConfig* Source::View::spellcheck_config=NULL; Source::View::View(const boost::filesystem::path &file_path): file_path(file_path) { set_smart_home_end(Gsv::SMART_HOME_END_BEFORE); get_source_buffer()->begin_not_undoable_action(); - if(!juci::filesystem::read(file_path, get_buffer())) - Singleton::terminal()->print("Error: "+file_path.string()+" is not a valid UTF-8 file.\n"); + if(juci::filesystem::read(file_path, get_buffer())==-1) + Singleton::terminal()->print("Warning: "+file_path.string()+" is not a valid UTF-8 file. Saving might corrupt the file.\n", true); get_source_buffer()->end_not_undoable_action(); get_buffer()->place_cursor(get_buffer()->get_iter_at_offset(0)); search_settings = gtk_source_search_settings_new(); diff --git a/src/sourcefile.cc b/src/sourcefile.cc index e1434e5..459390e 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -15,7 +15,7 @@ std::string juci::filesystem::read(const std::string &path) { return ss.str(); } -bool juci::filesystem::read(const std::string &path, Glib::RefPtr text_buffer) { +int juci::filesystem::read(const std::string &path, Glib::RefPtr text_buffer) { std::ifstream input(path, std::ofstream::binary); if(input) { @@ -24,11 +24,14 @@ bool juci::filesystem::read(const std::string &path, Glib::RefPtrinsert_at_cursor(ustr); @@ -54,9 +57,12 @@ bool juci::filesystem::read(const std::string &path, Glib::RefPtrinsert_at_cursor(ustr); //What if insert happens in the middle of an UTF-8 char??? }*/ input.close(); - return true; + if(valid) + return 1; + else + return -1; } - return false; + return 0; } //Only use on small files diff --git a/src/sourcefile.h b/src/sourcefile.h index d1ee608..9ddc937 100644 --- a/src/sourcefile.h +++ b/src/sourcefile.h @@ -10,8 +10,8 @@ namespace juci { public: static std::string read(const std::string &path); static std::string read(const boost::filesystem::path &path) { return read(path.string()); } - static bool read(const std::string &path, Glib::RefPtr text_buffer); - static bool read(const boost::filesystem::path &path, Glib::RefPtr text_buffer) { return read(path.string(), text_buffer); } + static int read(const std::string &path, Glib::RefPtr text_buffer); + static int read(const boost::filesystem::path &path, Glib::RefPtr text_buffer) { return read(path.string(), text_buffer); } static std::vector read_lines(const std::string &path); static std::vector read_lines(const boost::filesystem::path &path) { return read_lines(path.string()); }; From f40f4075684c0dccfcf95c01ffa420470e800f4c Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 2 Sep 2015 12:46:47 +0200 Subject: [PATCH 14/37] Back to not being able to load non-valid UTF-8 files. The replace-process was extremely slow on medium sized files. --- src/source.cc | 2 +- src/sourcefile.cc | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/source.cc b/src/source.cc index adb8d1f..fa1c734 100644 --- a/src/source.cc +++ b/src/source.cc @@ -52,7 +52,7 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat set_smart_home_end(Gsv::SMART_HOME_END_BEFORE); get_source_buffer()->begin_not_undoable_action(); if(juci::filesystem::read(file_path, get_buffer())==-1) - Singleton::terminal()->print("Warning: "+file_path.string()+" is not a valid UTF-8 file. Saving might corrupt the file.\n", true); + Singleton::terminal()->print("Error: "+file_path.string()+" is not a valid UTF-8 file."); get_source_buffer()->end_not_undoable_action(); get_buffer()->place_cursor(get_buffer()->get_iter_at_offset(0)); search_settings = gtk_source_search_settings_new(); diff --git a/src/sourcefile.cc b/src/sourcefile.cc index 459390e..2ee7219 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -25,16 +25,20 @@ int juci::filesystem::read(const std::string &path, Glib::RefPtrinsert_at_cursor(ustr); + if(ustr.validate()) + text_buffer->insert_at_cursor(ustr); + else + valid=false; //TODO: maybe correct this, emphasis on maybe: /*std::vector buffer(buffer_size); From 3bd298459f73a780b55313cbd50a70d101879e18 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 3 Sep 2015 09:53:00 +0200 Subject: [PATCH 15/37] Further typing does not include warning or error underline anymore. --- src/source.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/source.cc b/src/source.cc index fa1c734..f2d422d 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1022,11 +1022,11 @@ void Source::ClangViewParse::update_diagnostics() { if(diagnostic.path==file_path.string()) { auto start_line=get_line(diagnostic.offsets.first.line-1); //index is sometimes off the line auto start_line_index=diagnostic.offsets.first.index-1; - if(start_line_index>start_line.size()) { + if(start_line_index>=start_line.size()) { if(start_line.size()==0) start_line_index=0; else - start_line_index=start_line.size(); + start_line_index=start_line.size()-1; } auto end_line=get_line(diagnostic.offsets.second.line-1); //index is sometimes off the line auto end_line_index=diagnostic.offsets.second.index-1; @@ -1055,6 +1055,12 @@ void Source::ClangViewParse::update_diagnostics() { diagnostic_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); get_buffer()->apply_tag_by_name(diagnostic_tag_name+"_underline", start, end); + auto iter=get_buffer()->get_insert()->get_iter(); + if(iter.ends_line()) { + auto next_iter=iter; + if(next_iter.forward_char()) + get_buffer()->remove_tag_by_name(diagnostic_tag_name+"_underline", iter, next_iter); + } } } } From 90d28e9ae07786d090485ecf199bfb18772652df Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 3 Sep 2015 10:38:28 +0200 Subject: [PATCH 16/37] Fixed spellchecking abit. --- src/source.cc | 40 +++++++++++++++++++++------------------- src/source.h | 1 + 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/source.cc b/src/source.cc index f2d422d..48fde53 100644 --- a/src/source.cc +++ b/src/source.cc @@ -186,26 +186,24 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat delayed_spellcheck_suggestions_connection.disconnect(); auto iter=get_buffer()->get_insert()->get_iter(); - if(last_keyval_is_backspace || iter.backward_char()) { - auto context_iter=iter; - if(context_iter.backward_char()) { - if((spellcheck_all && !get_source_buffer()->iter_has_context_class(context_iter, "no-spell-check")) || get_source_buffer()->iter_has_context_class(context_iter, "comment") || get_source_buffer()->iter_has_context_class(context_iter, "string")) { - if(*iter==32 || *iter==45) { //Might have used space or - to split two words - auto first=iter; - auto second=iter; - if(first.backward_char() && second.forward_char()) { - get_buffer()->remove_tag_by_name("spellcheck_error", first, second); - auto word=spellcheck_get_word(first); - spellcheck_word(word.first, word.second); - word=spellcheck_get_word(second); - spellcheck_word(word.first, word.second); - } - } - else { - auto word=spellcheck_get_word(iter); + auto context_iter=iter; + if(((last_keyval_is_backspace && !iter.ends_line()) || iter.backward_char()) && context_iter.backward_char() && context_iter.backward_char()) { + if((spellcheck_all && !get_source_buffer()->iter_has_context_class(context_iter, "no-spell-check")) || get_source_buffer()->iter_has_context_class(context_iter, "comment") || get_source_buffer()->iter_has_context_class(context_iter, "string")) { + if(*iter==32 || *iter==45) { //Might have used space or - to split two words + auto first=iter; + auto second=iter; + if(first.backward_char() && second.forward_char()) { + get_buffer()->remove_tag_by_name("spellcheck_error", first, second); + auto word=spellcheck_get_word(first); + spellcheck_word(word.first, word.second); + word=spellcheck_get_word(second); spellcheck_word(word.first, word.second); } } + else { + auto word=spellcheck_get_word(iter); + spellcheck_word(word.first, word.second); + } } } }); @@ -701,16 +699,20 @@ std::pair Source::View::find_tab_char_and_size() { return {found_tab_char, found_tab_size}; } +bool Source::View::is_word_iter(const Gtk::TextIter& iter) { + return ((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter==39 || *iter>=128); +} + std::pair Source::View::spellcheck_get_word(Gtk::TextIter iter) { auto start=iter; auto end=iter; - while((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter==39 || *iter>=128) { + while(is_word_iter(iter)) { start=iter; if(!iter.backward_char()) break; } - while((*end>=48 && *end<=57) || (*end>=65 && *end<=90) || (*end>=97 && *end<=122) || *iter==39 || *end>=128) { + while(is_word_iter(end)) { if(!end.forward_char()) break; } diff --git a/src/source.h b/src/source.h index 6480d6b..29a7cd3 100644 --- a/src/source.h +++ b/src/source.h @@ -108,6 +108,7 @@ namespace Source { static AspellConfig* spellcheck_config; AspellCanHaveError *spellcheck_possible_err; AspellSpeller *spellcheck_checker; + bool is_word_iter(const Gtk::TextIter& iter); std::pair spellcheck_get_word(Gtk::TextIter iter); void spellcheck_word(const Gtk::TextIter& start, const Gtk::TextIter& end); std::vector spellcheck_get_suggestions(const Gtk::TextIter& start, const Gtk::TextIter& end); From 5420343e8d20256ae6b6b1751a7c8cbfd6d7540b Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 3 Sep 2015 11:44:43 +0200 Subject: [PATCH 17/37] Hopefully the last spellcheck fix. --- src/source.cc | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/source.cc b/src/source.cc index 48fde53..0f979af 100644 --- a/src/source.cc +++ b/src/source.cc @@ -186,24 +186,31 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat delayed_spellcheck_suggestions_connection.disconnect(); auto iter=get_buffer()->get_insert()->get_iter(); - auto context_iter=iter; - if(((last_keyval_is_backspace && !iter.ends_line()) || iter.backward_char()) && context_iter.backward_char() && context_iter.backward_char()) { - if((spellcheck_all && !get_source_buffer()->iter_has_context_class(context_iter, "no-spell-check")) || get_source_buffer()->iter_has_context_class(context_iter, "comment") || get_source_buffer()->iter_has_context_class(context_iter, "string")) { - if(*iter==32 || *iter==45) { //Might have used space or - to split two words - auto first=iter; - auto second=iter; - if(first.backward_char() && second.forward_char()) { - get_buffer()->remove_tag_by_name("spellcheck_error", first, second); - auto word=spellcheck_get_word(first); - spellcheck_word(word.first, word.second); - word=spellcheck_get_word(second); + bool ends_line=iter.ends_line(); + if(iter.backward_char()) { + auto context_iter=iter; + bool backward_success=true; + if(ends_line || *iter=='/' || *iter=='*') //iter_has_context_class is sadly bugged + backward_success=context_iter.backward_char(); + if(backward_success) { + if((spellcheck_all && !get_source_buffer()->iter_has_context_class(context_iter, "no-spell-check")) || get_source_buffer()->iter_has_context_class(context_iter, "comment") || get_source_buffer()->iter_has_context_class(context_iter, "string")) { + if(last_keyval_is_backspace && !is_word_iter(iter) && iter.forward_char()) {} //backspace fix + if(*iter==32 || *iter==45) { //Might have used space or - to split two words + auto first=iter; + auto second=iter; + if(first.backward_char() && second.forward_char()) { + get_buffer()->remove_tag_by_name("spellcheck_error", first, second); + auto word=spellcheck_get_word(first); + spellcheck_word(word.first, word.second); + word=spellcheck_get_word(second); + spellcheck_word(word.first, word.second); + } + } + else { + auto word=spellcheck_get_word(iter); spellcheck_word(word.first, word.second); } } - else { - auto word=spellcheck_get_word(iter); - spellcheck_word(word.first, word.second); - } } } }); From e7ac97b4424d0de5900514bce4700a4a6f007021 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 5 Sep 2015 09:42:46 +0200 Subject: [PATCH 18/37] Improved smart paste, and tab and shift-tab indenting. --- src/source.cc | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/source.cc b/src/source.cc index 0f979af..c9e9f37 100644 --- a/src/source.cc +++ b/src/source.cc @@ -427,13 +427,16 @@ void Source::View::paste() { paste_line=true; } if(paste_line) { + bool empty_line=true; std::string line=text.substr(start_line, end_line-start_line); size_t tabs=0; for(auto chr: line) { if(chr==tab_char) tabs++; - else + else { + empty_line=false; break; + } } if(first_paste_line) { if(tabs!=0) { @@ -442,7 +445,7 @@ void Source::View::paste() { } first_paste_line=false; } - else + else if(!empty_line) paste_line_tabs=std::min(paste_line_tabs, tabs); start_line=end_line+1; @@ -466,15 +469,28 @@ void Source::View::paste() { paste_line=true; } if(paste_line) { + std::string line=text.substr(start_line, end_line-start_line); + size_t line_tabs=0; + for(auto chr: line) { + if(chr==tab_char) + line_tabs++; + else + break; + } + auto tabs=paste_line_tabs; + if(!(first_paste_line && !first_paste_line_has_tabs) && line_tabsinsert_at_cursor(text.substr(start_line+paste_line_tabs, end_line-start_line-paste_line_tabs)); + get_buffer()->insert_at_cursor(text.substr(start_line+tabs, end_line-start_line-tabs)); else get_buffer()->insert_at_cursor(text.substr(start_line, end_line-start_line)); first_paste_line=false; } else - get_buffer()->insert_at_cursor('\n'+prefix_tabs+text.substr(start_line+paste_line_tabs, end_line-start_line-paste_line_tabs)); + get_buffer()->insert_at_cursor('\n'+prefix_tabs+text.substr(start_line+tabs, end_line-start_line-tabs)); start_line=end_line+1; paste_line=false; } @@ -571,13 +587,21 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { int line_end=selection_end.get_line(); unsigned indent_left_steps=tab_size; + std::vector ignore_line; for(int line_nr=line_start;line_nr<=line_end;line_nr++) { auto line_it = get_source_buffer()->get_iter_at_line(line_nr); if(!get_buffer()->get_has_selection() || line_it!=selection_end) { string line=get_line(line_nr); std::smatch sm; - 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()); + if(std::regex_match(line, sm, tabs_regex) && (sm[1].str().size()>0 || sm[2].str().size()==0)) { + if(sm[2].str().size()>0) { + indent_left_steps=std::min(indent_left_steps, (unsigned)sm[1].str().size()); + ignore_line.push_back(false); + } + else if((unsigned)sm[1].str().size()end_user_action(); @@ -591,7 +615,8 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { Gtk::TextIter line_plus_it=line_it; if(!get_buffer()->get_has_selection() || line_it!=selection_end) { if(indent_left_steps==0 || line_plus_it.forward_chars(indent_left_steps)) - get_source_buffer()->erase(line_it, line_plus_it); + if(!ignore_line.at(line_nr-line_start)) + get_source_buffer()->erase(line_it, line_plus_it); } } get_source_buffer()->end_user_action(); From 859936392edc101fea12d21c503ba806c2e553de Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 5 Sep 2015 10:16:50 +0200 Subject: [PATCH 19/37] Improved autocomplete. --- src/source.cc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/source.cc b/src/source.cc index c9e9f37..97fcf51 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1249,12 +1249,15 @@ Source::ClangViewParse(file_path, project_path), autocomplete_cancel_starting(fa autocomplete_cancel_starting=true; if(completion_dialog_shown) { completion_dialog->hide(); + start_reparse(); } } }); signal_scroll_event().connect([this](GdkEventScroll* event){ - if(completion_dialog_shown) + if(completion_dialog_shown) { completion_dialog->hide(); + start_reparse(); + } return false; }, false); signal_key_release_event().connect([this](GdkEventKey* key){ @@ -1270,6 +1273,7 @@ Source::ClangViewParse(file_path, project_path), autocomplete_cancel_starting(fa autocomplete_cancel_starting=true; if(completion_dialog_shown) { completion_dialog->hide(); + start_reparse(); } return false; @@ -1277,12 +1281,7 @@ Source::ClangViewParse(file_path, project_path), autocomplete_cancel_starting(fa } bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { - if(key->keyval>=32 && key->keyval<=126) { - if(key->keyval=='>' && last_keyval=='-') - last_keyval=127; - else - last_keyval=key->keyval; - } + last_keyval=key->keyval; if(completion_dialog_shown) { if(completion_dialog->on_key_press(key)) return true; @@ -1293,15 +1292,17 @@ bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { void Source::ClangViewAutocomplete::start_autocomplete() { if(!has_focus()) return; + auto iter=get_buffer()->get_insert()->get_iter(); if(!((last_keyval>='0' && last_keyval<='9') || (last_keyval>='a' && last_keyval<='z') || (last_keyval>='A' && last_keyval<='Z') || - last_keyval=='_' || last_keyval==127 || last_keyval=='.' || last_keyval==':')) { + last_keyval=='_' || last_keyval=='.' || last_keyval==':' || + (last_keyval=='>' && iter.backward_char() && iter.backward_char() && *iter=='-'))) { autocomplete_cancel_starting=true; return; } std::string line=" "+get_line_before_insert(); if((std::count(line.begin(), line.end(), '\"')%2)!=1 && line.find("//")==std::string::npos) { - const std::regex in_specified_namespace("^(.*[a-zA-Z0-9_\\)])(->|\\.|::)([a-zA-Z0-9_]*)$"); + const std::regex in_specified_namespace("^(.*[a-zA-Z0-9_\\)\\]\\>])(->|\\.|::)([a-zA-Z0-9_]*)$"); const std::regex within_namespace("^(.*)([^a-zA-Z0-9_]+)([a-zA-Z0-9_]{3,})$"); std::smatch sm; if(std::regex_match(line, sm, in_specified_namespace)) { @@ -1344,9 +1345,9 @@ void Source::ClangViewAutocomplete::autocomplete() { completion_dialog=std::unique_ptr(new CompletionDialog(*this, get_buffer()->create_mark(start_iter))); auto rows=std::make_shared >(); completion_dialog->on_hide=[this](){ - start_reparse(); get_source_buffer()->end_user_action(); completion_dialog_shown=false; + start_reparse(); }; completion_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { auto row = rows->at(selected); From c3447d52d35637f62ea8bd48c7cecf7ea248b00e Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 5 Sep 2015 10:27:57 +0200 Subject: [PATCH 20/37] Minor fixes to reparse and spellchecker. --- src/source.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index 97fcf51..81999a3 100644 --- a/src/source.cc +++ b/src/source.cc @@ -195,7 +195,7 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat if(backward_success) { if((spellcheck_all && !get_source_buffer()->iter_has_context_class(context_iter, "no-spell-check")) || get_source_buffer()->iter_has_context_class(context_iter, "comment") || get_source_buffer()->iter_has_context_class(context_iter, "string")) { if(last_keyval_is_backspace && !is_word_iter(iter) && iter.forward_char()) {} //backspace fix - if(*iter==32 || *iter==45) { //Might have used space or - to split two words + if(!is_word_iter(iter)) { //Might have used space or - to split two words auto first=iter; auto second=iter; if(first.backward_char() && second.forward_char()) { @@ -1641,6 +1641,7 @@ void Source::ClangView::async_delete() { bool Source::ClangView::restart_parse() { if(!restart_parse_running) { + start_reparse_needed=false; restart_parse_running=true; parse_thread_stop=true; if(restart_parse_thread.joinable()) From 7601e0d646ec1272658697067fa844a81f91bea4 Mon Sep 17 00:00:00 2001 From: Ole Date: Sat, 5 Sep 2015 10:49:47 +0200 Subject: [PATCH 21/37] Fixed select word on double mouse click such that it works on all platforms. --- src/source.cc | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/source.cc b/src/source.cc index 81999a3..5bef9db 100644 --- a/src/source.cc +++ b/src/source.cc @@ -660,20 +660,19 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { bool Source::View::on_button_press_event(GdkEventButton *event) { if(event->type==GDK_2BUTTON_PRESS) { Gtk::TextIter start, end; - if(get_buffer()->get_selection_bounds(start, end)) { - auto iter=start; - while((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter==95) { - start=iter; - if(!iter.backward_char()) - break; - } - while((*end>=48 && *end<=57) || (*end>=65 && *end<=90) || (*end>=97 && *end<=122) || *end==95) { - if(!end.forward_char()) - break; - } - get_buffer()->select_range(start, end); - return true; + get_buffer()->get_selection_bounds(start, end); + auto iter=start; + while((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter==95) { + start=iter; + if(!iter.backward_char()) + break; } + while((*end>=48 && *end<=57) || (*end>=65 && *end<=90) || (*end>=97 && *end<=122) || *end==95) { + if(!end.forward_char()) + break; + } + get_buffer()->select_range(start, end); + return true; } return Gsv::View::on_button_press_event(event); From e81801beb644ea6b09809d8c204635330c12d450 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 5 Sep 2015 17:17:38 +0200 Subject: [PATCH 22/37] Improved clang indentation, further improvements coming soon. --- src/source.cc | 183 +++++++++++++++++++++++++++++--------------------- src/source.h | 5 +- 2 files changed, 112 insertions(+), 76 deletions(-) diff --git a/src/source.cc b/src/source.cc index 5bef9db..c6b50c7 100644 --- a/src/source.cc +++ b/src/source.cc @@ -525,12 +525,53 @@ string Source::View::get_line_before_insert() { return line; } +bool Source::View::find_start_of_sentence(Gtk::TextIter iter, Gtk::TextIter &found_iter) { + int count=0; + while(iter.backward_char()) { + if(*iter=='{' && count==0) + continue; + if(*iter==')' || *iter==']' || *iter=='}') + count++; + else if(*iter=='(' || *iter=='[' || *iter =='{') + count--; + if(iter.ends_line() && count==0) { + found_iter=iter; + found_iter.forward_char(); + return true; + } + } + return false; +} + +bool Source::View::find_right_bracket_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter) { + int count=0; + bool last_iter_ended_line=iter.ends_line(); + while(iter.forward_char()) { + if(*iter=='}') { + if(count==0) { + found_iter=iter; + return true; + } + count--; + } + else if(*iter=='{') + count++; + if(last_iter_ended_line) { + if(*iter!=tab_char && !iter.ends_line()) + return false; + } + last_iter_ended_line=iter.ends_line(); + } + return false; +} + //Basic indentation bool Source::View::on_key_press_event(GdkEventKey* key) { if(spellcheck_suggestions_dialog_shown) { if(spellcheck_suggestions_dialog->on_key_press(key)) return true; } + if(key->keyval==GDK_KEY_BackSpace) last_keyval_is_backspace=true; else @@ -622,33 +663,16 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { get_source_buffer()->end_user_action(); return true; } - //"Smart" backspace key + //"Smart" backspace key TODO: remove commented out lines if this works else if(key->keyval==GDK_KEY_BackSpace && !get_buffer()->get_has_selection()) { auto insert_it=get_buffer()->get_insert()->get_iter(); - int line_nr=insert_it.get_line(); + //int line_nr=insert_it.get_line(); auto line=get_line_before_insert(); std::smatch sm; 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, 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; - if(previous_line_end_it.backward_chars(line.size()+1)) - get_source_buffer()->erase(previous_line_end_it, insert_it); - get_source_buffer()->end_user_action(); - return true; - } - } - } - if(line.size()>=tab_size) { - auto insert_minus_tab_it=insert_it; - if(tab_size==0 || insert_minus_tab_it.backward_chars(tab_size)) - get_source_buffer()->erase(insert_minus_tab_it, insert_it); - get_source_buffer()->end_user_action(); - return true; - } + auto line_start_iter=insert_it; + if(line_start_iter.backward_chars(line.size())) + get_buffer()->erase(insert_it, line_start_iter); } } @@ -1128,37 +1152,44 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { //Indent depending on if/else/etc and brackets if(key->keyval==GDK_KEY_Return) { - string line(get_line_before_insert()); - std::smatch sm; - if(std::regex_match(line, sm, bracket_regex)) { - int line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); - 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, 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; + auto iter=get_buffer()->get_insert()->get_iter(); + Gtk::TextIter found_iter; + if(find_start_of_sentence(iter, found_iter)) { + auto start_line=get_line(found_iter.get_line()); + std::smatch sm; + std::string tabs; + if(std::regex_match(start_line, sm, tabs_regex)) { + tabs=sm[1].str(); + } + + 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 line_it = get_source_buffer()->get_iter_at_line(found_iter.get_line()); + std::string line(get_source_buffer()->get_text(line_it, found_iter)); + if(std::regex_match(line, sm, tabs_regex)) { + if(tabs.size()==sm[1].str().size()) + has_bracket=true; } } - auto next_char=*get_buffer()->get_insert()->get_iter(); - auto next_line_with_end_bracket=sm[1].str()+"}"; - if(next_char!='}' && next_line.substr(0, next_line_with_end_bracket.size())!=next_line_with_end_bracket) { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab+"\n"+sm[1].str()+"}"); + 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(sm[1].str().size()+2)) { + 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(next_char=='}') { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab+"\n"+sm[1].str()); + 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(sm[1].str().size()+1)) { + if(insert_it.backward_chars(tabs.size()+2)) { scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->place_cursor(insert_it); } @@ -1166,42 +1197,44 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { return true; } else { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); - scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->insert_at_cursor("\n"+tabs+tab); + scroll_to(get_buffer()->get_insert()); get_source_buffer()->end_user_action(); return true; } } - } - else if(std::regex_match(line, sm, no_bracket_statement_regex)) { - 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()+tab); - scroll_to(get_source_buffer()->get_insert()); - get_source_buffer()->end_user_action(); - return true; - } - 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()>=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)) { - 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(std::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; + auto line=get_line_before_insert(); + if(std::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(std::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(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 && tabs.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)) { + 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(std::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; + } } } } diff --git a/src/source.h b/src/source.h index 29a7cd3..cbbfb6e 100644 --- a/src/source.h +++ b/src/source.h @@ -90,6 +90,9 @@ namespace Source { std::string get_line(size_t line_number); std::string get_line_before_insert(); + bool find_start_of_sentence(Gtk::TextIter iter, Gtk::TextIter &found_iter); + bool find_right_bracket_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter); + bool on_key_press_event(GdkEventKey* key); bool on_button_press_event(GdkEventButton *event); @@ -104,7 +107,7 @@ namespace Source { GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; static void search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data); - + static AspellConfig* spellcheck_config; AspellCanHaveError *spellcheck_possible_err; AspellSpeller *spellcheck_checker; From 756bd0a69cdc7218e9fb0ce41cf8f714f740ff01 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 5 Sep 2015 18:41:05 +0200 Subject: [PATCH 23/37] Fixed a bug in find_tab_char_and_size(). --- src/source.cc | 52 +++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/src/source.cc b/src/source.cc index c6b50c7..e0c8b04 100644 --- a/src/source.cc +++ b/src/source.cc @@ -703,7 +703,7 @@ bool Source::View::on_button_press_event(GdkEventButton *event) { } std::pair Source::View::find_tab_char_and_size() { - const std::regex indent_regex("^([ \t]+).*$"); + const std::regex indent_regex("^([ \t]+)(.*)$"); auto size=get_buffer()->get_line_count(); std::unordered_map tab_chars; std::unordered_map tab_sizes; @@ -711,28 +711,36 @@ std::pair Source::View::find_tab_char_and_size() { 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; - } + if(sm[2].str().size()==0) + continue; + str=sm[1].str(); + } + else { + str=""; + if(line.size()==0) + continue; + } + + long tab_diff=abs(static_cast(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; From 75edbd4b7c14e7e1e1ec56e1fc420dfd691fbf7d Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 5 Sep 2015 18:54:01 +0200 Subject: [PATCH 24/37] Now parsing should always start after autocomplete is finished. --- src/source.cc | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/source.cc b/src/source.cc index e0c8b04..8055bab 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1287,17 +1287,13 @@ Source::ClangViewParse(file_path, project_path), autocomplete_cancel_starting(fa get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark){ if(mark->get_name()=="insert") { autocomplete_cancel_starting=true; - if(completion_dialog_shown) { + if(completion_dialog_shown) completion_dialog->hide(); - start_reparse(); - } } }); signal_scroll_event().connect([this](GdkEventScroll* event){ - if(completion_dialog_shown) { + if(completion_dialog_shown) completion_dialog->hide(); - start_reparse(); - } return false; }, false); signal_key_release_event().connect([this](GdkEventKey* key){ @@ -1311,10 +1307,8 @@ Source::ClangViewParse(file_path, project_path), autocomplete_cancel_starting(fa signal_focus_out_event().connect([this](GdkEventFocus* event) { autocomplete_cancel_starting=true; - if(completion_dialog_shown) { + if(completion_dialog_shown) completion_dialog->hide(); - start_reparse(); - } return false; }); @@ -1439,6 +1433,7 @@ void Source::ClangViewAutocomplete::autocomplete() { } else { set_status(""); + start_reparse(); start_autocomplete(); } }); From ad323c12adc14964ad7368148308867a0bc7d0c4 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 6 Sep 2015 13:23:46 +0200 Subject: [PATCH 25/37] Automatic clang indentation finished. Requires testing though. --- src/source.cc | 205 +++++++++++++++++++++++++++++++++++++++----------- src/source.h | 10 ++- 2 files changed, 170 insertions(+), 45 deletions(-) diff --git a/src/source.cc b/src/source.cc index 8055bab..ac84013 100644 --- a/src/source.cc +++ b/src/source.cc @@ -405,7 +405,7 @@ void Source::View::replace_all(const std::string &replacement) { void Source::View::paste() { Gtk::Clipboard::get()->request_text([this](const Glib::ustring& text){ - auto line=get_line_before_insert(); + auto line=get_line_before(); std::smatch sm; std::string prefix_tabs; if(!get_buffer()->get_has_selection() && std::regex_match(line, sm, tabs_regex) && sm[2].str().size()==0) { @@ -510,57 +510,165 @@ void Source::View::set_status(const std::string &status) { on_update_status(this, status); } -string Source::View::get_line(size_t line_number) { - Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_number); - Gtk::TextIter line_end_it = line_it; +std::string Source::View::get_line(const Gtk::TextIter &iter) { + auto line_start_it = get_buffer()->get_iter_at_line(iter.get_line()); + auto line_end_it = iter; while(!line_end_it.ends_line() && line_end_it.forward_char()) {} - std::string line(get_source_buffer()->get_text(line_it, line_end_it)); + std::string line(get_source_buffer()->get_text(line_start_it, line_end_it)); return line; } -string Source::View::get_line_before_insert() { - 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()); - std::string line(get_source_buffer()->get_text(line_it, insert_it)); +std::string Source::View::get_line(Glib::RefPtr mark) { + return get_line(mark->get_iter()); +} + +std::string Source::View::get_line(int line_nr) { + return get_line(get_buffer()->get_iter_at_line(line_nr)); +} + +std::string Source::View::get_line() { + return get_line(get_buffer()->get_insert()); +} + +std::string Source::View::get_line_before(const Gtk::TextIter &iter) { + auto line_it = get_source_buffer()->get_iter_at_line(iter.get_line()); + std::string line(get_source_buffer()->get_text(line_it, iter)); return line; } +std::string Source::View::get_line_before(Glib::RefPtr mark) { + return get_line_before(mark->get_iter()); +} + +std::string Source::View::get_line_before() { + return get_line_before(get_buffer()->get_insert()); +} + bool Source::View::find_start_of_sentence(Gtk::TextIter iter, Gtk::TextIter &found_iter) { - int count=0; while(iter.backward_char()) { - if(*iter=='{' && count==0) - continue; - if(*iter==')' || *iter==']' || *iter=='}') - count++; - else if(*iter=='(' || *iter=='[' || *iter =='{') - count--; - if(iter.ends_line() && count==0) { + if(*iter!='{' && *iter!=' ' && *iter!='\t') + break; + if(iter.starts_line()) { found_iter=iter; - found_iter.forward_char(); return true; } } + + int count1=0; + int count2=0; + int count3=0; + int count4=0; + + bool ignore=false; + + do { + if(!get_source_buffer()->iter_has_context_class(iter, "comment") && !get_source_buffer()->iter_has_context_class(iter, "string")) { + if(*iter=='\'') { + auto before_iter=iter; + before_iter.backward_char(); + auto before_before_iter=before_iter; + before_before_iter.backward_char(); + if(*before_iter!='\\' || *before_before_iter=='\\') + ignore=!ignore; + } + else if(!ignore) { + if(*iter==')') + count1++; + else if(*iter==']') + count2++; + else if(*iter=='>') + count3++; + else if(*iter=='}') + count4++; + else if(*iter=='(') + count1--; + else if(*iter=='[') + count2--; + else if(*iter=='<') + count3--; + else if(*iter=='{') + count4--; + } + } + if(iter.starts_line() && count1<=0 && count2<=0 && count3<=0) { + found_iter=iter; + return true; + } + } while(iter.backward_char()); return false; } -bool Source::View::find_right_bracket_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter) { - int count=0; - bool last_iter_ended_line=iter.ends_line(); - while(iter.forward_char()) { - if(*iter=='}') { - if(count==0) { +bool Source::View::find_open_symbol(Gtk::TextIter iter, const Gtk::TextIter &until_iter, Gtk::TextIter &found_iter) { + int count1=0; + int count2=0; + int count3=0; + + bool ignore=false; + + while(iter!=until_iter && iter.backward_char()) { + if(!get_source_buffer()->iter_has_context_class(iter, "comment") && !get_source_buffer()->iter_has_context_class(iter, "string")) { + if(*iter=='\'') { + auto before_iter=iter; + before_iter.backward_char(); + auto before_before_iter=before_iter; + before_before_iter.backward_char(); + if(*before_iter!='\\' || *before_before_iter=='\\') + ignore=!ignore; + } + else if(!ignore) { + if(*iter==')') + count1++; + else if(*iter==']') + count2++; + else if(*iter=='>') + count3++; + else if(*iter=='(') + count1--; + else if(*iter=='[') + count2--; + else if(*iter=='<') + count3--; + } + if(count1<0 || count2<0 || count3<0) { found_iter=iter; return true; } - count--; } - else if(*iter=='{') - count++; - if(last_iter_ended_line) { - if(*iter!=tab_char && !iter.ends_line()) - return false; + } + + return false; +} + +bool Source::View::find_right_bracket_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter) { + int count=0; + + bool ignore=false; + + while(iter.forward_char()) { + if(!get_source_buffer()->iter_has_context_class(iter, "comment") && !get_source_buffer()->iter_has_context_class(iter, "string")) { + if(*iter=='\'') { + auto before_iter=iter; + before_iter.backward_char(); + auto before_before_iter=before_iter; + before_before_iter.backward_char(); + if(*before_iter!='\\' || *before_before_iter=='\\') + ignore=!ignore; + } + else if(!ignore) { + if(*iter=='}') { + if(count==0) { + found_iter=iter; + return true; + } + count--; + } + else if(*iter=='{') + count++; + } } - last_iter_ended_line=iter.ends_line(); + + if(iter.starts_line() && *iter!=tab_char && !iter.ends_line() && *iter!='#') + return false; } return false; } @@ -582,7 +690,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { if(key->keyval==GDK_KEY_Return && !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(); + auto line=get_line_before(); std::smatch sm; if(std::regex_match(line, sm, tabs_regex)) { if((line_nr+1)get_line_count()) { @@ -667,7 +775,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { else if(key->keyval==GDK_KEY_BackSpace && !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(); + auto line=get_line_before(); std::smatch sm; if(std::regex_match(line, sm, tabs_regex) && sm[1].str().size()==line.size()) { auto line_start_iter=insert_it; @@ -1161,9 +1269,9 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { //Indent depending on if/else/etc and brackets if(key->keyval==GDK_KEY_Return) { auto iter=get_buffer()->get_insert()->get_iter(); - Gtk::TextIter found_iter; - if(find_start_of_sentence(iter, found_iter)) { - auto start_line=get_line(found_iter.get_line()); + Gtk::TextIter start_of_sentence_iter; + if(find_start_of_sentence(iter, start_of_sentence_iter)) { + auto start_line=get_line(start_of_sentence_iter); std::smatch sm; std::string tabs; if(std::regex_match(start_line, sm, tabs_regex)) { @@ -1176,8 +1284,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { bool has_bracket=false; if(found_right_bracket) { - auto line_it = get_source_buffer()->get_iter_at_line(found_iter.get_line()); - std::string line(get_source_buffer()->get_text(line_it, found_iter)); + auto line=get_line_before(found_iter); if(std::regex_match(line, sm, tabs_regex)) { if(tabs.size()==sm[1].str().size()) has_bracket=true; @@ -1211,8 +1318,16 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { return true; } } - auto line=get_line_before_insert(); - if(std::regex_match(line, sm, no_bracket_statement_regex)) { + auto line=get_line_before(); + iter=get_buffer()->get_insert()->get_iter(); + auto found_iter=iter; + if(find_open_symbol(iter, start_of_sentence_iter, found_iter)) { + auto offset=found_iter.get_line_offset(); + tabs.clear(); + for(int c=0;cinsert_at_cursor("\n"+tabs+tab); scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->end_user_action(); @@ -1225,7 +1340,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { return true; } //Indenting after for instance if(...)\n...;\n - else if(std::regex_match(line, sm, tabs_regex)) { + else if(iter.backward_char() && *iter==';') { std::smatch sm2; size_t line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); if(line_nr>0 && tabs.size()>=tab_size) { @@ -1246,11 +1361,15 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { } } } + 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) { - string line=get_line_before_insert(); + string line=get_line_before(); if(line.size()>=tab_size) { for(auto c: line) { if(c!=tab_char) { @@ -1334,7 +1453,7 @@ void Source::ClangViewAutocomplete::start_autocomplete() { autocomplete_cancel_starting=true; return; } - std::string line=" "+get_line_before_insert(); + std::string line=" "+get_line_before(); if((std::count(line.begin(), line.end(), '\"')%2)!=1 && line.find("//")==std::string::npos) { const std::regex in_specified_namespace("^(.*[a-zA-Z0-9_\\)\\]\\>])(->|\\.|::)([a-zA-Z0-9_]*)$"); const std::regex within_namespace("^(.*)([^a-zA-Z0-9_]+)([a-zA-Z0-9_]{3,})$"); diff --git a/src/source.h b/src/source.h index cbbfb6e..cd90d83 100644 --- a/src/source.h +++ b/src/source.h @@ -87,10 +87,16 @@ namespace Source { void set_status(const std::string &status); - std::string get_line(size_t line_number); - std::string get_line_before_insert(); + std::string get_line(const Gtk::TextIter &iter); + std::string get_line(Glib::RefPtr mark); + std::string get_line(int line_nr); + std::string get_line(); + std::string get_line_before(const Gtk::TextIter &iter); + std::string get_line_before(Glib::RefPtr mark); + std::string get_line_before(); bool find_start_of_sentence(Gtk::TextIter iter, Gtk::TextIter &found_iter); + bool find_open_symbol(Gtk::TextIter iter, const Gtk::TextIter &until_iter, Gtk::TextIter &found_iter); bool find_right_bracket_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter); bool on_key_press_event(GdkEventKey* key); From 8e31159dadabd915627f069b859eadb892ed551b Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 6 Sep 2015 14:18:26 +0200 Subject: [PATCH 26/37] Improved clang indentation. Its getting there. --- src/source.cc | 39 +++++++++++++++++---------------------- src/source.h | 8 ++++---- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/source.cc b/src/source.cc index ac84013..870909b 100644 --- a/src/source.cc +++ b/src/source.cc @@ -544,20 +544,19 @@ std::string Source::View::get_line_before() { return get_line_before(get_buffer()->get_insert()); } -bool Source::View::find_start_of_sentence(Gtk::TextIter iter, Gtk::TextIter &found_iter) { - while(iter.backward_char()) { +bool Source::View::find_start_of_closed_expression(Gtk::TextIter iter, Gtk::TextIter &found_iter) { + do { if(*iter!='{' && *iter!=' ' && *iter!='\t') break; if(iter.starts_line()) { found_iter=iter; return true; } - } + } while(iter.backward_char()); int count1=0; int count2=0; int count3=0; - int count4=0; bool ignore=false; @@ -576,18 +575,14 @@ bool Source::View::find_start_of_sentence(Gtk::TextIter iter, Gtk::TextIter &fou count1++; else if(*iter==']') count2++; - else if(*iter=='>') - count3++; else if(*iter=='}') - count4++; + count3++; else if(*iter=='(') count1--; else if(*iter=='[') count2--; - else if(*iter=='<') - count3--; else if(*iter=='{') - count4--; + count3--; } } if(iter.starts_line() && count1<=0 && count2<=0 && count3<=0) { @@ -598,10 +593,9 @@ bool Source::View::find_start_of_sentence(Gtk::TextIter iter, Gtk::TextIter &fou return false; } -bool Source::View::find_open_symbol(Gtk::TextIter iter, const Gtk::TextIter &until_iter, Gtk::TextIter &found_iter) { +bool Source::View::find_open_expression_symbol(Gtk::TextIter iter, const Gtk::TextIter &until_iter, Gtk::TextIter &found_iter) { int count1=0; int count2=0; - int count3=0; bool ignore=false; @@ -620,16 +614,12 @@ bool Source::View::find_open_symbol(Gtk::TextIter iter, const Gtk::TextIter &unt count1++; else if(*iter==']') count2++; - else if(*iter=='>') - count3++; else if(*iter=='(') count1--; else if(*iter=='[') count2--; - else if(*iter=='<') - count3--; } - if(count1<0 || count2<0 || count3<0) { + if(count1<0 || count2<0) { found_iter=iter; return true; } @@ -667,7 +657,8 @@ bool Source::View::find_right_bracket_forward(Gtk::TextIter iter, Gtk::TextIter } } - if(iter.starts_line() && *iter!=tab_char && !iter.ends_line() && *iter!='#') + //To avoid parsing of the whole file in case of erroneous brackets + if(iter.starts_line() && *iter!=tab_char && !iter.ends_line() && *iter!='#' && *iter!='p') //added p for public, private and protected keywords. return false; } return false; @@ -1258,9 +1249,13 @@ void Source::ClangViewParse::update_types() { } } -//Clang indentation -//TODO: replace indentation methods with a better implementation or maybe use libclang +//Clang indentation. bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { + if(spellcheck_suggestions_dialog_shown) { + if(spellcheck_suggestions_dialog->on_key_press(key)) + return true; + } + if(get_buffer()->get_has_selection()) { return Source::View::on_key_press_event(key); } @@ -1270,7 +1265,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { if(key->keyval==GDK_KEY_Return) { auto iter=get_buffer()->get_insert()->get_iter(); Gtk::TextIter start_of_sentence_iter; - if(find_start_of_sentence(iter, start_of_sentence_iter)) { + if(find_start_of_closed_expression(iter, start_of_sentence_iter)) { auto start_line=get_line(start_of_sentence_iter); std::smatch sm; std::string tabs; @@ -1321,7 +1316,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { auto line=get_line_before(); iter=get_buffer()->get_insert()->get_iter(); auto found_iter=iter; - if(find_open_symbol(iter, start_of_sentence_iter, found_iter)) { + if(find_open_expression_symbol(iter, start_of_sentence_iter, found_iter)) { auto offset=found_iter.get_line_offset(); tabs.clear(); for(int c=0;c mark); std::string get_line_before(); - bool find_start_of_sentence(Gtk::TextIter iter, Gtk::TextIter &found_iter); - bool find_open_symbol(Gtk::TextIter iter, const Gtk::TextIter &until_iter, Gtk::TextIter &found_iter); + bool find_start_of_closed_expression(Gtk::TextIter iter, Gtk::TextIter &found_iter); + bool find_open_expression_symbol(Gtk::TextIter iter, const Gtk::TextIter &until_iter, Gtk::TextIter &found_iter); bool find_right_bracket_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter); bool on_key_press_event(GdkEventKey* key); @@ -109,6 +109,8 @@ namespace Source { std::regex tabs_regex; bool spellcheck_all=false; + std::unique_ptr spellcheck_suggestions_dialog; + bool spellcheck_suggestions_dialog_shown=false; private: GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; @@ -121,8 +123,6 @@ namespace Source { std::pair spellcheck_get_word(Gtk::TextIter iter); void spellcheck_word(const Gtk::TextIter& start, const Gtk::TextIter& end); std::vector spellcheck_get_suggestions(const Gtk::TextIter& start, const Gtk::TextIter& end); - std::unique_ptr spellcheck_suggestions_dialog; - bool spellcheck_suggestions_dialog_shown=false; sigc::connection delayed_spellcheck_suggestions_connection; bool last_keyval_is_backspace=false; }; From c0ef562ea1a7ab2d36e22af21bf94969f3a99dde Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 6 Sep 2015 14:23:25 +0200 Subject: [PATCH 27/37] Removed check for erroneous brackets, the delay even in large files was acceptable. --- src/source.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/source.cc b/src/source.cc index 870909b..fc84387 100644 --- a/src/source.cc +++ b/src/source.cc @@ -656,10 +656,6 @@ bool Source::View::find_right_bracket_forward(Gtk::TextIter iter, Gtk::TextIter count++; } } - - //To avoid parsing of the whole file in case of erroneous brackets - if(iter.starts_line() && *iter!=tab_char && !iter.ends_line() && *iter!='#' && *iter!='p') //added p for public, private and protected keywords. - return false; } return false; } From a1c6ac6a209e16c98351c538534b7e90645e559a Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 6 Sep 2015 14:31:23 +0200 Subject: [PATCH 28/37] minor spellcheck fix. --- src/source.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index fc84387..efdd2ea 100644 --- a/src/source.cc +++ b/src/source.cc @@ -198,7 +198,7 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat if(!is_word_iter(iter)) { //Might have used space or - to split two words auto first=iter; auto second=iter; - if(first.backward_char() && second.forward_char()) { + if(first.backward_char() && second.forward_char() && !second.starts_line()) { get_buffer()->remove_tag_by_name("spellcheck_error", first, second); auto word=spellcheck_get_word(first); spellcheck_word(word.first, word.second); From e39533c1732e54c0c6d06e45d6e681915147ee98 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 6 Sep 2015 15:33:47 +0200 Subject: [PATCH 29/37] Clang indenting cleanup. --- src/source.cc | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/source.cc b/src/source.cc index efdd2ea..4f7bbc8 100644 --- a/src/source.cc +++ b/src/source.cc @@ -545,18 +545,8 @@ std::string Source::View::get_line_before() { } bool Source::View::find_start_of_closed_expression(Gtk::TextIter iter, Gtk::TextIter &found_iter) { - do { - if(*iter!='{' && *iter!=' ' && *iter!='\t') - break; - if(iter.starts_line()) { - found_iter=iter; - return true; - } - } while(iter.backward_char()); - int count1=0; int count2=0; - int count3=0; bool ignore=false; @@ -575,17 +565,13 @@ bool Source::View::find_start_of_closed_expression(Gtk::TextIter iter, Gtk::Text count1++; else if(*iter==']') count2++; - else if(*iter=='}') - count3++; else if(*iter=='(') count1--; else if(*iter=='[') count2--; - else if(*iter=='{') - count3--; } } - if(iter.starts_line() && count1<=0 && count2<=0 && count3<=0) { + if(iter.starts_line() && count1<=0 && count2<=0) { found_iter=iter; return true; } From 77c637a577fe870a599275b57179d3a1b052a9ea Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 6 Sep 2015 15:46:25 +0200 Subject: [PATCH 30/37] Minor clang indentation fix. --- src/source.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index 4f7bbc8..bc90924 100644 --- a/src/source.cc +++ b/src/source.cc @@ -572,6 +572,8 @@ bool Source::View::find_start_of_closed_expression(Gtk::TextIter iter, Gtk::Text } } if(iter.starts_line() && count1<=0 && count2<=0) { + auto insert_iter=get_buffer()->get_insert()->get_iter(); + while(iter!=insert_iter && *iter==tab_char && iter.forward_char()) {} found_iter=iter; return true; } @@ -1248,7 +1250,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { auto 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_line=get_line(start_of_sentence_iter); + auto start_line=get_line_before(start_of_sentence_iter); std::smatch sm; std::string tabs; if(std::regex_match(start_line, sm, tabs_regex)) { From 9e3fbd216e61ab32b239d05a99762ceb2833e980 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 6 Sep 2015 17:36:10 +0200 Subject: [PATCH 31/37] Removed reparse on tab switch after rename-refactoring, which is already reparsing affected buffers. --- src/notebook.cc | 16 +++++++++------- src/notebook.h | 2 +- src/source.cc | 2 +- src/source.h | 2 +- src/window.cc | 11 ++++++----- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/notebook.cc b/src/notebook.cc index 3d1ff49..459ce59 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -112,7 +112,7 @@ void Notebook::open(const boost::filesystem::path &file_path) { DEBUG("end"); } -bool Notebook::save(int page) { +bool Notebook::save(int page, bool reparse_needed) { DEBUG("start"); if(page>=size()) { DEBUG("end false"); @@ -121,11 +121,13 @@ bool Notebook::save(int page) { auto view=get_view(page); if (view->file_path != "" && view->get_buffer()->get_modified()) { if(juci::filesystem::write(view->file_path, view->get_buffer())) { - if(auto clang_view=dynamic_cast(view)) { - for(auto a_view: source_views) { - if(auto a_clang_view=dynamic_cast(a_view)) { - if(clang_view!=a_clang_view) - a_clang_view->start_reparse_needed=true; + if(reparse_needed) { + if(auto clang_view=dynamic_cast(view)) { + for(auto a_view: source_views) { + if(auto a_clang_view=dynamic_cast(a_view)) { + if(clang_view!=a_clang_view) + a_clang_view->reparse_needed=true; + } } } } @@ -161,7 +163,7 @@ bool Notebook::save(int page) { bool Notebook::save_current() { if(get_current_page()==-1) return false; - return save(get_current_page()); + return save(get_current_page(), true); } bool Notebook::close_current_page() { diff --git a/src/notebook.h b/src/notebook.h index a77040f..3c75e0c 100644 --- a/src/notebook.h +++ b/src/notebook.h @@ -18,7 +18,7 @@ public: Source::View* get_current_view(); bool close_current_page(); void open(const boost::filesystem::path &file_path); - bool save(int page); + bool save(int page, bool reparse_needed=false); bool save_current(); private: diff --git a/src/source.cc b/src/source.cc index bc90924..afa41d4 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1774,7 +1774,7 @@ void Source::ClangView::async_delete() { bool Source::ClangView::restart_parse() { if(!restart_parse_running) { - start_reparse_needed=false; + reparse_needed=false; restart_parse_running=true; parse_thread_stop=true; if(restart_parse_thread.joinable()) diff --git a/src/source.h b/src/source.h index 0d75d1f..0f62769 100644 --- a/src/source.h +++ b/src/source.h @@ -138,7 +138,7 @@ namespace Source { ~ClangViewParse(); boost::filesystem::path project_path; void start_reparse(); - bool start_reparse_needed=false; + bool reparse_needed=false; protected: void init_parse(); bool on_key_press_event(GdkEventKey* key); diff --git a/src/window.cc b/src/window.cc index eb73164..3b09318 100644 --- a/src/window.cc +++ b/src/window.cc @@ -104,9 +104,9 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil directories.select(notebook.get_current_view()->file_path); if(auto source_view=dynamic_cast(notebook.get_current_view())) { - if(source_view->start_reparse_needed) { + if(source_view->reparse_needed) { source_view->start_reparse(); - source_view->start_reparse_needed=false; + source_view->reparse_needed=false; } } @@ -688,10 +688,11 @@ void Window::rename_token_entry() { entry_box.entries.emplace_back(*token_name, [this, token_name, token](const std::string& content){ if(notebook.get_current_page()!=-1 && content!=*token_name) { for(int c=0;crename_similar_tokens) { - auto number=notebook.get_view(c)->rename_similar_tokens(*token, content); + auto view=notebook.get_view(c); + if(view->rename_similar_tokens) { + auto number=view->rename_similar_tokens(*token, content); if(number>0) { - Singleton::terminal()->print("Replaced "+boost::lexical_cast(number)+" occurrences in file "+notebook.get_view(c)->file_path.string()+"\n"); + Singleton::terminal()->print("Replaced "+boost::lexical_cast(number)+" occurrences in file "+view->file_path.string()+"\n"); notebook.save(c); } } From 49ccddf0ab969d168e960bb2fd13bedd6c8b33a6 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 7 Sep 2015 17:07:27 +0200 Subject: [PATCH 32/37] Fixed CMakeLists for OS X 10.10 I think. --- src/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2d43bff..3cbdb24 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,7 +3,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -std=c++11 -pthread -Wall -Wno-reord set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake/Modules/") if(APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L/usr/local/opt/gettext/lib -I/usr/local/opt/gettext/include -undefined dynamic_lookup") #T + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -undefined dynamic_lookup") + link_directories(/usr/local/lib /usr/local/opt/gettext/lib) + include_directories(/usr/local/opt/gettext/include) set(CMAKE_MACOSX_RPATH 1) set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig") endif() From c8da3bd03d36cf13f3fb950b2f4ac409976492b3 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 7 Sep 2015 18:44:59 +0200 Subject: [PATCH 33/37] Fixes #51. Removed carriage returns, which makes libclang report wrong line index. --- src/source.cc | 195 ++++++++++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 87 deletions(-) diff --git a/src/source.cc b/src/source.cc index afa41d4..c8fa338 100644 --- a/src/source.cc +++ b/src/source.cc @@ -404,104 +404,125 @@ void Source::View::replace_all(const std::string &replacement) { } void Source::View::paste() { - Gtk::Clipboard::get()->request_text([this](const Glib::ustring& text){ - auto line=get_line_before(); - std::smatch sm; - std::string prefix_tabs; - 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; - Glib::ustring::size_type end_line=0; - bool paste_line=false; - bool first_paste_line=true; - size_t paste_line_tabs=-1; - bool first_paste_line_has_tabs=false; - for(Glib::ustring::size_type c=0;cwait_for_text(); + //remove carriage returns (which makes clang return wrong line index) + for(auto it=text.begin();it!=text.end();) { + if(*it=='\r') { + auto it2=it; + it2++; + if(it2!=text.end()) { + if(*it2=='\n') + it=text.erase(it); + else { + text.replace(it, it2, "\n"); + it++; } - if(paste_line) { - bool empty_line=true; - std::string line=text.substr(start_line, end_line-start_line); - size_t tabs=0; - for(auto chr: line) { - if(chr==tab_char) - tabs++; - else { - empty_line=false; - break; - } + } + else + it=text.erase(it); + } + else + it++; + } + + auto line=get_line_before(); + std::smatch sm; + std::string prefix_tabs; + 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; + Glib::ustring::size_type end_line=0; + bool paste_line=false; + bool first_paste_line=true; + size_t paste_line_tabs=-1; + bool first_paste_line_has_tabs=false; + for(Glib::ustring::size_type c=0;cbegin_user_action(); - for(Glib::ustring::size_type c=0;cbegin_user_action(); + for(Glib::ustring::size_type c=0;cinsert_at_cursor(text.substr(start_line+tabs, end_line-start_line-tabs)); - else - get_buffer()->insert_at_cursor(text.substr(start_line, end_line-start_line)); - first_paste_line=false; - } + + if(first_paste_line) { + if(first_paste_line_has_tabs) + get_buffer()->insert_at_cursor(text.substr(start_line+tabs, end_line-start_line-tabs)); else - get_buffer()->insert_at_cursor('\n'+prefix_tabs+text.substr(start_line+tabs, end_line-start_line-tabs)); - start_line=end_line+1; - paste_line=false; + get_buffer()->insert_at_cursor(text.substr(start_line, end_line-start_line)); + first_paste_line=false; } + else + get_buffer()->insert_at_cursor('\n'+prefix_tabs+text.substr(start_line+tabs, end_line-start_line-tabs)); + start_line=end_line+1; + paste_line=false; } - get_buffer()->place_cursor(get_buffer()->get_insert()->get_iter()); - scroll_to(get_buffer()->get_insert()); - get_source_buffer()->end_user_action(); } - else - get_buffer()->paste_clipboard(Gtk::Clipboard::get()); - }); + get_buffer()->place_cursor(get_buffer()->get_insert()->get_iter()); + scroll_to(get_buffer()->get_insert()); + get_source_buffer()->end_user_action(); + } + else { + Gtk::Clipboard::get()->set_text(text); + get_buffer()->paste_clipboard(Gtk::Clipboard::get()); + } } void Source::View::set_status(const std::string &status) { From a3d950b6bcea113fce081c04bdd60fd67d47409d Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 7 Sep 2015 18:57:51 +0200 Subject: [PATCH 34/37] Improved fix for #51. Now only replaces stand-alone carriage returns with newlines. --- src/source.cc | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/source.cc b/src/source.cc index c8fa338..92186b9 100644 --- a/src/source.cc +++ b/src/source.cc @@ -405,24 +405,16 @@ void Source::View::replace_all(const std::string &replacement) { void Source::View::paste() { auto text=Gtk::Clipboard::get()->wait_for_text(); - //remove carriage returns (which makes clang return wrong line index) - for(auto it=text.begin();it!=text.end();) { + //replace stand-alone carriage returns (which makes clang return wrong line index) with newlines + for(auto it=text.begin();it!=text.end();it++) { if(*it=='\r') { auto it2=it; it2++; - if(it2!=text.end()) { - if(*it2=='\n') - it=text.erase(it); - else { + if(it2!=text.end() && *it2!='\n') text.replace(it, it2, "\n"); - it++; - } - } else - it=text.erase(it); + text.replace(it, it2, "\n"); } - else - it++; } auto line=get_line_before(); From ae26de286073099060ed5ca53b7f29ac0c2ee83d Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 7 Sep 2015 19:17:45 +0200 Subject: [PATCH 35/37] Finally fixes #51, now with correct if statement. --- src/source.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/source.cc b/src/source.cc index 92186b9..9380b7f 100644 --- a/src/source.cc +++ b/src/source.cc @@ -410,9 +410,7 @@ void Source::View::paste() { if(*it=='\r') { auto it2=it; it2++; - if(it2!=text.end() && *it2!='\n') - text.replace(it, it2, "\n"); - else + if(it2==text.end() || *it2!='\n') text.replace(it, it2, "\n"); } } From 6d8fb734f6ee6a05e93f26c8edc5f30c86f889a9 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 8 Sep 2015 12:44:18 +0200 Subject: [PATCH 36/37] Fixes #55 somehow. Stops clang-parse and autocomplete when error is detected. --- src/notebook.cc | 2 +- src/source.cc | 37 ++++++++++++++++++++++++++----------- src/source.h | 1 + 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/notebook.cc b/src/notebook.cc index 459ce59..7f472b5 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -145,7 +145,7 @@ bool Notebook::save(int page, bool reparse_needed) { if(source_clang_view->restart_parse()) Singleton::terminal()->async_print("Reparsing "+source_clang_view->file_path.string()+"\n"); else - Singleton::terminal()->async_print("Already reparsing "+source_clang_view->file_path.string()+". Please reopen the file manually.\n"); + Singleton::terminal()->async_print("Error: failed to reparse "+source_clang_view->file_path.string()+". Please reopen the file manually.\n"); } } } diff --git a/src/source.cc b/src/source.cc index 9380b7f..0e3ab19 100644 --- a/src/source.cc +++ b/src/source.cc @@ -980,6 +980,10 @@ Source::View(file_path), project_path(project_path) { parse_thread_go=true; } }); + parse_fail.connect([this](){ + Singleton::terminal()->print("Error: failed to reparse "+this->file_path.string()+".\n"); + set_status(""); + }); init_parse(); get_buffer()->signal_changed().connect([this]() { @@ -1006,7 +1010,6 @@ void Source::ClangViewParse::init_parse() { parse_thread_mapped=false; parse_thread_stop=false; - auto buffer_map=get_buffer_map(); //Remove includes for first parse for initial syntax highlighting auto& str=buffer_map[file_path.string()]; @@ -1023,7 +1026,7 @@ void Source::ClangViewParse::init_parse() { } init_syntax_highlighting(buffer_map); update_syntax(); - + set_status("parsing..."); if(parse_thread.joinable()) parse_thread.join(); @@ -1038,10 +1041,16 @@ void Source::ClangViewParse::init_parse() { parse_start(); } else if (parse_thread_mapped && parsing_mutex.try_lock() && parse_thread_buffer_map_mutex.try_lock()) { - reparse(parse_thread_buffer_map); + int status=reparse(parse_thread_buffer_map); parse_thread_go=false; + if(status!=0) + parse_thread_stop=true; parsing_mutex.unlock(); parse_thread_buffer_map_mutex.unlock(); + if(status!=0) { + parse_fail(); + return; + } parse_done(); } } @@ -1067,16 +1076,21 @@ void Source::ClangViewParse::start_reparse() { parse_thread_mapped=false; source_readable=false; delayed_reparse_connection.disconnect(); - delayed_reparse_connection=Glib::signal_timeout().connect([this]() { - source_readable=false; - parse_thread_go=true; - set_status("parsing..."); - return false; - }, 1000); + if(!parse_thread_stop) { + delayed_reparse_connection=Glib::signal_timeout().connect([this]() { + source_readable=false; + parse_thread_go=true; + set_status("parsing..."); + return false; + }, 1000); + } } int Source::ClangViewParse::reparse(const std::map &buffer) { int status = clang_tu->ReparseTranslationUnit(buffer); + if(status!=0) { + return status; + } clang_tokens=clang_tu->get_tokens(0, parse_thread_buffer_map.find(file_path.string())->second.size()-1); return status; } @@ -1564,7 +1578,8 @@ void Source::ClangViewAutocomplete::autocomplete() { autocomplete_thread.join(); autocomplete_thread=std::thread([this, ac_data, line_nr, column_nr, buffer_map](){ parsing_mutex.lock(); - *ac_data=move(get_autocomplete_suggestions(line_nr, column_nr, *buffer_map)); + if(!parse_thread_stop) + *ac_data=move(get_autocomplete_suggestions(line_nr, column_nr, *buffer_map)); autocomplete_done(); parsing_mutex.unlock(); }); @@ -1784,7 +1799,7 @@ void Source::ClangView::async_delete() { } bool Source::ClangView::restart_parse() { - if(!restart_parse_running) { + if(!restart_parse_running && !parse_thread_stop) { reparse_needed=false; restart_parse_running=true; parse_thread_stop=true; diff --git a/src/source.h b/src/source.h index 0f62769..e28b9d5 100644 --- a/src/source.h +++ b/src/source.h @@ -169,6 +169,7 @@ namespace Source { Glib::Dispatcher parse_done; Glib::Dispatcher parse_start; + Glib::Dispatcher parse_fail; std::map parse_thread_buffer_map; std::mutex parse_thread_buffer_map_mutex; std::atomic parse_thread_go; From 019f5172facea2be29a569a8d902ce9b2a4866ce Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 8 Sep 2015 12:54:17 +0200 Subject: [PATCH 37/37] Two minor fixes. --- src/source.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index 0e3ab19..2fa0193 100644 --- a/src/source.cc +++ b/src/source.cc @@ -584,7 +584,7 @@ bool Source::View::find_start_of_closed_expression(Gtk::TextIter iter, Gtk::Text } if(iter.starts_line() && count1<=0 && count2<=0) { auto insert_iter=get_buffer()->get_insert()->get_iter(); - while(iter!=insert_iter && *iter==tab_char && iter.forward_char()) {} + while(iter!=insert_iter && *iter==static_cast(tab_char) && iter.forward_char()) {} found_iter=iter; return true; } @@ -983,6 +983,7 @@ Source::View(file_path), project_path(project_path) { parse_fail.connect([this](){ Singleton::terminal()->print("Error: failed to reparse "+this->file_path.string()+".\n"); set_status(""); + parsing_in_progress->cancel("failed"); }); init_parse();