From 2a6460eb814f02c9ecf4617dd226044d415e58bb Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 18 Aug 2015 15:47:53 +0200 Subject: [PATCH 1/8] Now refreshes opened directories instead of completely reloading them. Tomorrow I'll add auto-update on the directories when files are added or deleted. --- src/directories.cc | 143 +++++++++++++++++++++++++++++++-------------- src/directories.h | 8 +-- 2 files changed, 103 insertions(+), 48 deletions(-) diff --git a/src/directories.cc b/src/directories.cc index 82d9dba..80db07c 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -3,7 +3,7 @@ #include "logging.h" #include "singletons.h" #include -#include "boost/algorithm/string.hpp" +#include #include //TODO: remove using namespace std; //TODO: remove @@ -19,31 +19,46 @@ Directories::Directories() { tree_store = Gtk::TreeStore::create(column_record); tree_view.set_model(tree_store); tree_view.append_column("", column_record.name); - tree_store->set_sort_column(0, Gtk::SortType::SORT_ASCENDING); + tree_store->set_sort_column(column_record.id, Gtk::SortType::SORT_ASCENDING); 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) { - Gtk::TreeModel::Row row = *iter; - std::string upath = Glib::ustring(row[column_record.path]); - boost::filesystem::path fs_path(upath); - if (boost::filesystem::is_directory(fs_path)) { + auto path_str=iter->get_value(column_record.path); + if (boost::filesystem::is_directory(boost::filesystem::path(path_str))) { tree_view.row_expanded(path) ? tree_view.collapse_row(path) : tree_view.expand_row(path, false); } else { - std::stringstream sstm; - sstm << row[column_record.path]; if(on_row_activated) - on_row_activated(sstm.str()); + on_row_activated(path_str); } } }); + + tree_view.signal_test_expand_row().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){ + if(iter->children().begin()->get_value(column_record.path)=="") { + add_path(iter->get_value(column_record.path), *iter); + } + return false; + }); + tree_view.signal_row_collapsed().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){ + auto children=iter->children(); + if(children) { + while(children) { + tree_store->erase(children.begin()); + } + tree_store->append(iter->children()); + } + }); } void Directories::open_folder(const boost::filesystem::path& dir_path) { + if(dir_path!="") + tree_store->clear(); + auto new_path=dir_path; INFO("Open folder"); - if(new_path=="") { + if(dir_path=="") { if(current_path=="") return; new_path=current_path; @@ -56,8 +71,6 @@ void Directories::open_folder(const boost::filesystem::path& dir_path) { }); } - tree_store->clear(); - if(dir_path!="") cmake=std::unique_ptr(new CMake(new_path)); auto project=cmake->get_functions_parameters("project"); @@ -65,19 +78,44 @@ void Directories::open_folder(const boost::filesystem::path& dir_path) { tree_view.get_column(0)->set_title(project[0].second[0]); else tree_view.get_column(0)->set_title(""); - add_paths(new_path, Gtk::TreeModel::Row(), 0); + add_path(new_path, Gtk::TreeModel::Row()); for(auto &path: expanded_paths) tree_view.expand_row(path, false); current_path=new_path; - if(selected_path!="") - select_path(selected_path); DEBUG("Folder opened"); } void Directories::select_path(const boost::filesystem::path &path) { + if(current_path=="") + return; + + if(path.string().substr(0, current_path.string().size())!=current_path.string()) + return; + + if(boost::filesystem::is_directory(path)) + return; + + std::list paths; + auto parent_path=path.parent_path(); + paths.emplace_front(parent_path); + while(parent_path!=current_path) { + parent_path=parent_path.parent_path(); + paths.emplace_front(parent_path); + } + + for(auto &a_path: paths) { + tree_store->foreach_iter([this, &a_path](const Gtk::TreeModel::iterator& iter){ + if(iter->get_value(column_record.path)==a_path.string()) { + add_path(a_path, *iter); + return true; + } + return false; + }); + } + tree_store->foreach_iter([this, &path](const Gtk::TreeModel::iterator& iter){ if(iter->get_value(column_record.path)==path.string()) { auto tree_path=Gtk::TreePath(iter); @@ -106,37 +144,54 @@ bool Directories::ignored(std::string path) { return false; } -void Directories::add_paths(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent, unsigned row_id) { - boost::filesystem::directory_iterator end_itr; - Gtk::TreeModel::Row child; - Gtk::TreeModel::Row row; - DEBUG(""); - // Fill the treeview - for(boost::filesystem::directory_iterator itr(dir_path);itr != end_itr;++itr) { - if (!ignored(itr->path().filename().string())) { - if (boost::filesystem::is_directory(itr->status())) { - if (boost::filesystem::canonical(itr->path()) > boost::filesystem::canonical(dir_path)) { // is child - child = *(tree_store->append(parent.children())); - std::string col_id("a"+itr->path().filename().string()); - child[column_record.id] = col_id; - child[column_record.name] = itr->path().filename().string(); - child[column_record.path] = itr->path().string(); - add_paths(itr->path(), child, row_id); - } else { - row = *(tree_store->append()); - std::string col_id("a"+itr->path().filename().string()); - row[column_record.path] = itr->path().string(); - row[column_record.id] = col_id; - row[column_record.name] = itr->path().filename().string(); - add_paths(itr->path(), parent, row_id); +void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) { + auto children=tree_store->children(); + if(parent) + children=parent.children(); + if(children) { + if(children.begin()->get_value(column_record.path)=="") { + tree_store->erase(parent->children().begin()); + } + } + std::unordered_set not_deleted; + boost::filesystem::directory_iterator end_it; + for(boost::filesystem::directory_iterator it(dir_path);it!=end_it;it++) { + auto filename=it->path().filename().string(); + if (!ignored(filename)) { + bool already_added=false; + if(children) { + for(auto &child: children) { + if(child.get_value(column_record.name)==filename) { + not_deleted.emplace(filename); + already_added=true; + break; + } + } + } + if(!already_added) { + auto child = tree_store->append(children); + not_deleted.emplace(filename); + child->set_value(column_record.name, filename); + child->set_value(column_record.path, it->path().string()); + if (boost::filesystem::is_directory(*it)) { + child->set_value(column_record.id, "a"+filename); + tree_store->append(child->children()); } - } else { // is a file - child = *(tree_store->append(parent.children())); - std::string col_id("b"+itr->path().filename().string()); - child[column_record.id] = col_id; - child[column_record.name] = itr->path().filename().string(); - child[column_record.path] = itr->path().string(); + else + child->set_value(column_record.id, "b"+filename); } } } + if(children) { + auto last_it=children.begin(); + for(auto it=children.begin();it!=children.end();it++) { + if(not_deleted.count(it->get_value(column_record.name))==0) { + tree_store->erase(it); + it=last_it; + } + last_it=it; + } + } + else + tree_store->append(children); } diff --git a/src/directories.h b/src/directories.h index d8dcb77..4b7b557 100644 --- a/src/directories.h +++ b/src/directories.h @@ -22,9 +22,9 @@ public: add(name); add(path); } - Gtk::TreeModelColumn id; - Gtk::TreeModelColumn name; - Gtk::TreeModelColumn path; + Gtk::TreeModelColumn id; + Gtk::TreeModelColumn name; + Gtk::TreeModelColumn path; }; Directories(); @@ -36,7 +36,7 @@ public: boost::filesystem::path current_path; private: - void add_paths(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &row, unsigned depth); + void add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &row); bool ignored(std::string path); Gtk::TreeView tree_view; Glib::RefPtr tree_store; From 50d684b5767916ee02bd1390c045129bac7201d6 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 19 Aug 2015 07:56:11 +0200 Subject: [PATCH 2/8] Directories now gets updated automatically when files are deleted, added or renamed (max 1 sec delay). --- src/directories.cc | 165 ++++++++++++++++++++++++++++++--------------- src/directories.h | 12 +++- src/juci.cc | 2 +- src/notebook.cc | 1 - src/window.cc | 19 ++---- src/window.h | 1 - 6 files changed, 127 insertions(+), 73 deletions(-) diff --git a/src/directories.cc b/src/directories.cc index 80db07c..72ad344 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -26,80 +26,121 @@ Directories::Directories() { auto iter = tree_store->get_iter(path); if (iter) { auto path_str=iter->get_value(column_record.path); - if (boost::filesystem::is_directory(boost::filesystem::path(path_str))) { - tree_view.row_expanded(path) ? tree_view.collapse_row(path) : tree_view.expand_row(path, false); - } else { - if(on_row_activated) - on_row_activated(path_str); + if(path_str!="") { + if (boost::filesystem::is_directory(boost::filesystem::path(path_str))) { + tree_view.row_expanded(path) ? tree_view.collapse_row(path) : tree_view.expand_row(path, false); + } else { + if(on_row_activated) + on_row_activated(path_str); + } } } }); tree_view.signal_test_expand_row().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){ if(iter->children().begin()->get_value(column_record.path)=="") { + update_mutex.lock(); add_path(iter->get_value(column_record.path), *iter); + update_mutex.unlock(); } return false; }); tree_view.signal_row_collapsed().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){ + update_mutex.lock(); + last_write_times.erase(iter->get_value(column_record.path)); + update_mutex.unlock(); auto children=iter->children(); if(children) { while(children) { tree_store->erase(children.begin()); } - tree_store->append(iter->children()); + auto child=tree_store->append(iter->children()); + child->set_value(column_record.name, std::string("(empty)")); } }); + + update_dispatcher.connect([this](){ + update_mutex.lock(); + for(auto &path: update_paths) { + if(last_write_times.count(path)>0) + add_path(path, last_write_times.at(path).first); + } + update_paths.clear(); + update_mutex.unlock(); + }); + + std::thread update_thread([this](){ + while(true) { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + update_mutex.lock(); + if(update_paths.size()==0) { + for(auto &last_write_time: last_write_times) { + try { + if(last_write_time.second.second0) + update_dispatcher(); + } + update_mutex.unlock(); + } + }); + update_thread.detach(); } -void Directories::open_folder(const boost::filesystem::path& dir_path) { - if(dir_path!="") - tree_store->clear(); +void Directories::open(const boost::filesystem::path& dir_path) { + if(dir_path=="") + return; - auto new_path=dir_path; INFO("Open folder"); - if(dir_path=="") { - if(current_path=="") - return; - new_path=current_path; - } - std::vector expanded_paths; - if(current_path==new_path) { - tree_view.map_expanded_rows([&expanded_paths](Gtk::TreeView* tree_view, const Gtk::TreeModel::Path& path){ - expanded_paths.emplace_back(path); - }); - } - - if(dir_path!="") - cmake=std::unique_ptr(new CMake(new_path)); + tree_store->clear(); + update_mutex.lock(); + last_write_times.clear(); + update_paths.clear(); + update_mutex.unlock(); + + cmake=std::unique_ptr(new CMake(dir_path)); auto project=cmake->get_functions_parameters("project"); if(project.size()>0 && project[0].second.size()>0) tree_view.get_column(0)->set_title(project[0].second[0]); else tree_view.get_column(0)->set_title(""); - add_path(new_path, Gtk::TreeModel::Row()); - - for(auto &path: expanded_paths) - tree_view.expand_row(path, false); + update_mutex.lock(); + add_path(dir_path, Gtk::TreeModel::Row()); + update_mutex.unlock(); - current_path=new_path; + current_path=dir_path; DEBUG("Folder opened"); } -void Directories::select_path(const boost::filesystem::path &path) { +void Directories::update() { + 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(); +} + +void Directories::select(const boost::filesystem::path &path) { if(current_path=="") return; if(path.string().substr(0, current_path.string().size())!=current_path.string()) return; - if(boost::filesystem::is_directory(path)) - return; - std::list paths; - auto parent_path=path.parent_path(); + boost::filesystem::path parent_path; + if(boost::filesystem::is_directory(path)) + parent_path=path; + else + parent_path=path.parent_path(); paths.emplace_front(parent_path); while(parent_path!=current_path) { parent_path=parent_path.parent_path(); @@ -109,7 +150,9 @@ void Directories::select_path(const boost::filesystem::path &path) { for(auto &a_path: paths) { tree_store->foreach_iter([this, &a_path](const Gtk::TreeModel::iterator& iter){ if(iter->get_value(column_record.path)==a_path.string()) { + update_mutex.lock(); add_path(a_path, *iter); + update_mutex.unlock(); return true; } return false; @@ -121,7 +164,6 @@ void Directories::select_path(const boost::filesystem::path &path) { auto tree_path=Gtk::TreePath(iter); tree_view.expand_to_path(tree_path); tree_view.set_cursor(tree_path); - selected_path=path; return true; } return false; @@ -145,13 +187,15 @@ bool Directories::ignored(std::string path) { } void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) { - auto children=tree_store->children(); + 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) - children=parent.children(); - if(children) { - if(children.begin()->get_value(column_record.path)=="") { - tree_store->erase(parent->children().begin()); - } + children=std::unique_ptr(new Gtk::TreeNodeChildren(parent.children())); + else + children=std::unique_ptr(new Gtk::TreeNodeChildren(tree_store->children())); + if(*children) { + if(children->begin()->get_value(column_record.path)=="") + tree_store->erase(children->begin()); } std::unordered_set not_deleted; boost::filesystem::directory_iterator end_it; @@ -159,8 +203,8 @@ void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::T auto filename=it->path().filename().string(); if (!ignored(filename)) { bool already_added=false; - if(children) { - for(auto &child: children) { + if(*children) { + for(auto &child: *children) { if(child.get_value(column_record.name)==filename) { not_deleted.emplace(filename); already_added=true; @@ -169,29 +213,44 @@ void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::T } } if(!already_added) { - auto child = tree_store->append(children); + auto child = tree_store->append(*children); not_deleted.emplace(filename); child->set_value(column_record.name, filename); child->set_value(column_record.path, it->path().string()); if (boost::filesystem::is_directory(*it)) { child->set_value(column_record.id, "a"+filename); - tree_store->append(child->children()); + auto grandchild=tree_store->append(child->children()); + grandchild->set_value(column_record.name, std::string("(empty)")); } else child->set_value(column_record.id, "b"+filename); } } } - if(children) { - auto last_it=children.begin(); - for(auto it=children.begin();it!=children.end();it++) { + if(*children) { + auto last_it=children->begin(); + auto it=last_it; + while(it!=children->end()) { if(not_deleted.count(it->get_value(column_record.name))==0) { - tree_store->erase(it); - it=last_it; + if(it==children->begin()) { + tree_store->erase(it); + it=children->begin(); + last_it=it; + } + else { + tree_store->erase(it); + it=last_it; + it++; + } + } + else { + last_it=it; + it++; } - last_it=it; } } - else - tree_store->append(children); + if(!*children) { + auto child=tree_store->append(*children); + child->set_value(column_record.name, std::string("(empty)")); + } } diff --git a/src/directories.h b/src/directories.h index 4b7b557..1b0d6f0 100644 --- a/src/directories.h +++ b/src/directories.h @@ -6,6 +6,8 @@ #include #include "boost/filesystem.hpp" #include "cmake.h" +#include +#include class Directories : public Gtk::ScrolledWindow { public: @@ -28,8 +30,9 @@ public: }; Directories(); - void open_folder(const boost::filesystem::path& dir_path=""); - void select_path(const boost::filesystem::path &path); + void open(const boost::filesystem::path& dir_path=""); + void update(); + void select(const boost::filesystem::path &path); std::function on_row_activated; std::unique_ptr cmake; @@ -41,7 +44,10 @@ private: Gtk::TreeView tree_view; Glib::RefPtr tree_store; ColumnRecord column_record; - boost::filesystem::path selected_path; + std::unordered_map > last_write_times; + std::mutex update_mutex; + Glib::Dispatcher update_dispatcher; + std::vector update_paths; }; #endif // JUCI_DIRECTORIES_H_ diff --git a/src/juci.cc b/src/juci.cc index 68623ea..6390d3d 100644 --- a/src/juci.cc +++ b/src/juci.cc @@ -45,7 +45,7 @@ void app::on_activate() { bool first_directory=true; for(auto &directory: directories) { if(first_directory) { - window->directories.open_folder(directory); + window->directories.open(directory); first_directory=false; } else { diff --git a/src/notebook.cc b/src/notebook.cc index 3bc8f0e..7bfd4f9 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -120,7 +120,6 @@ bool Notebook::save(int page) { //TODO: recreate cmake even without directories open? if(view->file_path.filename()=="CMakeLists.txt") { if(directories.cmake && directories.cmake->project_path!="" && view->file_path.string().substr(0, directories.cmake->project_path.string().size())==directories.cmake->project_path.string() && CMake::create_compile_commands(directories.cmake->project_path)) { - directories.open_folder(); for(auto source_view: source_views) { if(auto source_clang_view=dynamic_cast(source_view)) { if(directories.cmake->project_path.string()==source_clang_view->project_path) { diff --git a/src/window.cc b/src/window.cc index 11e4722..be27f3c 100644 --- a/src/window.cc +++ b/src/window.cc @@ -91,7 +91,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil if(auto menu_item=dynamic_cast(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceRename"))) menu_item->set_sensitive((bool)notebook.get_current_view()->rename_similar_tokens); - directories.select_path(notebook.get_current_view()->file_path); + directories.select(notebook.get_current_view()->file_path); Singleton::status()->set_text(notebook.get_current_view()->status); } @@ -99,10 +99,6 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil notebook.signal_page_removed().connect([this](Gtk::Widget* page, guint page_num) { entry_box.hide(); }); - - compile_success.connect([this](){ - directories.open_folder(); - }); INFO("Window created"); } // Window constructor @@ -217,7 +213,6 @@ void Window::create_menu() { if(notebook.get_current_page()==-1 || compiling) return; CMake cmake(notebook.get_current_view()->file_path); - directories.open_folder(); auto executables = cmake.get_functions_parameters("add_executable"); boost::filesystem::path executable_path; if(executables.size()>0 && executables[0].second.size()>0) { @@ -233,7 +228,6 @@ void Window::create_menu() { Singleton::terminal()->async_execute(Singleton::Config::terminal()->make_command, cmake.project_path, [this, executable_path, project_path](int exit_code){ compiling=false; if(exit_code==EXIT_SUCCESS) { - compile_success(); //TODO: Windows... auto executable_path_spaces_fixed=executable_path.string(); char last_char=0; @@ -261,15 +255,12 @@ void Window::create_menu() { if(notebook.get_current_page()==-1 || compiling) return; CMake cmake(notebook.get_current_view()->file_path); - directories.open_folder(); if(cmake.project_path!="") { compiling=true; Singleton::terminal()->print("Compiling project "+cmake.project_path.string()+"\n"); //TODO: Windows... Singleton::terminal()->async_execute(Singleton::Config::terminal()->make_command, cmake.project_path, [this](int exit_code){ compiling=false; - if(exit_code==EXIT_SUCCESS) - compile_success(); }); } }); @@ -369,7 +360,7 @@ void Window::new_file_entry() { else { if(juci::filesystem::write(p)) { if(directories.current_path!="") - directories.open_folder(); + directories.update(); notebook.open(boost::filesystem::canonical(p).string()); Singleton::terminal()->print("New file "+p.string()+" created.\n"); } @@ -420,7 +411,7 @@ void Window::new_cpp_project_dialog() { std::string cmakelists="cmake_minimum_required(VERSION 2.8)\n\nproject("+project_name+")\n\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++1y -Wall\")\n\nadd_executable("+project_name+" main.cpp)\n"; std::string cpp_main="#include \n\nusing namespace std;\n\nint main() {\n cout << \"Hello World!\" << endl;\n\n return 0;\n}\n"; if(juci::filesystem::write(cmakelists_path, cmakelists) && juci::filesystem::write(cpp_main_path, cpp_main)) { - directories.open_folder(project_path); + directories.open(project_path); notebook.open(cpp_main_path); Singleton::terminal()->print("C++ project "+project_name+" created.\n"); } @@ -444,7 +435,7 @@ void Window::open_folder_dialog() { if(result==Gtk::RESPONSE_OK) { std::string project_path=dialog.get_filename(); - directories.open_folder(project_path); + directories.open(project_path); } } @@ -506,7 +497,7 @@ void Window::save_file_dialog() { file << notebook.get_current_view()->get_buffer()->get_text(); file.close(); if(directories.current_path!="") - directories.open_folder(); + directories.update(); notebook.open(path); Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n"); } diff --git a/src/window.h b/src/window.h index dbb08eb..3d2cf65 100644 --- a/src/window.h +++ b/src/window.h @@ -36,7 +36,6 @@ private: EntryBox entry_box; Menu menu; std::atomic compiling; - Glib::Dispatcher compile_success; void create_menu(); void hide(); From a67230499f6274a4cc56f33298059c26850ed478 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 19 Aug 2015 09:17:59 +0200 Subject: [PATCH 3/8] Fixed some issues with directories. --- src/directories.cc | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/directories.cc b/src/directories.cc index 72ad344..8f2e5d1 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -74,14 +74,19 @@ Directories::Directories() { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); update_mutex.lock(); if(update_paths.size()==0) { - for(auto &last_write_time: last_write_times) { + for(auto it=last_write_times.begin();it!=last_write_times.end();) { try { - if(last_write_time.second.secondfirst)) { //Added for older boost versions (no exception thrown) + if(it->second.secondfirst)) { + update_paths.emplace_back(it->first); + } + it++; } + else + it=last_write_times.erase(it); } catch(const std::exception &e) { - last_write_times.erase(last_write_time.first); + it=last_write_times.erase(it); } } if(update_paths.size()>0) @@ -228,25 +233,12 @@ void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::T } } if(*children) { - auto last_it=children->begin(); - auto it=last_it; - while(it!=children->end()) { + for(auto it=children->begin();it!=children->end();) { if(not_deleted.count(it->get_value(column_record.name))==0) { - if(it==children->begin()) { - tree_store->erase(it); - it=children->begin(); - last_it=it; - } - else { - tree_store->erase(it); - it=last_it; - it++; - } + it=tree_store->erase(it); } - else { - last_it=it; + else it++; - } } } if(!*children) { From a794bd5eec4933b240a51bbe1a89a44797bef70f Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 19 Aug 2015 10:10:44 +0200 Subject: [PATCH 4/8] Fixed a couple of crashes. most notably a crash in diagnostics when writing an extra } in the middle of code. --- src/directories.cc | 12 ++++++++---- src/directories.h | 4 ++++ src/source.cc | 26 ++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/directories.cc b/src/directories.cc index 8f2e5d1..fb91c97 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -12,7 +12,7 @@ namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE } -Directories::Directories() { +Directories::Directories() : stop_update_thread(false) { DEBUG("adding treeview to scrolledwindow"); add(tree_view); set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); @@ -69,8 +69,8 @@ Directories::Directories() { update_mutex.unlock(); }); - std::thread update_thread([this](){ - while(true) { + update_thread=std::thread([this](){ + while(!stop_update_thread) { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); update_mutex.lock(); if(update_paths.size()==0) { @@ -95,7 +95,11 @@ Directories::Directories() { update_mutex.unlock(); } }); - update_thread.detach(); +} + +Directories::~Directories() { + stop_update_thread=true; + update_thread.join(); } void Directories::open(const boost::filesystem::path& dir_path) { diff --git a/src/directories.h b/src/directories.h index 1b0d6f0..c34e319 100644 --- a/src/directories.h +++ b/src/directories.h @@ -8,6 +8,7 @@ #include "cmake.h" #include #include +#include class Directories : public Gtk::ScrolledWindow { public: @@ -30,6 +31,7 @@ public: }; Directories(); + ~Directories(); void open(const boost::filesystem::path& dir_path=""); void update(); void select(const boost::filesystem::path &path); @@ -46,6 +48,8 @@ private: ColumnRecord column_record; std::unordered_map > last_write_times; std::mutex update_mutex; + std::thread update_thread; + std::atomic stop_update_thread; Glib::Dispatcher update_dispatcher; std::vector update_paths; }; diff --git a/src/source.cc b/src/source.cc index 47f36d6..1948282 100644 --- a/src/source.cc +++ b/src/source.cc @@ -658,8 +658,24 @@ void Source::ClangViewParse::update_diagnostics() { auto diagnostics=clang_tu->get_diagnostics(); for(auto &diagnostic: diagnostics) { if(diagnostic.path==file_path.string()) { - auto start=get_buffer()->get_iter_at_line_index(diagnostic.offsets.first.line-1, diagnostic.offsets.first.index-1); - auto end=get_buffer()->get_iter_at_line_index(diagnostic.offsets.second.line-1, diagnostic.offsets.second.index-1); + 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.size()==0) + start_line_index=0; + else + 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; + if(end_line_index>=end_line.size()) { + if(end_line.size()==0) + end_line_index=0; + else + end_line_index=end_line.size()-1; + } + 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); std::string diagnostic_tag_name; if(diagnostic.severity<=CXDiagnostic_Warning) diagnostic_tag_name="def:warning"; @@ -846,8 +862,9 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { if(line.size()>=config->tab_size) { for(auto c: line) { if(c!=config->tab_char) { + get_source_buffer()->insert_at_cursor("}"); get_source_buffer()->end_user_action(); - return Source::View::on_key_press_event(key); + return true; } } Gtk::TextIter insert_it = get_source_buffer()->get_insert()->get_iter(); @@ -858,8 +875,9 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { get_source_buffer()->erase(line_it, line_plus_it); } + get_source_buffer()->insert_at_cursor("}"); get_source_buffer()->end_user_action(); - return Source::View::on_key_press_event(key); + return true; } get_source_buffer()->end_user_action(); From d59d925ce74e1bff1bcf16ae314573c5caea0244 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 19 Aug 2015 11:16:19 +0200 Subject: [PATCH 5/8] Fixes #40 among other things. Some cleanup of dialogs. Remember to rm ~/.juci to get updated menu and keybindings. --- src/files.h | 4 +- src/window.cc | 134 +++++++++++++++++++++++++++----------------------- src/window.h | 3 +- 3 files changed, 77 insertions(+), 64 deletions(-) diff --git a/src/files.h b/src/files.h index 4312334..eea021b 100644 --- a/src/files.h +++ b/src/files.h @@ -30,7 +30,8 @@ const std::string configjson = " },\n" " \"keybindings\": {\n" " \"new_file\": \"n\",\n" -" \"open_folder\": \"o\",\n" +" \"new_folder\": \"n\",\n" +" \"open_folder\": \"o\",\n" " \"open_file\": \"o\",\n" " \"save\": \"s\",\n" " \"save_as\": \"s\",\n" @@ -76,6 +77,7 @@ const std::string menuxml = " \n" " \n" " \n" +" \n" " \n" " \n" " \n" diff --git a/src/window.cc b/src/window.cc index be27f3c..2aa0100 100644 --- a/src/window.cc +++ b/src/window.cc @@ -108,20 +108,23 @@ void Window::create_menu() { menu.action_group->add(Gtk::Action::create("FileQuit", "Quit juCi++"), Gtk::AccelKey(menu.key_map["quit"]), [this]() { hide(); }); - menu.action_group->add(Gtk::Action::create("FileNewFile", "New file"), Gtk::AccelKey(menu.key_map["new_file"]), [this]() { - new_file_entry(); + menu.action_group->add(Gtk::Action::create("FileNewFile", "New File"), Gtk::AccelKey(menu.key_map["new_file"]), [this]() { + new_file_dialog(); + }); + menu.action_group->add(Gtk::Action::create("FileNewFolder", "New Folder"), Gtk::AccelKey(menu.key_map["new_folder"]), [this]() { + new_folder_dialog(); }); menu.action_group->add(Gtk::Action::create("FileNewProject", "New Project")); menu.action_group->add(Gtk::Action::create("FileNewProjectCpp", "C++"), [this]() { new_cpp_project_dialog(); }); - menu.action_group->add(Gtk::Action::create("FileOpenFile", "Open file"), Gtk::AccelKey(menu.key_map["open_file"]), [this]() { + menu.action_group->add(Gtk::Action::create("FileOpenFile", "Open File"), Gtk::AccelKey(menu.key_map["open_file"]), [this]() { open_file_dialog(); }); - menu.action_group->add(Gtk::Action::create("FileOpenFolder", "Open folder"), Gtk::AccelKey(menu.key_map["open_folder"]), [this]() { + menu.action_group->add(Gtk::Action::create("FileOpenFolder", "Open Folder"), Gtk::AccelKey(menu.key_map["open_folder"]), [this]() { open_folder_dialog(); }); - menu.action_group->add(Gtk::Action::create("FileSaveAs", "Save as"), Gtk::AccelKey(menu.key_map["save_as"]), [this]() { + menu.action_group->add(Gtk::Action::create("FileSaveAs", "Save As"), Gtk::AccelKey(menu.key_map["save_as"]), [this]() { save_file_dialog(); }); @@ -174,17 +177,17 @@ void Window::create_menu() { INFO("Done Redo"); }); - menu.action_group->add(Gtk::Action::create("SourceGotoLine", "Go to line"), Gtk::AccelKey(menu.key_map["source_goto_line"]), [this]() { + menu.action_group->add(Gtk::Action::create("SourceGotoLine", "Go to Line"), Gtk::AccelKey(menu.key_map["source_goto_line"]), [this]() { goto_line_entry(); }); - menu.action_group->add(Gtk::Action::create("SourceCenterCursor", "Center cursor"), Gtk::AccelKey(menu.key_map["source_center_cursor"]), [this]() { + menu.action_group->add(Gtk::Action::create("SourceCenterCursor", "Center Cursor"), Gtk::AccelKey(menu.key_map["source_center_cursor"]), [this]() { 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); } }); - menu.action_group->add(Gtk::Action::create("SourceGotoDeclaration", "Go to declaration"), Gtk::AccelKey(menu.key_map["source_goto_declaration"]), [this]() { + menu.action_group->add(Gtk::Action::create("SourceGotoDeclaration", "Go to Declaration"), Gtk::AccelKey(menu.key_map["source_goto_declaration"]), [this]() { if(notebook.get_current_page()!=-1) { if(notebook.get_current_view()->get_declaration_location) { auto location=notebook.get_current_view()->get_declaration_location(); @@ -198,7 +201,7 @@ void Window::create_menu() { } } }); - menu.action_group->add(Gtk::Action::create("SourceGotoMethod", "Go to method"), Gtk::AccelKey(menu.key_map["source_goto_method"]), [this]() { + menu.action_group->add(Gtk::Action::create("SourceGotoMethod", "Go to Method"), Gtk::AccelKey(menu.key_map["source_goto_method"]), [this]() { if(notebook.get_current_page()!=-1) { if(notebook.get_current_view()->goto_method) { notebook.get_current_view()->goto_method(); @@ -209,7 +212,7 @@ void Window::create_menu() { rename_token_entry(); }); - menu.action_group->add(Gtk::Action::create("ProjectCompileAndRun", "Compile And Run"), Gtk::AccelKey(menu.key_map["compile_and_run"]), [this]() { + menu.action_group->add(Gtk::Action::create("ProjectCompileAndRun", "Compile and Run"), Gtk::AccelKey(menu.key_map["compile_and_run"]), [this]() { if(notebook.get_current_page()==-1 || compiling) return; CMake cmake(notebook.get_current_view()->file_path); @@ -289,7 +292,7 @@ void Window::create_menu() { Singleton::terminal()->kill_last_async_execute(true); }); - menu.action_group->add(Gtk::Action::create("WindowCloseTab", "Close tab"), Gtk::AccelKey(menu.key_map["close_tab"]), [this]() { + menu.action_group->add(Gtk::Action::create("WindowCloseTab", "Close Tab"), Gtk::AccelKey(menu.key_map["close_tab"]), [this]() { notebook.close_current_page(); }); add_accel_group(menu.ui_manager->get_accel_group()); @@ -346,35 +349,62 @@ void Window::hide() { Gtk::Window::hide(); } -void Window::new_file_entry() { - entry_box.clear(); - entry_box.entries.emplace_back("untitled", [this](const std::string& content){ - std::string filename=content; - if(filename!="") { - if(directories.current_path!="" && !boost::filesystem::path(filename).is_absolute()) - filename=directories.current_path.string()+"/"+filename; - boost::filesystem::path p(filename); - if(boost::filesystem::exists(p)) { - Singleton::terminal()->print("Error: "+p.string()+" already exists.\n"); +void Window::new_file_dialog() { + Gtk::FileChooserDialog dialog("Please create a new file", Gtk::FILE_CHOOSER_ACTION_SAVE); + if(directories.current_path!="") + gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), directories.current_path.string().c_str()); + else + gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); + dialog.set_transient_for(*this); + dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); + dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("Save", Gtk::RESPONSE_OK); + + int result = dialog.run(); + if(result==Gtk::RESPONSE_OK) { + boost::filesystem::path path = dialog.get_filename(); + if(path!="") { + if(boost::filesystem::exists(path)) { + Singleton::terminal()->print("Error: "+path.string()+" already exists.\n"); } else { - if(juci::filesystem::write(p)) { + if(juci::filesystem::write(path)) { if(directories.current_path!="") directories.update(); - notebook.open(boost::filesystem::canonical(p).string()); - Singleton::terminal()->print("New file "+p.string()+" created.\n"); + notebook.open(path.string()); + Singleton::terminal()->print("New file "+path.string()+" created.\n"); } else - Singleton::terminal()->print("Error: could not create new file "+p.string()+".\n"); + Singleton::terminal()->print("Error: could not create new file "+path.string()+".\n"); } } - entry_box.hide(); - }); - auto entry_it=entry_box.entries.begin(); - entry_box.buttons.emplace_back("Create file", [this, entry_it](){ - entry_it->activate(); - }); - entry_box.show(); + } +} + +void Window::new_folder_dialog() { + auto time_now=std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + Gtk::FileChooserDialog dialog("Please create a new folder", Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER); + if(directories.current_path!="") + gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), directories.current_path.string().c_str()); + else + gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); + dialog.set_transient_for(*this); + dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); + dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("Create", Gtk::RESPONSE_OK); + + int result = dialog.run(); + if(result==Gtk::RESPONSE_OK) { + boost::filesystem::path path=dialog.get_filename(); + if(boost::filesystem::last_write_time(path)>=time_now) { + if(directories.current_path!="") + directories.update(); + Singleton::terminal()->print("New folder "+path.string()+" created.\n"); + } + else + Singleton::terminal()->print("Error: "+path.string()+" already exists.\n"); + directories.select(path); + } } void Window::new_cpp_project_dialog() { @@ -384,9 +414,9 @@ void Window::new_cpp_project_dialog() { else gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); dialog.set_transient_for(*this); - - dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); - dialog.add_button("Select", Gtk::RESPONSE_OK); + dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); + dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("Create", Gtk::RESPONSE_OK); int result = dialog.run(); if(result==Gtk::RESPONSE_OK) { @@ -427,9 +457,9 @@ void Window::open_folder_dialog() { else gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); dialog.set_transient_for(*this); - //Add response buttons the the dialog: - dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); - dialog.add_button("Select", Gtk::RESPONSE_OK); + dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); + dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("Open", Gtk::RESPONSE_OK); int result = dialog.run(); @@ -447,28 +477,8 @@ void Window::open_file_dialog() { gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); dialog.set_transient_for(*this); dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); - - //Add response buttons the the dialog: - dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); - dialog.add_button("_Open", Gtk::RESPONSE_OK); - - //Add filters, so that only certain file types can be selected: - Glib::RefPtr filter_text = Gtk::FileFilter::create(); - filter_text->set_name("Text files"); - filter_text->add_mime_type("text/plain"); - dialog.add_filter(filter_text); - - Glib::RefPtr filter_cpp = Gtk::FileFilter::create(); - filter_cpp->set_name("C/C++ files"); - filter_cpp->add_mime_type("text/x-c"); - filter_cpp->add_mime_type("text/x-c++"); - filter_cpp->add_mime_type("text/x-c-header"); - dialog.add_filter(filter_cpp); - - Glib::RefPtr filter_any = Gtk::FileFilter::create(); - filter_any->set_name("Any files"); - filter_any->add_pattern("*"); - dialog.add_filter(filter_any); + dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("Open", Gtk::RESPONSE_OK); int result = dialog.run(); @@ -485,8 +495,8 @@ void Window::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.c_str()); dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); - dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); - dialog.add_button("_Save", Gtk::RESPONSE_OK); + dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("Save", Gtk::RESPONSE_OK); int result = dialog.run(); if(result==Gtk::RESPONSE_OK) { diff --git a/src/window.h b/src/window.h index 3d2cf65..b18ae0f 100644 --- a/src/window.h +++ b/src/window.h @@ -39,7 +39,8 @@ private: void create_menu(); void hide(); - void new_file_entry(); + void new_file_dialog(); + void new_folder_dialog(); void new_cpp_project_dialog(); void open_folder_dialog(); void open_file_dialog(); From bfd248216320babc02a29f1acbfddcbfa558c640 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 19 Aug 2015 14:39:04 +0200 Subject: [PATCH 6/8] Added search to directories. --- src/directories.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/directories.cc b/src/directories.cc index fb91c97..edf3ea7 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -20,6 +20,8 @@ Directories::Directories() : stop_update_thread(false) { tree_view.set_model(tree_store); tree_view.append_column("", column_record.name); tree_store->set_sort_column(column_record.id, Gtk::SortType::SORT_ASCENDING); + tree_view.set_enable_search(true); //TODO: why does this not work in OS X? + 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"); From d66d1f5a97844cff63dee17a90fb1d2bd102fef1 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 20 Aug 2015 09:48:05 +0200 Subject: [PATCH 7/8] Now automatically finds tab char and size, if not turned off in config.json. Please remove ~/.juci before running. --- src/config.cc | 7 ++- src/files.h | 5 +- src/source.cc | 138 +++++++++++++++++++++++++++++++++++++------------- src/source.h | 17 +++++-- 4 files changed, 124 insertions(+), 43 deletions(-) diff --git a/src/config.cc b/src/config.cc index 7a433fb..f41feb4 100644 --- a/src/config.cc +++ b/src/config.cc @@ -45,10 +45,9 @@ void MainConfig::GenerateSource() { auto source_cfg = Singleton::Config::source(); auto source_json = cfg.get_child("source"); - source_cfg->tab_size = source_json.get("tab_size"); - source_cfg->tab_char = source_json.get("tab_char"); - for(unsigned c=0;ctab_size;c++) - source_cfg->tab+=source_cfg->tab_char; + source_cfg->default_tab_char = source_json.get("default_tab_char"); + source_cfg->default_tab_size = source_json.get("default_tab_size"); + source_cfg->auto_tab_char_and_size = source_json.get("auto_tab_char_and_size"); source_cfg->highlight_current_line = source_json.get_value("highlight_current_line"); source_cfg->show_line_numbers = source_json.get_value("show_line_numbers"); diff --git a/src/files.h b/src/files.h index eea021b..1370fa9 100644 --- a/src/files.h +++ b/src/files.h @@ -23,8 +23,9 @@ const std::string configjson = " \"702\": \"def:statement\",\n" " \"705\": \"def:comment\"\n" " },\n" -" \"tab_size\": 2,\n" -" \"tab_char\": \" \", //Use \"\\t\" for regular tab\n" +" \"auto_tab_char_and_size\": true, //Use false to always use default tab char and size\n" +" \"default_tab_char\": \" \", //Use \"\\t\" for regular tab\n" +" \"default_tab_size\": 2,\n" " \"highlight_current_line\": true,\n" " \"show_line_numbers\": true\n" " },\n" diff --git a/src/source.cc b/src/source.cc index 1948282..06672c8 100644 --- a/src/source.cc +++ b/src/source.cc @@ -4,7 +4,6 @@ #include #include "logging.h" #include -#include #include "singletons.h" #include #include @@ -75,6 +74,29 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat property_show_line_numbers() = Singleton::Config::source()->show_line_numbers; if(Singleton::Config::source()->font.size()>0) override_font(Pango::FontDescription(Singleton::Config::source()->font)); + + tab_char=Singleton::Config::source()->default_tab_char; + tab_size=Singleton::Config::source()->default_tab_size; + if(Singleton::Config::source()->auto_tab_char_and_size) { + auto tab_char_and_size=find_tab_char_and_size(); + if(tab_char_and_size.first!=0) { + if(tab_char!=tab_char_and_size.first || tab_size!=tab_char_and_size.second) { + std::string tab_str; + if(tab_char_and_size.first==' ') + tab_str=""; + else + tab_str=""; + Singleton::terminal()->print("Tab char and size for file "+file_path.string()+" set to: "+tab_str+", "+boost::lexical_cast(tab_char_and_size.second)+".\n"); + } + + tab_char=tab_char_and_size.first; + tab_size=tab_char_and_size.second; + } + } + for(unsigned c=0;crequest_text([this](const Glib::ustring& text){ - const std::regex spaces_regex(std::string("^(")+Singleton::Config::source()->tab_char+"*)(.*)$"); auto line=get_line_before_insert(); std::smatch sm; std::string prefix_tabs; - if(!get_buffer()->get_has_selection() && std::regex_match(line, sm, spaces_regex) && sm[2].str().size()==0) { + if(!get_buffer()->get_has_selection() && std::regex_match(line, sm, tabs_regex) && sm[2].str().size()==0) { prefix_tabs=sm[1].str(); Glib::ustring::size_type start_line=0; @@ -177,7 +198,7 @@ void Source::View::paste() { std::string line=text.substr(start_line, end_line-start_line); size_t tabs=0; for(auto chr: line) { - if(chr==Singleton::Config::source()->tab_char) + if(chr==tab_char) tabs++; else break; @@ -260,21 +281,19 @@ string Source::View::get_line_before_insert() { //Basic indentation bool Source::View::on_key_press_event(GdkEventKey* key) { get_source_buffer()->begin_user_action(); - auto config=Singleton::Config::source(); - const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$"); //Indent as in next or previous line if(key->keyval==GDK_KEY_Return && key->state==0 && !get_buffer()->get_has_selection()) { auto insert_it=get_buffer()->get_insert()->get_iter(); int line_nr=insert_it.get_line(); auto line=get_line_before_insert(); std::smatch sm; - if(std::regex_match(line, sm, spaces_regex)) { + if(std::regex_match(line, sm, tabs_regex)) { if((line_nr+1)get_line_count()) { string next_line=get_line(line_nr+1); auto line_end_iter=get_buffer()->get_iter_at_line(line_nr+1); line_end_iter--; std::smatch sm2; - if(insert_it==line_end_iter && std::regex_match(next_line, sm2, spaces_regex)) { + if(insert_it==line_end_iter && std::regex_match(next_line, sm2, tabs_regex)) { if(sm2[1].str().size()>sm[1].str().size()) { get_source_buffer()->insert_at_cursor("\n"+sm2[1].str()); scroll_to(get_source_buffer()->get_insert()); @@ -297,7 +316,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { int line_end=selection_end.get_line(); for(int line=line_start;line<=line_end;line++) { Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line); - get_source_buffer()->insert(line_it, config->tab); + get_source_buffer()->insert(line_it, tab); } get_source_buffer()->end_user_action(); return true; @@ -309,11 +328,11 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { int line_start=selection_start.get_line(); int line_end=selection_end.get_line(); - unsigned indent_left_steps=config->tab_size; + unsigned indent_left_steps=tab_size; for(int line_nr=line_start;line_nr<=line_end;line_nr++) { string line=get_line(line_nr); std::smatch sm; - if(std::regex_match(line, sm, spaces_regex) && sm[1].str().size()>0) { + if(std::regex_match(line, sm, tabs_regex) && sm[1].str().size()>0) { indent_left_steps=std::min(indent_left_steps, (unsigned)sm[1].str().size()); } else { @@ -339,12 +358,12 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { int line_nr=insert_it.get_line(); auto line=get_line_before_insert(); std::smatch sm; - if(std::regex_match(line, sm, spaces_regex) && sm[1].str().size()==line.size()) { + if(std::regex_match(line, sm, tabs_regex) && sm[1].str().size()==line.size()) { if((line_nr-1)>=0) { string previous_line=get_line(line_nr-1); std::smatch sm2; - if(std::regex_match(previous_line, sm2, spaces_regex)) { - if(line.size()==sm2[1].str().size() || line.size()==sm2[1].str().size()+config->tab_size || line.size()==sm2[1].str().size()-config->tab_size) { + if(std::regex_match(previous_line, sm2, tabs_regex)) { + if(line.size()==sm2[1].str().size() || line.size()==sm2[1].str().size()+tab_size || line.size()==sm2[1].str().size()-tab_size) { auto previous_line_end_it=insert_it; for(unsigned c=0;c=config->tab_size) { + if(line.size()>=tab_size) { auto insert_minus_tab_it=insert_it; - for(unsigned c=0;ctab_size;c++) + for(unsigned c=0;cerase(insert_minus_tab_it, insert_it); get_source_buffer()->end_user_action(); @@ -371,6 +390,58 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { return stop; } +std::pair Source::View::find_tab_char_and_size() { + const std::regex indent_regex("^([ \t]+).*$"); + auto size=get_buffer()->get_line_count(); + std::unordered_map tab_chars; + std::unordered_map tab_sizes; + unsigned last_tab_size=0; + for(int c=0;c(str.size()-last_tab_size)); + if(tab_diff>0) { + unsigned tab_diff_unsigned=static_cast(tab_diff); + auto it_size=tab_sizes.find(tab_diff_unsigned); + if(it_size!=tab_sizes.end()) + it_size->second++; + else + tab_sizes[tab_diff_unsigned]=1; + } + + last_tab_size=str.size(); + + if(str.size()>0) { + auto it_char=tab_chars.find(str[0]); + if(it_char!=tab_chars.end()) + it_char->second++; + else + tab_chars[str[0]]=1; + } + } + } + char found_tab_char=0; + size_t occurences=0; + for(auto &tab_char: tab_chars) { + if(tab_char.second>occurences) { + found_tab_char=tab_char.first; + occurences=tab_char.second; + } + } + unsigned found_tab_size=0; + occurences=0; + for(auto &tab_size: tab_sizes) { + if(tab_size.second>occurences) { + found_tab_size=tab_size.first; + occurences=tab_size.second; + } + } + return {found_tab_char, found_tab_size}; +} + ///////////////////// //// GenericView //// ///////////////////// @@ -509,6 +580,10 @@ Source::View(file_path), project_path(project_path) { }); get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangViewParse::on_mark_set), false); + + bracket_regex=std::regex(std::string("^(")+tab_char+"*).*\\{ *$"); + no_bracket_statement_regex=std::regex(std::string("^(")+tab_char+"*)(if|for|else if|catch|while) *\\(.*[^;}] *$"); + no_bracket_no_para_statement_regex=std::regex(std::string("^(")+tab_char+"*)(else|try|do) *$"); } void Source::ClangViewParse::init_parse() { @@ -781,11 +856,6 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { return Source::View::on_key_press_event(key); } get_source_buffer()->begin_user_action(); - auto config=Singleton::Config::source(); - const std::regex bracket_regex(std::string("^(")+config->tab_char+"*).*\\{ *$"); - const std::regex no_bracket_statement_regex(std::string("^(")+config->tab_char+"*)(if|for|else if|catch|while) *\\(.*[^;}] *$"); - const std::regex no_bracket_no_para_statement_regex(std::string("^(")+config->tab_char+"*)(else|try|do) *$"); - const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$"); //Indent depending on if/else/etc and brackets if(key->keyval==GDK_KEY_Return && key->state==0) { @@ -796,18 +866,18 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { if((line_nr+1)get_line_count()) { string next_line=get_line(line_nr+1); std::smatch sm2; - if(std::regex_match(next_line, sm2, spaces_regex)) { - if(sm2[1].str()==sm[1].str()+config->tab) { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); + if(std::regex_match(next_line, sm2, tabs_regex)) { + if(sm2[1].str()==sm[1].str()+tab) { + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->end_user_action(); return true; } } if(next_line!=sm[1].str()+"}") { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab+"\n"+sm[1].str()+"}"); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab+"\n"+sm[1].str()+"}"); auto insert_it = get_source_buffer()->get_insert()->get_iter(); - for(size_t c=0;ctab_size+sm[1].str().size();c++) + for(size_t c=0;cget_insert()); get_source_buffer()->place_cursor(insert_it); @@ -815,7 +885,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { return true; } else { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->end_user_action(); return true; @@ -823,21 +893,21 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { } } else if(std::regex_match(line, sm, no_bracket_statement_regex)) { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->end_user_action(); return true; } else if(std::regex_match(line, sm, no_bracket_no_para_statement_regex)) { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->end_user_action(); return true; } - else if(std::regex_match(line, sm, spaces_regex)) { + else if(std::regex_match(line, sm, tabs_regex)) { std::smatch sm2; size_t line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); - if(line_nr>0 && sm[1].str().size()>=config->tab_size) { + if(line_nr>0 && sm[1].str().size()>=tab_size) { string previous_line=get_line(line_nr-1); if(!std::regex_match(previous_line, sm2, bracket_regex)) { if(std::regex_match(previous_line, sm2, no_bracket_statement_regex)) { @@ -859,9 +929,9 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { //Indent left when writing } on a new line else if(key->keyval==GDK_KEY_braceright) { string line=get_line_before_insert(); - if(line.size()>=config->tab_size) { + if(line.size()>=tab_size) { for(auto c: line) { - if(c!=config->tab_char) { + if(c!=tab_char) { get_source_buffer()->insert_at_cursor("}"); get_source_buffer()->end_user_action(); return true; @@ -870,7 +940,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { Gtk::TextIter insert_it = get_source_buffer()->get_insert()->get_iter(); Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(insert_it.get_line()); Gtk::TextIter line_plus_it=line_it; - for(unsigned c=0;ctab_size;c++) + for(unsigned c=0;cerase(line_it, line_plus_it); diff --git a/src/source.h b/src/source.h index e76fb1e..ee4a4ec 100644 --- a/src/source.h +++ b/src/source.h @@ -14,6 +14,7 @@ #include "tooltips.h" #include "selectiondialog.h" #include +#include namespace Source { Glib::RefPtr guess_language(const boost::filesystem::path &file_path); @@ -22,9 +23,9 @@ namespace Source { public: std::string style; std::string font; - unsigned tab_size; - char tab_char; - std::string tab; + bool auto_tab_char_and_size; + char default_tab_char; + unsigned default_tab_size; bool highlight_current_line; bool show_line_numbers; std::unordered_map clang_types; @@ -79,6 +80,12 @@ namespace Source { std::string get_line_before_insert(); bool on_key_press_event(GdkEventKey* key); + + std::pair find_tab_char_and_size(); + unsigned tab_size; + char tab_char; + std::string tab; + std::regex tabs_regex; private: GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; @@ -109,6 +116,10 @@ namespace Source { std::shared_ptr parsing_in_progress; std::thread parse_thread; std::atomic parse_thread_stop; + + std::regex bracket_regex; + std::regex no_bracket_statement_regex; + std::regex no_bracket_no_para_statement_regex; private: std::map get_buffer_map() const; // inits the syntax highligthing on file open From 6d83d4cce452bbf33f2413e62ff44b17ce7a0bac Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 20 Aug 2015 11:38:11 +0200 Subject: [PATCH 8/8] More OS X friendly font for OS X, Monospace for other OS'es. --- src/files.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/files.h b/src/files.h index 1370fa9..9112019 100644 --- a/src/files.h +++ b/src/files.h @@ -7,7 +7,12 @@ const std::string configjson = " },\n" " \"source\": {\n" " \"style\": \"juci-light\", //Use \"\" for default style, and for instance juci-dark together with dark gtk_theme variant. Styles from normal gtksourceview install: classic, cobalt, kate, oblivion, solarized-dark, solarized-light, tango\n" -" \"font\": \"Monospace\", //Use \"\" for default font, and for instance \"Monospace 12\" to also set size.\n" +#ifdef __APPLE__ +" \"font\": \"Menlo 11\", " +#else +" \"font\": \"Monospace\", " +#endif +"//Use \"\" for default font, and for instance \"Monospace 12\" to also set size.\n" " \"clang_types\": {\n" " \"8\": \"def:function\",\n" " \"21\": \"def:function\",\n"