From 2a6460eb814f02c9ecf4617dd226044d415e58bb Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 18 Aug 2015 15:47:53 +0200 Subject: [PATCH 01/60] 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 02/60] 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 03/60] 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 04/60] 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 05/60] 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 06/60] 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 07/60] 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 08/60] 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" From f7efa11cdddd32ff6525603b10cc5782b1a613c2 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Thu, 20 Aug 2015 15:09:31 +0200 Subject: [PATCH 09/60] terminal now works on Cygwin. --- src/terminal.cc | 50 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/terminal.cc b/src/terminal.cc index d47b9be..4df8e24 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -11,7 +11,7 @@ using namespace std; //TODO: remove //TODO: Windows... //A working implementation of popen3, with all pipes getting closed properly. //TODO: Eidheim is going to publish this one on his github, along with example uses -pid_t popen3(const char *command, int &stdin, int &stdout, int &stderr) { +pid_t popen3(const char *command, int &stdin_fd, int &stdout_fd, int &stderr_fd) { pid_t pid; int p_stdin[2], p_stdout[2], p_stderr[2]; @@ -56,9 +56,9 @@ pid_t popen3(const char *command, int &stdin, int &stdout, int &stderr) { close(p_stdout[1]); close(p_stderr[1]); - stdin = p_stdin[1]; - stdout = p_stdout[0]; - stderr = p_stderr[0]; + stdin_fd = p_stdin[1]; + stdout_fd = p_stdout[0]; + stderr_fd = p_stderr[0]; return pid; } @@ -145,18 +145,18 @@ int Terminal::execute(const std::string &command, const boost::filesystem::path else cd_path_and_command=command; - int stdin, stdout, stderr; - auto pid=popen3(cd_path_and_command.c_str(), stdin, stdout, stderr); + int stdin_fd, stdout_fd, stderr_fd; + auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); if (pid<=0) { async_print("Error: Failed to run command: " + command + "\n"); return -1; } else { - std::thread stderr_thread([this, stderr](){ + std::thread stderr_thread([this, stderr_fd](){ char buffer[1024]; ssize_t n; - while ((n=read(stderr, buffer, 1024)) > 0) { + while ((n=read(stderr_fd, buffer, 1024)) > 0) { std::string message; for(ssize_t c=0;c 0) { + while ((n=read(stdout_fd, buffer, 1024)) > 0) { std::string message; for(ssize_t c=0;c 0) { + while ((n=read(stderr_fd, buffer, 1024)) > 0) { std::string message; for(ssize_t c=0;c 0) { + while ((n=read(stdout_fd, buffer, 1024)) > 0) { std::string message; for(ssize_t c=0;c Date: Fri, 21 Aug 2015 12:44:24 +0200 Subject: [PATCH 10/60] Fixed a couple indenting issues around brackets. --- src/source.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index 06672c8..fb223b8 100644 --- a/src/source.cc +++ b/src/source.cc @@ -874,7 +874,9 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { return true; } } - if(next_line!=sm[1].str()+"}") { + 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()+"}"); auto insert_it = get_source_buffer()->get_insert()->get_iter(); for(size_t c=0;cend_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); + get_source_buffer()->end_user_action(); + return true; + } else { get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); scroll_to(get_source_buffer()->get_insert()); From d977cfa03260fbfd7169f82df663496cb3a77e38 Mon Sep 17 00:00:00 2001 From: "U-ole-PC\\ole" Date: Sat, 22 Aug 2015 12:03:42 +0200 Subject: [PATCH 11/60] Cygwin-support added, please note that I have not yet tested the changes on OS X and Debian. Doing it now. --- CMakeLists.txt | 6 +-- docs/install.md | 57 ++++++++++++++++++++------ src/CMakeLists.txt | 45 ++++++++++++-------- src/cmake/Modules/FindLibClangmm.cmake | 14 +++++-- src/window.cc | 4 +- 5 files changed, 87 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da710eb..efaa283 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,13 @@ cmake_minimum_required (VERSION 2.8.4) set(project_name juci) -set(module juci_to_python_api) +#set(module juci_to_python_api) #### TODO WINDOWS SUPPORT #### set(bin_install_path "/usr/local/bin") -set(lib_install_path "/usr/local/lib/python2.7/dist-packages/") +#set(lib_install_path "/usr/local/lib/python2.7/dist-packages/") ##### project (${project_name}) -add_subdirectory("src") \ No newline at end of file +add_subdirectory("src") diff --git a/docs/install.md b/docs/install.md index 345a815..042ab50 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,22 +1,55 @@ # juCi++ ## Installation guide ## -Before installation, please install libclangmm see [installation guide](http://github.com/cppit/libclangmm/blob/master/docs/install.md) for installation. +Before installation, please install libclangmm, see [installation guide](http://github.com/cppit/libclangmm/blob/master/docs/install.md). + ## Debian -First dependencies: ```sh -$ sudo apt-get install libboost-python-dev libboost-filesystem-dev libboost-log-dev libboost-test-dev -libboost-thread-dev libboost-system-dev libgtkmm-3.0-dev libgtksourceview2.0-dev libgtksourceviewmm-3.0-dev -libpython-dev libclang-dev make cmake gcc g++ +sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev ``` -Install the project: ```sh -$ git clone http://github.com/cppit/jucipp.git juci -$ cd juci -$ cmake . -$ make -$ sudo make install +git clone http://github.com/cppit/jucipp.git +cd jucipp +cmake . +make +sudo make install ``` + +## OS X with Homebrew (http://brew.sh/) +```sh +brew install pkg-config boost gtkmm3 gtksourceviewmm3 +``` + +```sh +git clone https://github.com/cppit/jucipp.git +cd jucipp +cmake . +make +make install +``` + +## Windows with Cygwin (https://www.cygwin.com/) +**Make sure the PATH environment variable does not include paths to non-Cygwin cmake, make and g++.** +Select and install the following packages from the Cygwin-installer: +``` +pkg-config libboost-devel libgtkmm3.0-devel libgtksourceviewmm3.0-devel xinit +``` +Then run the following in the Cygwin Terminal: +```sh +git clone https://github.com/cppit/jucipp.git +cd jucipp +cmake . +make +make install +``` + +Note that we are currently working on a Windows-version without the need of an X-server. + ## Run ```sh -$ juci +juci +``` + +#Windows +```sh +startxwin /usr/local/bin/juci ``` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f892eb..c2bda6f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,11 @@ if(APPLE) set(CMAKE_MACOSX_RPATH 1) set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig") endif() + +if(CYGWIN) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") #TODO: make juci work with -mwin32 to run without X-server +endif() + INCLUDE(FindPkgConfig) set(validation true) @@ -21,7 +26,7 @@ function(install_help APPLE UNIX WINDOWS) endif(APPLE) endif(UNIX) if(WINDOWS) - message("choco install ${WINDOWS}") + #message("choco install ${WINDOWS}") #Removed this for the time being endif(WINDOWS) endfunction(install_help) @@ -38,10 +43,11 @@ validate(${LCL_FOUND} "clangmm" "clangmm" "clangmm") find_package(LibClang) validate(${LIBCLANG_FOUND} "clang" "libclang-dev" "llvm") -find_package(PythonLibs 2.7) -validate(${PYTHONLIBS_FOUND} "python" "libpython-dev" "python") +#find_package(PythonLibs 2.7) +#validate(${PYTHONLIBS_FOUND} "python" "libpython-dev" "python") -find_package(Boost 1.55 COMPONENTS python thread log system filesystem REQUIRED) +#find_package(Boost 1.55 COMPONENTS python thread log system filesystem REQUIRED) +find_package(Boost 1.55 COMPONENTS thread log system filesystem REQUIRED) validate(${Boost_FOUND} "boost" "libboost-all-dev" "boost") pkg_check_modules(GTKMM gtkmm-3.0) # The name GTKMM is set here for the variables abouve @@ -66,8 +72,8 @@ if(${validation}) sourcefile.cc window.cc window.h - api.h - api.cc +# api.h +# api.cc notebook.cc notebook.h entrybox.h @@ -83,13 +89,13 @@ if(${validation}) cmake.h cmake.cc) - add_library(${module} SHARED - api - api_ext) +# add_library(${module} SHARED +# api +# api_ext) include_directories( ${Boost_INCLUDE_DIRS} - ${PYTHON_INCLUDE_DIRS} +# ${PYTHON_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} ${GTKSVMM_INCLUDE_DIRS} ${LCL_INCLUDE_DIRS} @@ -99,15 +105,16 @@ if(${validation}) ${GTKMM_LIBRARY_DIRS} ${GTKSVMM_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} - ${PYTHON_INCLUDE_DIRS} +# ${PYTHON_INCLUDE_DIRS} ${LCL_LIBRARY_DIRS} ${LIBCLANG_LIBRARY_DIRS}) - set_target_properties(${module} - PROPERTIES PREFIX "" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/") +# set_target_properties(${module} +# PROPERTIES PREFIX "" +# LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/") - target_link_libraries(${module} ${PYTHON_LIBRARIES} ${Boost_LIBRARIES}) +# target_link_libraries(${module} ${PYTHON_LIBRARIES} ${Boost_LIBRARIES}) +# target_link_libraries(${module} ${Boost_LIBRARIES}) target_link_libraries(${project_name} ${LIBCLANG_LIBRARIES} @@ -115,11 +122,13 @@ if(${validation}) ${GTKMM_LIBRARIES} ${GTKSVMM_LIBRARIES} ${Boost_LIBRARIES} - ${PYTHON_LIBRARIES}) +# ${PYTHON_LIBRARIES} + ) - install(TARGETS ${project_name} ${module} +# install(TARGETS ${project_name} ${module} + install(TARGETS ${project_name} RUNTIME DESTINATION ${bin_install_path} - LIBRARY DESTINATION ${lib_install_path} +# LIBRARY DESTINATION ${lib_install_path} ) endif(${validation}) diff --git a/src/cmake/Modules/FindLibClangmm.cmake b/src/cmake/Modules/FindLibClangmm.cmake index 49f950b..c8e7f65 100644 --- a/src/cmake/Modules/FindLibClangmm.cmake +++ b/src/cmake/Modules/FindLibClangmm.cmake @@ -5,12 +5,18 @@ find_package(PkgConfig) find_path(LCL_INCLUDE_DIR clangmm.h - HINTS "/usr/local/include/libclangmm/" - ) + HINTS /usr/local/include/libclangmm +) + + +if(CYGWIN) + set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} "cyg") + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} ".dll") +endif() find_library(LCL_LIBRARY NAMES clangmm - HINTS "/usr/local/lib/" - ) + PATHS /usr/local/lib /usr/local/bin +) set(LCL_LIBRARIES ${LCL_LIBRARY} ) set(LCL_INCLUDE_DIRS ${LCL_INCLUDE_DIR} ) diff --git a/src/window.cc b/src/window.cc index 2aa0100..ebd1cff 100644 --- a/src/window.cc +++ b/src/window.cc @@ -3,7 +3,7 @@ #include "singletons.h" #include "sourcefile.h" #include "config.h" -#include "api.h" +//#include "api.h" #include #include //TODO: remove @@ -30,7 +30,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil add(box); generate_keybindings(); - PluginApi(&this->notebook, &this->menu); + //PluginApi(&this->notebook, &this->menu); create_menu(); box.pack_start(menu.get_widget(), Gtk::PACK_SHRINK); From 4afeb5339c87e70afaa58655766d31c0257a7a5c Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 22 Aug 2015 12:12:07 +0200 Subject: [PATCH 12/60] Tested and works with debian and OS X. --- docs/install.md | 2 +- src/cmake/Modules/FindLibClang.cmake | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/install.md b/docs/install.md index 042ab50..f7f4f99 100644 --- a/docs/install.md +++ b/docs/install.md @@ -49,7 +49,7 @@ Note that we are currently working on a Windows-version without the need of an X juci ``` -#Windows +###Windows ```sh startxwin /usr/local/bin/juci ``` diff --git a/src/cmake/Modules/FindLibClang.cmake b/src/cmake/Modules/FindLibClang.cmake index 3d15636..f294979 100644 --- a/src/cmake/Modules/FindLibClang.cmake +++ b/src/cmake/Modules/FindLibClang.cmake @@ -14,7 +14,8 @@ # Known LLVM release numbers. # most recent versions come first -set(LIBCLANG_KNOWN_LLVM_VERSIONS 3.6.1 +set(LIBCLANG_KNOWN_LLVM_VERSIONS 3.6.2 + 3.6.1 3.6 3.5.1 3.5.0 #Arch Linux From c10077b02a5e8299c53ffdc735743beb24c79086 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sat, 22 Aug 2015 12:13:37 +0200 Subject: [PATCH 13/60] Update install.md --- docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index f7f4f99..933673a 100644 --- a/docs/install.md +++ b/docs/install.md @@ -49,7 +49,7 @@ Note that we are currently working on a Windows-version without the need of an X juci ``` -###Windows +## Windows ```sh startxwin /usr/local/bin/juci ``` From 0f0c943efb83a5e65515676d0e96054617f75356 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sat, 22 Aug 2015 12:14:27 +0200 Subject: [PATCH 14/60] Update install.md --- docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index 933673a..3aed74e 100644 --- a/docs/install.md +++ b/docs/install.md @@ -49,7 +49,7 @@ Note that we are currently working on a Windows-version without the need of an X juci ``` -## Windows +#### Windows ```sh startxwin /usr/local/bin/juci ``` From d45a80a0694aa0a3f9642933e992407d863404ca Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sat, 22 Aug 2015 12:15:03 +0200 Subject: [PATCH 15/60] Update install.md --- docs/install.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/install.md b/docs/install.md index 3aed74e..d24fd88 100644 --- a/docs/install.md +++ b/docs/install.md @@ -45,6 +45,7 @@ make install Note that we are currently working on a Windows-version without the need of an X-server. ## Run +#### Linux/OS X ```sh juci ``` From 6bccc417fbbf52a86b5abeba27b136c79ed5b20f Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sat, 22 Aug 2015 12:32:48 +0200 Subject: [PATCH 16/60] Update install.md --- docs/install.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index d24fd88..eb9a248 100644 --- a/docs/install.md +++ b/docs/install.md @@ -2,7 +2,7 @@ ## Installation guide ## Before installation, please install libclangmm, see [installation guide](http://github.com/cppit/libclangmm/blob/master/docs/install.md). -## Debian +## Debian/Ubuntu ```sh sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev ``` @@ -29,6 +29,7 @@ make install ## Windows with Cygwin (https://www.cygwin.com/) **Make sure the PATH environment variable does not include paths to non-Cygwin cmake, make and g++.** + Select and install the following packages from the Cygwin-installer: ``` pkg-config libboost-devel libgtkmm3.0-devel libgtksourceviewmm3.0-devel xinit From aa50a94a006115df4620868449cd9197edb869f7 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 22 Aug 2015 13:45:12 +0200 Subject: [PATCH 17/60] Added cmake_command to config.json so that one can use the MinGW toolchain in Windows if that is wanted. Also now shows all files in directory (some files like cmake.cc got hidden before). --- src/CMakeLists.txt | 2 +- src/cmake.cc | 2 +- src/config.cc | 3 ++- src/files.h | 7 +------ src/terminal.h | 1 + 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c2bda6f..3118301 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,7 +9,7 @@ if(APPLE) endif() if(CYGWIN) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") #TODO: make juci work with -mwin32 to run without X-server + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") endif() INCLUDE(FindPkgConfig) diff --git a/src/cmake.cc b/src/cmake.cc index d2ecfe6..aab2338 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -47,7 +47,7 @@ CMake::CMake(const boost::filesystem::path &path) { bool CMake::create_compile_commands(const boost::filesystem::path &path) { Singleton::terminal()->print("Creating "+path.string()+"/compile_commands.json\n"); //TODO: Windows... - if(Singleton::terminal()->execute("cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==EXIT_SUCCESS) + if(Singleton::terminal()->execute(Singleton::Config::terminal()->cmake_command+" . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==EXIT_SUCCESS) return true; return false; } diff --git a/src/config.cc b/src/config.cc index f41feb4..0de059c 100644 --- a/src/config.cc +++ b/src/config.cc @@ -14,8 +14,9 @@ MainConfig::MainConfig() { Singleton::Config::window()->theme_name=cfg.get("gtk_theme.name"); Singleton::Config::window()->theme_variant=cfg.get("gtk_theme.variant"); - + Singleton::Config::terminal()->make_command=cfg.get("project.make_command"); + Singleton::Config::terminal()->cmake_command=cfg.get("project.cmake_command"); } void MainConfig::find_or_create_config_files() { diff --git a/src/files.h b/src/files.h index 9112019..a706c2f 100644 --- a/src/files.h +++ b/src/files.h @@ -62,18 +62,13 @@ const std::string configjson = " \"force_kill_last_running\": \"Escape\"\n" " },\n" " \"project\": {\n" +" \"cmake_command\": \"cmake\",\n" " \"make_command\": \"make\"\n" " },\n" " \"directoryfilter\": {\n" " \"ignore\": [\n" -" \"cmake\",\n" -" \"#\",\n" -" \"~\",\n" -" \".idea\",\n" -" \".so\"\n" " ],\n" " \"exceptions\": [\n" -" \"cmakelists.txt\"\n" " ]\n" " }\n" "}\n"; diff --git a/src/terminal.h b/src/terminal.h index 5bdbe1a..dfd1f50 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -13,6 +13,7 @@ class Terminal : public Gtk::TextView { public: class Config { public: + std::string cmake_command; std::string make_command; }; From eedb344d7ea3408fa1bd73e1a2ad3594a8e33cc4 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Sat, 22 Aug 2015 14:31:11 +0200 Subject: [PATCH 18/60] Fixed tooltip issue on Windows. --- src/source.cc | 25 ++++++++++++++----------- src/source.h | 2 ++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/source.cc b/src/source.cc index fb223b8..24c3d1a 100644 --- a/src/source.cc +++ b/src/source.cc @@ -794,18 +794,21 @@ void Source::ClangViewParse::update_types() { } bool Source::ClangViewParse::on_motion_notify_event(GdkEventMotion* event) { - delayed_tooltips_connection.disconnect(); - if(clang_readable && event->state==0) { - Gdk::Rectangle rectangle(event->x, event->y, 1, 1); - Tooltips::init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); - } - else { - type_tooltips.hide(); - diagnostic_tooltips.hide(); + if(on_motion_last_x!=event->x || on_motion_last_y!=event->y) { + delayed_tooltips_connection.disconnect(); + if(clang_readable && event->state==0) { + Gdk::Rectangle rectangle(event->x, event->y, 1, 1); + Tooltips::init(); + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + else { + type_tooltips.hide(); + diagnostic_tooltips.hide(); + } } - + on_motion_last_x=event->x; + on_motion_last_y=event->y; return Source::View::on_motion_notify_event(event); } diff --git a/src/source.h b/src/source.h index ee4a4ec..c374dfc 100644 --- a/src/source.h +++ b/src/source.h @@ -132,6 +132,8 @@ namespace Source { Tooltips diagnostic_tooltips; Tooltips type_tooltips; bool on_motion_notify_event(GdkEventMotion* event); + gdouble on_motion_last_x; + gdouble on_motion_last_y; void on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); bool on_scroll_event(GdkEventScroll* event); From d892f7386f50843b2430f60e55ed6058ab5a353b Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 23 Aug 2015 08:53:24 +0200 Subject: [PATCH 19/60] Improved README.md. --- README.md | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 3823f43..40ec707 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,22 @@ # juCi++ ###### a lightweight C++-IDE with support for C++11 and C++14. ## About -A lot of IDEs struggle with good C++11/14 support. Therefore we -created juCi++. juCi++ is based of the compiler and will *always* -support new versions of C++. +Current IDEs struggle with C++ support due to the complexity of +the programming language. juCI++, however, is designed especially +towards libclang with speed in mind. ## Features -* Syntax highlighing (even C++11/14) -* Superfast autocomletion (even external libraries) +* Fast and responsive +* Syntax highlighing (even C++11/14, and 118 other file types) +* C++ warnings and errors on the fly +* Fast C++ autocomletion (even external libraries) +* Tooltips showing type information and doxygen documentation * Accurate refactoring across files * Basic editor functionallity * Highlighting of similar types -* write your own plugins in python (limited atm) +* Write your own plugins in python (disabled at the moment) ## Dependencies ## -Please install these dependencies on your system. -* libboost-python-dev * libboost-filesystem-dev * libboost-log-dev * libboost-test-dev @@ -24,19 +25,8 @@ Please install these dependencies on your system. * libgtkmm-3.0-dev * libgtksourceview2.0-dev * libgtksourceviewmm-3.0-dev -* libpython-dev * libclang-dev * [libclangmm](http://github.com/cppit/libclangmm/) -* cmake -* make -* clang or gcc (compiler) ## Installation ## -Quickstart: -```sh -$ cmake . -$ make -$ sudo make install -``` -See [installation guide](http://github.com/cppit/jucipp/blob/master/docs/install.md) for more details. - +See [installation guide](http://github.com/cppit/jucipp/blob/master/docs/install.md). From d9a1f7805ba94924a484b16c25a80262aa3c825b Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 23 Aug 2015 10:52:34 +0200 Subject: [PATCH 20/60] Fixed double click to select whole variable in Linux. --- src/source.cc | 22 ++++++++++++++++++++++ src/source.h | 1 + 2 files changed, 23 insertions(+) diff --git a/src/source.cc b/src/source.cc index 24c3d1a..eb2b65e 100644 --- a/src/source.cc +++ b/src/source.cc @@ -390,6 +390,28 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { return stop; } +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; + } + } + + return Gsv::View::on_button_press_event(event); +} + std::pair Source::View::find_tab_char_and_size() { const std::regex indent_regex("^([ \t]+).*$"); auto size=get_buffer()->get_line_count(); diff --git a/src/source.h b/src/source.h index c374dfc..e51ff3d 100644 --- a/src/source.h +++ b/src/source.h @@ -80,6 +80,7 @@ namespace Source { std::string get_line_before_insert(); bool on_key_press_event(GdkEventKey* key); + bool on_button_press_event(GdkEventButton *event); std::pair find_tab_char_and_size(); unsigned tab_size; From 8175836db1ba1bab8319a756854bcd6cce62c580 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 23 Aug 2015 11:05:36 +0200 Subject: [PATCH 21/60] Added slight delay on mouse-pointer tooltips. --- src/source.cc | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/source.cc b/src/source.cc index eb2b65e..f02d005 100644 --- a/src/source.cc +++ b/src/source.cc @@ -818,16 +818,21 @@ void Source::ClangViewParse::update_types() { bool Source::ClangViewParse::on_motion_notify_event(GdkEventMotion* event) { if(on_motion_last_x!=event->x || on_motion_last_y!=event->y) { delayed_tooltips_connection.disconnect(); - if(clang_readable && event->state==0) { - Gdk::Rectangle rectangle(event->x, event->y, 1, 1); - Tooltips::init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); - } - else { - type_tooltips.hide(); - diagnostic_tooltips.hide(); + if(event->state==0) { + gdouble x=event->x; + gdouble y=event->y; + delayed_tooltips_connection=Glib::signal_timeout().connect([this, x, y]() { + if(clang_readable) { + Gdk::Rectangle rectangle(x, y, 1, 1); + Tooltips::init(); + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + return false; + }, 100); } + type_tooltips.hide(); + diagnostic_tooltips.hide(); } on_motion_last_x=event->x; on_motion_last_y=event->y; From fce4b93961ab0372bf4a0fbdc58c8f6438597275 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 14:33:41 +0200 Subject: [PATCH 22/60] Added MINGW-packages for gtksourceview3 and gtksourceviewmm3 (3.12.0). --- .../0006-hack-convert-path-back-to-unix.patch | 15 +++++ .../mingw-w64-gtksourceview3/PKGBUILD | 64 +++++++++++++++++++ .../mingw-w64-gtksourceviewmm3/PKGBUILD | 33 ++++++++++ 3 files changed, 112 insertions(+) create mode 100644 MINGW-packages/mingw-w64-gtksourceview3/0006-hack-convert-path-back-to-unix.patch create mode 100644 MINGW-packages/mingw-w64-gtksourceview3/PKGBUILD create mode 100644 MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD diff --git a/MINGW-packages/mingw-w64-gtksourceview3/0006-hack-convert-path-back-to-unix.patch b/MINGW-packages/mingw-w64-gtksourceview3/0006-hack-convert-path-back-to-unix.patch new file mode 100644 index 0000000..68f217f --- /dev/null +++ b/MINGW-packages/mingw-w64-gtksourceview3/0006-hack-convert-path-back-to-unix.patch @@ -0,0 +1,15 @@ +--- gtksourceview-3.13.90/configure.ac.orig 2014-08-22 00:42:28.532000000 +0400 ++++ gtksourceview-3.13.90/configure.ac 2014-08-22 00:43:00.621200000 +0400 +@@ -133,6 +133,12 @@ + AC_MSG_RESULT([$GLADE_CATALOG_DIR]) + AC_SUBST(GLADE_CATALOG_DIR)]) + ++case "$host" in ++ *-*-mingw*) ++ GLADE_CATALOG_DIR=`cygpath -u $GLADE_CATALOG_DIR` ++ ;; ++esac ++ + # i18N stuff + IT_PROG_INTLTOOL([0.40]) + AS_IF([test "$USE_NLS" = "yes"], diff --git a/MINGW-packages/mingw-w64-gtksourceview3/PKGBUILD b/MINGW-packages/mingw-w64-gtksourceview3/PKGBUILD new file mode 100644 index 0000000..038333a --- /dev/null +++ b/MINGW-packages/mingw-w64-gtksourceview3/PKGBUILD @@ -0,0 +1,64 @@ +# Maintainer: Alexey Pavlov + +_realname=gtksourceview +pkgname="${MINGW_PACKAGE_PREFIX}-${_realname}3" +pkgver=3.12.0 +pkgrel=2 +pkgdesc="A text widget adding syntax highlighting and more to GNOME (mingw-w64)" +arch=('any') +url="http://www.gnome.org" +license=("LGPL") +makedepends=("${MINGW_PACKAGE_PREFIX}-gcc" + "${MINGW_PACKAGE_PREFIX}-pkg-config" + "${MINGW_PACKAGE_PREFIX}-gobject-introspection" + "${MINGW_PACKAGE_PREFIX}-glade" + "${MINGW_PACKAGE_PREFIX}-vala" + "intltool" + "gtk-doc") +depends=("${MINGW_PACKAGE_PREFIX}-gtk3" + "${MINGW_PACKAGE_PREFIX}-libxml2") +options=(!libtool strip staticlibs) +source=("http://ftp.gnome.org/pub/gnome/sources/gtksourceview/${pkgver%.*}/gtksourceview-${pkgver}.tar.xz" + 0006-hack-convert-path-back-to-unix.patch) +md5sums=('8850fc0aee4893668ede37a30ef05e85' + '324c9e3bb2e4fa2a4977653ce6ed6ef9') + +prepare() { + cd ${_realname}-${pkgver} + patch -p1 -i ${srcdir}/0006-hack-convert-path-back-to-unix.patch + + autoreconf -fi +} + +build() { + mkdir -p "${srcdir}/build-${MINGW_CHOST}" + cd "${srcdir}/build-${MINGW_CHOST}" + + mkdir -p docs/reference/html + cp -rf ../${_realname}-${pkgver}/docs/reference/html/* docs/reference/html + + DATADIRNAME=share \ + ../${_realname}-${pkgver}/configure \ + --prefix=${MINGW_PREFIX} \ + --build=${MINGW_CHOST} \ + --host=${MINGW_CHOST} \ + --enable-shared \ + --disable-static \ + --enable-glade-catalog + + LC_ALL=C make +} + +package() { + cd "${srcdir}/build-${MINGW_CHOST}" + make -j1 DESTDIR="${pkgdir}" install + + for ff in ${pkgdir}/${MINGW_PREFIX}/bin/libgtksourceview*.dll; do + local _reallib=$(basename $ff) + _reallib=${_reallib%.dll} + _reallib=${_reallib#lib} + sed -e "s|library=\"gtksourceview-3.0\"|library=\"${_reallib}\"|g" -i ${pkgdir}/${MINGW_PREFIX}/share/glade/catalogs/gtksourceview.xml + done + + install -Dm644 "${srcdir}/${_realname}-${pkgver}/COPYING" "${pkgdir}${MINGW_PREFIX}/share/licenses/${_realname}/COPYING" +} diff --git a/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD b/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD new file mode 100644 index 0000000..e76c572 --- /dev/null +++ b/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD @@ -0,0 +1,33 @@ +_realname=gtksourceviewmm3 +pkgname="${MINGW_PACKAGE_PREFIX}-${_realname}" +pkgver=3.12.0 +pkgrel=1 +pkgdesc="C++ bindings for gtksourceview3 (mingw-w64)" +arch=('any') +url="https://developer.gnome.org/gtksourceviewmm/" +license=("LGPL") +makedepends=("patch" "${MINGW_PACKAGE_PREFIX}-gcc" "${MINGW_PACKAGE_PREFIX}-pkg-config") +depends=("${MINGW_PACKAGE_PREFIX}-gtksourceview3=3.12.0") +options=('staticlibs' 'strip') +source=("https://download.gnome.org/sources/gtksourceviewmm/${pkgver%.*}/gtksourceviewmm-${pkgver}.tar.xz") +sha256sums=("73939031bcc60e6ad31a315ec84b132deba15e5732de16e75fe424a619267ace") + +build() { + mkdir -p "${srcdir}/build-${MINGW_CHOST}" + cd "${srcdir}/build-${MINGW_CHOST}" + ../gtksourceviewmm-${pkgver}/configure \ + CXXFLAGS=-std=c++11 \ + --prefix=${MINGW_PREFIX} \ + --build=${MINGW_CHOST} \ + --host=${MINGW_CHOST} \ + --enable-shared \ + --enable-static \ + --disable-documentation + make +} + +package() { + cd "${srcdir}/build-${MINGW_CHOST}" + make DESTDIR="${pkgdir}" install + find "${pkgdir}${MINGW_PREFIX}" -name '*.def' -o -name '*.exp' | xargs -rtl1 rm +} \ No newline at end of file From ddc0fddc97f6e8208693a5fb173f4ea3d9502927 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 14:36:59 +0200 Subject: [PATCH 23/60] Minor change to dependency check. --- MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD b/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD index e76c572..0d842a8 100644 --- a/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD +++ b/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD @@ -7,7 +7,7 @@ arch=('any') url="https://developer.gnome.org/gtksourceviewmm/" license=("LGPL") makedepends=("patch" "${MINGW_PACKAGE_PREFIX}-gcc" "${MINGW_PACKAGE_PREFIX}-pkg-config") -depends=("${MINGW_PACKAGE_PREFIX}-gtksourceview3=3.12.0") +depends=("${MINGW_PACKAGE_PREFIX}-gtksourceview3=${pkgver}") options=('staticlibs' 'strip') source=("https://download.gnome.org/sources/gtksourceviewmm/${pkgver%.*}/gtksourceviewmm-${pkgver}.tar.xz") sha256sums=("73939031bcc60e6ad31a315ec84b132deba15e5732de16e75fe424a619267ace") From ae09be013673ededdd658263e85ecf128ae39707 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 14:41:52 +0200 Subject: [PATCH 24/60] Added license file. --- MINGW-packages/LICENSE | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 MINGW-packages/LICENSE diff --git a/MINGW-packages/LICENSE b/MINGW-packages/LICENSE new file mode 100644 index 0000000..e0f07ba --- /dev/null +++ b/MINGW-packages/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013, Алексей +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 8991a4725b83fddfd3c353f70ad5c5301b52d7da Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 14:45:54 +0200 Subject: [PATCH 25/60] gtk_file_chooser_set_filename now works on Windows. --- src/window.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.cc b/src/window.cc index ebd1cff..bba2e52 100644 --- a/src/window.cc +++ b/src/window.cc @@ -493,7 +493,7 @@ void Window::save_file_dialog() { 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.c_str()); + 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); dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("Save", Gtk::RESPONSE_OK); From 7d06001e690f0fb549a72eecccd82f69931af590 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 15:43:34 +0200 Subject: [PATCH 26/60] Removed Cygwin, added MSYS2 with TODOs. --- docs/install.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/install.md b/docs/install.md index eb9a248..7c2c456 100644 --- a/docs/install.md +++ b/docs/install.md @@ -27,6 +27,13 @@ make make install ``` +##Windows with MSYS2 (https://msys2.github.io/) +Will be available when the following TODOs are resolved: +* Newlines are saved properly +* Windows implementation of fork/pipe/read/write +* libclang(mm) finds header-files + + ## Run #### Linux/OS X @@ -51,7 +59,9 @@ Note that we are currently working on a Windows-version without the need of an X juci ``` + \ No newline at end of file From dd14202ad89db49196dfa0d650e81a97601a33f3 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 16:00:56 +0200 Subject: [PATCH 27/60] CMakeFiles are now working in Windows. --- CMakeLists.txt | 10 +++++++--- src/CMakeLists.txt | 8 ++++---- src/cmake/Modules/FindLibClangmm.cmake | 18 ++++++++++-------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index efaa283..045f920 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,10 +3,14 @@ cmake_minimum_required (VERSION 2.8.4) set(project_name juci) #set(module juci_to_python_api) -#### TODO WINDOWS SUPPORT #### -set(bin_install_path "/usr/local/bin") +if(MSYS) + string(TOLOWER "/$ENV{MSYSTEM}" MSYS_PATH) + set(bin_install_path "${MSYS_PATH}/bin") +else() + set(bin_install_path "/usr/local/bin") +endif() + #set(lib_install_path "/usr/local/lib/python2.7/dist-packages/") -##### project (${project_name}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3118301..5a53998 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,10 +8,6 @@ if(APPLE) set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig") endif() -if(CYGWIN) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") -endif() - INCLUDE(FindPkgConfig) set(validation true) @@ -43,6 +39,10 @@ validate(${LCL_FOUND} "clangmm" "clangmm" "clangmm") find_package(LibClang) validate(${LIBCLANG_FOUND} "clang" "libclang-dev" "llvm") +if(MSYS) + set(LIBCLANG_LIBRARIES "${MSYS_PATH}/bin/clang.dll") +endif() + #find_package(PythonLibs 2.7) #validate(${PYTHONLIBS_FOUND} "python" "libpython-dev" "python") diff --git a/src/cmake/Modules/FindLibClangmm.cmake b/src/cmake/Modules/FindLibClangmm.cmake index c8e7f65..9ba851d 100644 --- a/src/cmake/Modules/FindLibClangmm.cmake +++ b/src/cmake/Modules/FindLibClangmm.cmake @@ -4,20 +4,22 @@ find_package(PkgConfig) +if(MSYS) + string(TOLOWER "/$ENV{MSYSTEM}" MSYS_PATH) + set(MSYS_INCLUDE_PATH "${MSYS_PATH}/include/libclangmm") + set(MSYS_BIN_PATH "${MSYS_PATH}/bin") +endif() + find_path(LCL_INCLUDE_DIR clangmm.h - HINTS /usr/local/include/libclangmm + PATHS /usr/local/include/libclangmm ${MSYS_INCLUDE_PATH} ) - -if(CYGWIN) - set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} "cyg") - set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} ".dll") -endif() - find_library(LCL_LIBRARY NAMES clangmm - PATHS /usr/local/lib /usr/local/bin + PATHS /usr/local/lib ${MSYS_BIN_PATH} ) +message("${LCL_INCLUDE_DIR}") + set(LCL_LIBRARIES ${LCL_LIBRARY} ) set(LCL_INCLUDE_DIRS ${LCL_INCLUDE_DIR} ) From 08d1bc7de80b5e674a03d3b0dd8d3bb407932a2c Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 16:02:07 +0200 Subject: [PATCH 28/60] Removed debug message. --- src/cmake/Modules/FindLibClangmm.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cmake/Modules/FindLibClangmm.cmake b/src/cmake/Modules/FindLibClangmm.cmake index 9ba851d..ff7c8cb 100644 --- a/src/cmake/Modules/FindLibClangmm.cmake +++ b/src/cmake/Modules/FindLibClangmm.cmake @@ -18,8 +18,6 @@ find_library(LCL_LIBRARY NAMES clangmm PATHS /usr/local/lib ${MSYS_BIN_PATH} ) -message("${LCL_INCLUDE_DIR}") - set(LCL_LIBRARIES ${LCL_LIBRARY} ) set(LCL_INCLUDE_DIRS ${LCL_INCLUDE_DIR} ) From 62830656202af71f409e85fc7d395b773c0483e8 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 24 Aug 2015 20:28:04 +0200 Subject: [PATCH 29/60] Added terminal_win.cc for Windows. --- src/CMakeLists.txt | 14 +- src/terminal_win.cc | 311 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 321 insertions(+), 4 deletions(-) create mode 100644 src/terminal_win.cc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5a53998..d15e8e1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,9 +56,7 @@ validate(${GTKMM_FOUND} "gtkmm" "libgtkmm-dev" "gtkmm") pkg_check_modules(GTKSVMM gtksourceviewmm-3.0) validate(${GTKSVMM_FOUND} "gtksvmm" "libgtksvmm-dev" "gtkmmsv") -if(${validation}) - add_executable(${project_name} - juci.h +set(source_files juci.h juci.cc menu.h menu.cc @@ -81,7 +79,6 @@ if(${validation}) directories.h directories.cc terminal.h - terminal.cc tooltips.h tooltips.cc singletons.h @@ -89,6 +86,15 @@ if(${validation}) cmake.h cmake.cc) +if(MSYS) + list(APPEND source_files terminal_win.cc) +else() + list(APPEND source_files terminal.cc) +endif() + +if(${validation}) + add_executable(${project_name} ${source_files}) + # add_library(${module} SHARED # api # api_ext) diff --git a/src/terminal_win.cc b/src/terminal_win.cc new file mode 100644 index 0000000..b6a7fdb --- /dev/null +++ b/src/terminal_win.cc @@ -0,0 +1,311 @@ +#include "terminal.h" +#include +#include "logging.h" +#include "singletons.h" +#include + +#include //TODO: remove +using namespace std; //TODO: remove + +Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) { + waiting_print.connect([this](){ + Singleton::terminal()->async_print(line_nr-1, "."); + }); + start(start_msg); +} + +Terminal::InProgress::~InProgress() { + stop=true; + if(wait_thread.joinable()) + wait_thread.join(); +} + +void Terminal::InProgress::start(const std::string& msg) { + line_nr=Singleton::terminal()->print(msg+"...\n"); + wait_thread=std::thread([this](){ + size_t c=0; + while(!stop) { + if(c%100==0) + waiting_print(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + c++; + } + }); +} + +void Terminal::InProgress::done(const std::string& msg) { + if(!stop) { + stop=true; + Singleton::terminal()->async_print(line_nr-1, msg); + } +} + +void Terminal::InProgress::cancel(const std::string& msg) { + if(!stop) { + stop=true; + Singleton::terminal()->async_print(line_nr-1, msg); + } +} + +Terminal::Terminal() { + bold_tag=get_buffer()->create_tag(); + bold_tag->property_weight()=PANGO_WEIGHT_BOLD; + + signal_size_allocate().connect([this](Gtk::Allocation& allocation){ + auto iter=get_buffer()->end(); + if(iter.backward_char()) { + auto mark=get_buffer()->create_mark(iter); + scroll_to(mark, 0.0, 1.0, 1.0); + get_buffer()->delete_mark(mark); + } + }); + + async_print_dispatcher.connect([this](){ + async_print_strings_mutex.lock(); + if(async_print_strings.size()>0) { + for(auto &string_bold: async_print_strings) + print(string_bold.first, string_bold.second); + async_print_strings.clear(); + } + async_print_strings_mutex.unlock(); + }); + async_print_on_line_dispatcher.connect([this](){ + async_print_on_line_strings_mutex.lock(); + if(async_print_on_line_strings.size()>0) { + for(auto &line_string: async_print_on_line_strings) + print(line_string.first, line_string.second); + async_print_on_line_strings.clear(); + } + async_print_on_line_strings_mutex.unlock(); + }); +} + +int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { + /*std::string cd_path_and_command; + if(path!="") { + //TODO: Windows... + cd_path_and_command="cd \""+path.string()+"\" && "+command; + } + else + cd_path_and_command=command; + + int stdin_fd, stdout_fd, stderr_fd; + auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); + + if (pid<=0) { + async_print("Error: Failed to run command: " + command + "\n"); + return -1; + } + else { + std::thread stderr_thread([this, stderr_fd](){ + char buffer[1024]; + ssize_t n; + while ((n=read(stderr_fd, buffer, 1024)) > 0) { + std::string message; + for(ssize_t c=0;c 0) { + std::string message; + for(ssize_t c=0;c callback) { + /*std::thread async_execute_thread([this, command, path, callback](){ + std::string cd_path_and_command; + if(path!="") { + + //TODO: Windows... + cd_path_and_command="cd \""+path.string()+"\" && "+command; + } + else + cd_path_and_command=command; + + int stdin_fd, stdout_fd, stderr_fd; + async_executes_mutex.lock(); + stdin_buffer.clear(); + auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); + async_executes.emplace_back(pid, stdin_fd); + async_executes_mutex.unlock(); + + if (pid<=0) { + async_print("Error: Failed to run command: " + command + "\n"); + if(callback) + callback(-1); + } + else { + std::thread stderr_thread([this, stderr_fd](){ + char buffer[1024]; + ssize_t n; + while ((n=read(stderr_fd, buffer, 1024)) > 0) { + std::string message; + for(ssize_t c=0;c 0) { + std::string message; + for(ssize_t c=0;cfirst==pid) { + async_executes.erase(it); + break; + } + } + stdin_buffer.clear(); + close(stdin_fd); + close(stdout_fd); + close(stderr_fd); + async_executes_mutex.unlock(); + + if(callback) + callback(exit_code); + } + }); + async_execute_thread.detach();*/ + if(callback) + callback(-1); +} + +void Terminal::kill_last_async_execute(bool force) { + async_executes_mutex.lock(); + /*if(async_executes.size()>0) { + if(force) + kill(-async_executes.back().first, SIGTERM); + else + kill(-async_executes.back().first, SIGINT); + }*/ + async_executes_mutex.unlock(); +} + +void Terminal::kill_async_executes(bool force) { + async_executes_mutex.lock(); + /*for(auto &async_execute: async_executes) { + if(force) + kill(-async_execute.first, SIGTERM); + else + kill(-async_execute.first, SIGINT); + }*/ + async_executes_mutex.unlock(); +} + +int Terminal::print(const std::string &message, bool bold){ + INFO("Terminal: PrintMessage"); + if(bold) + get_buffer()->insert_with_tag(get_buffer()->end(), message, bold_tag); + else + get_buffer()->insert(get_buffer()->end(), message); + + auto iter=get_buffer()->end(); + if(iter.backward_char()) { + auto mark=get_buffer()->create_mark(iter); + scroll_to(mark, 0.0, 1.0, 1.0); + get_buffer()->delete_mark(mark); + } + + return get_buffer()->end().get_line(); +} + +void Terminal::print(int line_nr, const std::string &message){ + INFO("Terminal: PrintMessage at line " << line_nr); + auto iter=get_buffer()->get_iter_at_line(line_nr); + while(!iter.ends_line()) + iter++; + get_buffer()->insert(iter, message); +} + +std::shared_ptr Terminal::print_in_progress(std::string start_msg) { + std::shared_ptr in_progress=std::shared_ptr(new Terminal::InProgress(start_msg)); + return in_progress; +} + +void Terminal::async_print(const std::string &message, bool bold) { + async_print_strings_mutex.lock(); + bool dispatch=true; + if(async_print_strings.size()>0) + dispatch=false; + async_print_strings.emplace_back(message, bold); + async_print_strings_mutex.unlock(); + if(dispatch) + async_print_dispatcher(); +} + +void Terminal::async_print(int line_nr, const std::string &message) { + async_print_on_line_strings_mutex.lock(); + bool dispatch=true; + if(async_print_on_line_strings.size()>0) + dispatch=false; + async_print_on_line_strings.emplace_back(line_nr, message); + async_print_on_line_strings_mutex.unlock(); + if(dispatch) + async_print_on_line_dispatcher(); +} + +bool Terminal::on_key_press_event(GdkEventKey *event) { + async_executes_mutex.lock(); + if(async_executes.size()>0) { + get_buffer()->place_cursor(get_buffer()->end()); + auto unicode=gdk_keyval_to_unicode(event->keyval); + char chr=(char)unicode; + if(unicode>=32 && unicode<=126) { + stdin_buffer+=chr; + get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); + scroll_to(get_buffer()->get_insert()); + } + else if(event->keyval==GDK_KEY_BackSpace) { + if(stdin_buffer.size()>0 && get_buffer()->get_char_count()>0) { + auto iter=get_buffer()->end(); + iter--; + stdin_buffer.pop_back(); + get_buffer()->erase(iter, get_buffer()->end()); + scroll_to(get_buffer()->get_insert()); + } + } + else if(event->keyval==GDK_KEY_Return) { + stdin_buffer+='\n'; + write(async_executes.back().second, stdin_buffer.c_str(), stdin_buffer.size()); + get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); + scroll_to(get_buffer()->get_insert()); + stdin_buffer.clear(); + } + } + async_executes_mutex.unlock(); + return true; +} From fac0d3ff2acb1525acb41948672fc432fb7e144c Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Tue, 25 Aug 2015 13:24:46 +0200 Subject: [PATCH 30/60] Update install.md --- docs/install.md | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/docs/install.md b/docs/install.md index 7c2c456..7f92809 100644 --- a/docs/install.md +++ b/docs/install.md @@ -28,10 +28,41 @@ make install ``` ##Windows with MSYS2 (https://msys2.github.io/) -Will be available when the following TODOs are resolved: +Please wait until the following TODOs are resolved: * Newlines are saved properly -* Windows implementation of fork/pipe/read/write +* Windows implementation of creating processes * libclang(mm) finds header-files +* fix make install, and install to mingw[32/64]/bin + +Install dependencies(replace [arch] with i686 or x86_64 depending on your MSYS2 install): +```sh +pacman -S patch autoconf automake-wrapper mingw-w64-[arch]-gtkmm3 mingw-w64-[arch]-boost +``` + +Get juCi++ source: +```sh +git clone https://github.com/cppit/jucipp.git +cd jucipp +``` + +Compiling and installing gtksourceview3 and gtksourceviewmm3: +```sh +cd MINGW-packages/mingw-w64-gtksourceview3/ +makepkg-mingw -sLf +pacman -U mingw-w64-[arch]-gtksourceview3-3.12.0-2-any.pkg.tar.xz +cd ../mingw-w64-gtksourceviewmm3/ +makepkg-mingw -sLf +pacman -U mingw-w64-[arch]-gtksourceviewmm3-3.12.0-1-any.pkg.tar.xz +cd ../../ +``` + +Compile and install juCi++ source: +```sh +cmake -G"MSYS Makefiles" . +make +make install +``` +**You might have to install juci manually** \ No newline at end of file +--> From 218decdb1504b81e216bb6b917c33df89207a1d0 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Tue, 25 Aug 2015 13:39:05 +0200 Subject: [PATCH 31/60] Update install.md --- docs/install.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index 7f92809..2e8837b 100644 --- a/docs/install.md +++ b/docs/install.md @@ -85,7 +85,6 @@ Note that we are currently working on a Windows-version without the need of an X --> ## Run -#### Linux/OS X ```sh juci ``` From 0a4253aa9b326fa1a5a907a171722f3c9d3bab9d Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Wed, 26 Aug 2015 11:47:34 +0200 Subject: [PATCH 32/60] Terminal now works in Windows. Cmake, make and run works as well. --- src/files.h | 4 + src/terminal.h | 5 +- src/terminal_win.cc | 346 +++++++++++++++++++++++++++++--------------- 3 files changed, 235 insertions(+), 120 deletions(-) diff --git a/src/files.h b/src/files.h index a706c2f..a20069d 100644 --- a/src/files.h +++ b/src/files.h @@ -62,7 +62,11 @@ const std::string configjson = " \"force_kill_last_running\": \"Escape\"\n" " },\n" " \"project\": {\n" +#ifdef _WIN32 +" \"cmake_command\": \"cmake -G\\\"MSYS Makefiles\\\"\",\n" +#else " \"cmake_command\": \"cmake\",\n" +#endif " \"make_command\": \"make\"\n" " },\n" " \"directoryfilter\": {\n" diff --git a/src/terminal.h b/src/terminal.h index dfd1f50..173a4de 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -54,8 +54,11 @@ private: Glib::RefPtr bold_tag; std::mutex async_executes_mutex; +#ifdef _WIN32 + std::list > async_executes; +#else std::list > async_executes; - +#endif std::string stdin_buffer; }; diff --git a/src/terminal_win.cc b/src/terminal_win.cc index b6a7fdb..2a8b2de 100644 --- a/src/terminal_win.cc +++ b/src/terminal_win.cc @@ -3,10 +3,121 @@ #include "logging.h" #include "singletons.h" #include +#include #include //TODO: remove using namespace std; //TODO: remove +#define BUFSIZE 1024 + +HANDLE popen3(const std::string &command, const boost::filesystem::path &path, HANDLE &stdin_h, HANDLE &stdout_h, HANDLE &stderr_h) { + HANDLE g_hChildStd_IN_Rd = NULL; + HANDLE g_hChildStd_IN_Wr = NULL; + HANDLE g_hChildStd_OUT_Rd = NULL; + HANDLE g_hChildStd_OUT_Wr = NULL; + HANDLE g_hChildStd_ERR_Rd = NULL; + HANDLE g_hChildStd_ERR_Wr = NULL; + + SECURITY_ATTRIBUTES saAttr; + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) + return NULL; + if(!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) { + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_IN_Wr); + return NULL; + } + if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) { + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_IN_Wr); + return NULL; + } + if(!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_IN_Wr); + CloseHandle(g_hChildStd_OUT_Rd); + CloseHandle(g_hChildStd_OUT_Wr); + return NULL; + } + if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr, 0)) { + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_IN_Wr); + CloseHandle(g_hChildStd_OUT_Rd); + CloseHandle(g_hChildStd_OUT_Wr); + return NULL; + } + if(!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) { + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_IN_Wr); + CloseHandle(g_hChildStd_OUT_Rd); + CloseHandle(g_hChildStd_OUT_Wr); + CloseHandle(g_hChildStd_ERR_Rd); + CloseHandle(g_hChildStd_ERR_Wr); + return NULL; + } + + PROCESS_INFORMATION process_info; + STARTUPINFO siStartInfo; + + ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION)); + + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = g_hChildStd_ERR_Wr; + siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; + siStartInfo.hStdInput = g_hChildStd_IN_Rd; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + char* path_ptr; + if(path=="") + path_ptr=NULL; + else { + auto path_str=path.string(); + path_ptr=new char[path_str.size()+1]; + std::strcpy(path_ptr, path_str.c_str()); + } + char* command_cstr=new char[command.size()+1]; + std::strcpy(command_cstr, command.c_str()); + BOOL bSuccess = CreateProcess(NULL, + command_cstr, // command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + path_ptr, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + &process_info); // receives PROCESS_INFORMATION + + if(!bSuccess) { + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_OUT_Wr); + CloseHandle(g_hChildStd_ERR_Wr); + return NULL; + } + else { + // Close handles to the child process and its primary thread. + // Some applications might keep these handles to monitor the status + // of the child process, for example. + + CloseHandle(process_info.hThread); + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_OUT_Wr); + CloseHandle(g_hChildStd_ERR_Wr); + } + + stdin_h=g_hChildStd_IN_Wr; + stdout_h=g_hChildStd_OUT_Rd; + stderr_h=g_hChildStd_ERR_Rd; + return process_info.hProcess; +} + Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) { waiting_print.connect([this](){ Singleton::terminal()->async_print(line_nr-1, "."); @@ -80,149 +191,144 @@ Terminal::Terminal() { }); } +//Based on the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { - /*std::string cd_path_and_command; - if(path!="") { - //TODO: Windows... - cd_path_and_command="cd \""+path.string()+"\" && "+command; - } - else - cd_path_and_command=command; - - int stdin_fd, stdout_fd, stderr_fd; - auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); - - if (pid<=0) { + HANDLE stdin_h, stdout_h, stderr_h; + + auto process=popen3(command, path, stdin_h, stdout_h, stderr_h); + if(process==NULL) { async_print("Error: Failed to run command: " + command + "\n"); return -1; } - else { - std::thread stderr_thread([this, stderr_fd](){ - char buffer[1024]; - ssize_t n; - while ((n=read(stderr_fd, buffer, 1024)) > 0) { - std::string message; - for(ssize_t c=0;c callback) { + std::thread async_execute_thread([this, command, path, callback](){ + HANDLE stdin_h, stdout_h, stderr_h; + + async_executes_mutex.lock(); + stdin_buffer.clear(); + auto process=popen3(command, path, stdin_h, stdout_h, stderr_h); + if(process==NULL) { + async_executes_mutex.unlock(); + async_print("Error: Failed to run command: " + command + "\n"); + if(callback) + callback(-1); + return; + } + async_executes.emplace_back(process, stdin_h); + async_executes_mutex.unlock(); + + std::thread stderr_thread([this, stderr_h](){ + DWORD n; + CHAR buffer[BUFSIZE]; + for (;;) { + BOOL bSuccess = ReadFile(stderr_h, buffer, BUFSIZE, &n, NULL); + if(!bSuccess || n == 0) + break; + + std::string message; + for(DWORD c=0;c 0) { - std::string message; - for(ssize_t c=0;c callback) { - /*std::thread async_execute_thread([this, command, path, callback](){ - std::string cd_path_and_command; - if(path!="") { - - //TODO: Windows... - cd_path_and_command="cd \""+path.string()+"\" && "+command; - } - else - cd_path_and_command=command; - - int stdin_fd, stdout_fd, stderr_fd; + unsigned long exit_code; + WaitForSingleObject(process, INFINITE); + GetExitCodeProcess(process, &exit_code); + async_executes_mutex.lock(); + for(auto it=async_executes.begin();it!=async_executes.end();it++) { + if(it->first==process) { + async_executes.erase(it); + break; + } + } stdin_buffer.clear(); - auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); - async_executes.emplace_back(pid, stdin_fd); + CloseHandle(process); + CloseHandle(stdin_h); + CloseHandle(stdout_h); + CloseHandle(stderr_h); async_executes_mutex.unlock(); - - if (pid<=0) { - async_print("Error: Failed to run command: " + command + "\n"); - if(callback) - callback(-1); - } - else { - std::thread stderr_thread([this, stderr_fd](){ - char buffer[1024]; - ssize_t n; - while ((n=read(stderr_fd, buffer, 1024)) > 0) { - std::string message; - for(ssize_t c=0;c 0) { - std::string message; - for(ssize_t c=0;cfirst==pid) { - async_executes.erase(it); - break; - } - } - stdin_buffer.clear(); - close(stdin_fd); - close(stdout_fd); - close(stderr_fd); - async_executes_mutex.unlock(); - - if(callback) - callback(exit_code); - } + if(callback) + callback(exit_code); }); - async_execute_thread.detach();*/ - if(callback) - callback(-1); + async_execute_thread.detach(); } void Terminal::kill_last_async_execute(bool force) { async_executes_mutex.lock(); - /*if(async_executes.size()>0) { - if(force) - kill(-async_executes.back().first, SIGTERM); - else - kill(-async_executes.back().first, SIGINT); - }*/ + if(async_executes.size()>0) { + TerminateProcess(async_executes.back().first, 2); + } async_executes_mutex.unlock(); } void Terminal::kill_async_executes(bool force) { async_executes_mutex.lock(); - /*for(auto &async_execute: async_executes) { - if(force) - kill(-async_execute.first, SIGTERM); - else - kill(-async_execute.first, SIGINT); - }*/ + for(auto &async_execute: async_executes) { + TerminateProcess(async_execute.first, 2); + } async_executes_mutex.unlock(); } @@ -300,7 +406,9 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { } else if(event->keyval==GDK_KEY_Return) { stdin_buffer+='\n'; - write(async_executes.back().second, stdin_buffer.c_str(), stdin_buffer.size()); + DWORD written; + WriteFile(async_executes.back().second, stdin_buffer.c_str(), stdin_buffer.size(), &written, NULL); + //TODO: is this line needed? get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); scroll_to(get_buffer()->get_insert()); stdin_buffer.clear(); From f9671f5b6e354c977c09a300f8c71fdaaea14308 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Wed, 26 Aug 2015 14:31:50 +0200 Subject: [PATCH 33/60] Added true monospace font for Windows. --- src/files.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/files.h b/src/files.h index a20069d..7b390a1 100644 --- a/src/files.h +++ b/src/files.h @@ -10,8 +10,12 @@ const std::string configjson = #ifdef __APPLE__ " \"font\": \"Menlo 11\", " #else +#ifdef _WIN32 +" \"font\": \"Consolas\", " +#else " \"font\": \"Monospace\", " #endif +#endif "//Use \"\" for default font, and for instance \"Monospace 12\" to also set size.\n" " \"clang_types\": {\n" " \"8\": \"def:function\",\n" From c43d579f5adc7bd02d6491f0941535faac0238c2 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Thu, 27 Aug 2015 10:05:46 +0200 Subject: [PATCH 34/60] Now will not add carriage returns unless gtk so decides (depending on file I guess), and fixed include problems for MSYS2's buggy libclang install. Mind the latter is a termporary fix. --- src/cmake.cc | 19 ++++++++++++++++++- src/source.cc | 33 +++++++++++++++++++++++++++++++++ src/sourcefile.cc | 2 +- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index aab2338..521eefa 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -47,8 +47,25 @@ CMake::CMake(const boost::filesystem::path &path) { bool CMake::create_compile_commands(const boost::filesystem::path &path) { Singleton::terminal()->print("Creating "+path.string()+"/compile_commands.json\n"); //TODO: Windows... - if(Singleton::terminal()->execute(Singleton::Config::terminal()->cmake_command+" . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==EXIT_SUCCESS) + if(Singleton::terminal()->execute(Singleton::Config::terminal()->cmake_command+" . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==EXIT_SUCCESS) { +#ifdef _WIN32 //Temporary fix to MSYS2's libclang + auto compile_commands_path=path; + compile_commands_path+="/compile_commands.json"; + auto compile_commands_file=juci::filesystem::read(compile_commands_path); + size_t pos=0; + while((pos=compile_commands_file.find("-I/", pos))!=std::string::npos) { + if(pos+3 Source::ClangViewParse::get_compilation_commands() { } if(file_path.extension()==".h") //TODO: temporary fix for .h-files (parse as c++) arguments.emplace_back("-xc++"); +#ifdef _WIN32 //Temporary fix to MSYS2's libclang + arguments.emplace_back("-IC:/msys32/mingw32/lib/gcc/i686-w64-mingw32/5.2.0/include"); + arguments.emplace_back("-IC:/msys32/mingw32//include"); + arguments.emplace_back("-IC:/msys32/mingw32/lib/gcc/i686-w64-mingw32/5.2.0/include-fixed"); + arguments.emplace_back("-IC:/msys32/mingw32/i686-w64-mingw32/include"); + arguments.emplace_back("-IC:/msys32/mingw32/include/c++/5.2.0"); + arguments.emplace_back("-IC:/msys32/mingw32/include/c++/5.2.0/i686-w64-mingw32"); + arguments.emplace_back("-IC:/msys32/mingw32/include/c++/5.2.0/backward"); + + arguments.emplace_back("-IC:/msys32/mingw64/lib/gcc/i686-w64-mingw32/5.2.0/include"); + arguments.emplace_back("-IC:/msys32/mingw64//include"); + arguments.emplace_back("-IC:/msys32/mingw64/lib/gcc/i686-w64-mingw32/5.2.0/include-fixed"); + arguments.emplace_back("-IC:/msys32/mingw64/i686-w64-mingw32/include"); + arguments.emplace_back("-IC:/msys32/mingw64/include/c++/5.2.0"); + arguments.emplace_back("-IC:/msys32/mingw64/include/c++/5.2.0/i686-w64-mingw32"); + arguments.emplace_back("-IC:/msys32/mingw64/include/c++/5.2.0/backward"); + + arguments.emplace_back("-IC:/msys64/mingw32/lib/gcc/i686-w64-mingw32/5.2.0/include"); + arguments.emplace_back("-IC:/msys64/mingw32//include"); + arguments.emplace_back("-IC:/msys64/mingw32/lib/gcc/i686-w64-mingw32/5.2.0/include-fixed"); + arguments.emplace_back("-IC:/msys64/mingw32/i686-w64-mingw32/include"); + arguments.emplace_back("-IC:/msys64/mingw32/include/c++/5.2.0"); + arguments.emplace_back("-IC:/msys64/mingw32/include/c++/5.2.0/i686-w64-mingw32"); + arguments.emplace_back("-IC:/msys64/mingw32/include/c++/5.2.0/backward"); + + arguments.emplace_back("-IC:/msys64/mingw64/lib/gcc/i686-w64-mingw32/5.2.0/include"); + arguments.emplace_back("-IC:/msys64/mingw64//include"); + arguments.emplace_back("-IC:/msys64/mingw64/lib/gcc/i686-w64-mingw32/5.2.0/include-fixed"); + arguments.emplace_back("-IC:/msys64/mingw64/i686-w64-mingw32/include"); + arguments.emplace_back("-IC:/msys64/mingw64/include/c++/5.2.0"); + arguments.emplace_back("-IC:/msys64/mingw64/include/c++/5.2.0/i686-w64-mingw32"); + arguments.emplace_back("-IC:/msys64/mingw64/include/c++/5.2.0/backward"); +#endif return arguments; } diff --git a/src/sourcefile.cc b/src/sourcefile.cc index ae5780b..6039136 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -58,7 +58,7 @@ bool juci::filesystem::write(const std::string &path, const std::string &new_con } bool juci::filesystem::write(const std::string &path, Glib::RefPtr buffer) { - std::ofstream output(path); + std::ofstream output(path, std::ofstream::binary); if(output) { auto start_iter=buffer->begin(); auto end_iter=start_iter; From 237381a251926612e1b9506bbf18df121d90dd39 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Thu, 27 Aug 2015 10:19:07 +0200 Subject: [PATCH 35/60] Added std::ofstream::binary to all file reads and writes. --- src/sourcefile.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sourcefile.cc b/src/sourcefile.cc index 6039136..7fc796b 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -7,7 +7,7 @@ const size_t buffer_size=131072; //Only use on small files std::string juci::filesystem::read(const std::string &path) { std::stringstream ss; - std::ifstream input(path); + std::ifstream input(path, std::ofstream::binary); if(input) { ss << input.rdbuf(); input.close(); @@ -16,7 +16,7 @@ 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::ifstream input(path, std::ofstream::binary); if(input) { std::vector buffer(buffer_size); size_t read_length; @@ -38,7 +38,7 @@ bool juci::filesystem::read(const std::string &path, Glib::RefPtr juci::filesystem::read_lines(const std::string &path) { std::vector res; - std::ifstream input(path); + std::ifstream input(path, std::ofstream::binary); if (input) { do { res.emplace_back(); } while(getline(input, res.back())); } @@ -48,7 +48,7 @@ std::vector juci::filesystem::read_lines(const std::string &path) { //Only use on small files bool juci::filesystem::write(const std::string &path, const std::string &new_content) { - std::ofstream output(path); + std::ofstream output(path, std::ofstream::binary); if(output) output << new_content; else From 52adf1c07d6d35aaab91649b9ce2b927690e28d7 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Thu, 27 Aug 2015 12:32:32 +0200 Subject: [PATCH 36/60] Now doing a soft reparse every time a clangview-page gets focused (in case a header file for instance is changed) --- src/source.h | 2 +- src/window.cc | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/source.h b/src/source.h index e51ff3d..f71d3ee 100644 --- a/src/source.h +++ b/src/source.h @@ -102,9 +102,9 @@ namespace Source { public: ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); boost::filesystem::path project_path; + void start_reparse(); protected: void init_parse(); - void start_reparse(); bool on_key_press_event(GdkEventKey* key); bool on_focus_out_event(GdkEventFocus* event); std::unique_ptr clang_tu; diff --git a/src/window.cc b/src/window.cc index bba2e52..75c528a 100644 --- a/src/window.cc +++ b/src/window.cc @@ -93,6 +93,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())) + source_view->start_reparse(); + Singleton::status()->set_text(notebook.get_current_view()->status); } }); From 729b8af35cbee50fbe851956533aafa54b2ed9d0 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Thu, 27 Aug 2015 13:09:49 +0200 Subject: [PATCH 37/60] Fixed: assertion 'buffer->priv->user_action_count > 0' failed --- src/selectiondialog.cc | 4 +++- src/selectiondialog.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index 9965b98..8b73072 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -64,6 +64,7 @@ void SelectionDialogBase::add_row(const std::string& row, const std::string& too } void SelectionDialogBase::show() { + shown=true; move(); window->show_all(); } @@ -72,8 +73,9 @@ void SelectionDialogBase::hide() { window->hide(); if(tooltips) tooltips->hide(); - if(on_hide) + if(on_hide && shown) on_hide(); + shown=false; } void SelectionDialogBase::update_tooltips() { diff --git a/src/selectiondialog.h b/src/selectiondialog.h index abdd59b..e454a3c 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -31,6 +31,8 @@ protected: std::unique_ptr tooltips; std::unordered_map tooltip_texts; std::string last_row; +private: + bool shown=false; }; class SelectionDialog : public SelectionDialogBase { From 1fc5a53f70166d163e51a938a8388607f404605f Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Thu, 27 Aug 2015 13:17:27 +0200 Subject: [PATCH 38/60] Fixed bug where autocomplete could not finish if a variable in a class was defined later in the source code. --- src/source.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index 43268c0..3a12d4c 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1194,7 +1194,7 @@ void Source::ClangViewAutocomplete::autocomplete() { std::shared_ptr > buffer_map=std::make_shared >(); auto& buffer=(*buffer_map)[this->file_path.string()]; - buffer=get_buffer()->get_text(get_buffer()->begin(), get_buffer()->get_insert()->get_iter()); + buffer=get_buffer()->get_text(); auto iter = get_source_buffer()->get_insert()->get_iter(); auto line_nr=iter.get_line()+1; auto column_nr=iter.get_line_offset()+1; From 96d9330d9dbc77e6460ba5b4004759f6e015b59a Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Thu, 27 Aug 2015 13:53:37 +0200 Subject: [PATCH 39/60] Added slight delay on tag-similar-tokens so that scrolling up/down with arrowkeys is more smooth. --- src/source.cc | 8 ++++++-- src/source.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/source.cc b/src/source.cc index 3a12d4c..6f652f5 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1340,8 +1340,12 @@ Source::ClangViewAutocomplete(file_path, project_path) { get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark){ if(mark->get_name()=="insert") { - auto usr=get_token(); - tag_similar_tokens(usr); + delayed_tag_similar_tokens_connection.disconnect(); + delayed_tag_similar_tokens_connection=Glib::signal_timeout().connect([this]() { + auto usr=get_token(); + tag_similar_tokens(usr); + return false; + }, 100); } }); diff --git a/src/source.h b/src/source.h index f71d3ee..5380f00 100644 --- a/src/source.h +++ b/src/source.h @@ -177,6 +177,7 @@ namespace Source { private: Glib::RefPtr similar_tokens_tag; std::string last_similar_tokens_tagged; + sigc::connection delayed_tag_similar_tokens_connection; std::unique_ptr selection_dialog; bool renaming=false; }; From 7213702d3f400ecd376865146fa87230c1693d53 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Thu, 27 Aug 2015 14:22:02 +0200 Subject: [PATCH 40/60] Fixed potential crash if file-read accidently splits up an UTF-8 char. --- src/sourcefile.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/sourcefile.cc b/src/sourcefile.cc index 7fc796b..260a5fb 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -20,13 +20,18 @@ bool juci::filesystem::read(const std::string &path, Glib::RefPtr buffer(buffer_size); size_t read_length; + std::string buffer_str; while((read_length=input.read(&buffer[0], buffer_size).gcount())>0) { - auto ustr=Glib::ustring(std::string(&buffer[0], read_length)); - if(ustr.validate()) - text_buffer->insert_at_cursor(ustr); - else { - input.close(); - return false; + 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; + } } } input.close(); From 25ef8f8610774975bd8947bb3a159a668698bea1 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 27 Aug 2015 16:02:03 +0200 Subject: [PATCH 41/60] Getting ready to add spellcheck in comments using aspell library. --- src/notebook.cc | 2 +- src/source.cc | 20 +++++++++++++++++++- src/source.h | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/notebook.cc b/src/notebook.cc index 7bfd4f9..ad329ab 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -67,7 +67,7 @@ void Notebook::open(const boost::filesystem::path &file_path) { else Singleton::terminal()->print("Error: could not find project path for "+file_path.string()+"\n"); } - source_views.emplace_back(new Source::ClangView(file_path, project_path)); + source_views.emplace_back(new Source::ClangView(file_path, project_path, language)); } else source_views.emplace_back(new Source::GenericView(file_path, language)); diff --git a/src/source.cc b/src/source.cc index 6f652f5..adab60d 100644 --- a/src/source.cc +++ b/src/source.cc @@ -97,6 +97,19 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat tab+=tab_char; tabs_regex=std::regex(std::string("^(")+tab_char+"*)(.*)$"); + + get_buffer()->signal_changed().connect([this](){ + auto iter=get_buffer()->get_insert()->get_iter(); + if(iter.backward_char()) { + auto context_iter=iter; + if(context_iter.backward_char()) { + if(get_source_buffer()->iter_has_context_class(context_iter, "comment")) { + //TODO: get word, and spellcheck + //cout << "comment: " << (char)*iter << endl; + } + } + } + }); } void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data) { @@ -1394,7 +1407,12 @@ Source::ClangViewAutocomplete(file_path, project_path) { }; } -Source::ClangView::ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path): ClangViewRefactor(file_path, project_path) { +Source::ClangView::ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr language): ClangViewRefactor(file_path, project_path) { + if(language) { + get_source_buffer()->set_highlight_syntax(false); + get_source_buffer()->set_language(language); + } + do_delete_object.connect([this](){ if(delete_thread.joinable()) delete_thread.join(); diff --git a/src/source.h b/src/source.h index 5380f00..20185f9 100644 --- a/src/source.h +++ b/src/source.h @@ -184,7 +184,7 @@ namespace Source { class ClangView : public ClangViewRefactor { public: - ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); + ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr language); void async_delete(); bool restart_parse(); private: From 946134d7fe2e68fd9afc11abdcb4d2c9ffacb875 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 27 Aug 2015 18:28:11 +0200 Subject: [PATCH 42/60] Fixed autocomplete again, now should work in all cases. --- src/source.cc | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/source.cc b/src/source.cc index adab60d..202b17e 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1207,15 +1207,23 @@ void Source::ClangViewAutocomplete::autocomplete() { std::shared_ptr > buffer_map=std::make_shared >(); auto& buffer=(*buffer_map)[this->file_path.string()]; - buffer=get_buffer()->get_text(); - auto iter = get_source_buffer()->get_insert()->get_iter(); + auto iter=get_buffer()->get_insert()->get_iter(); + buffer=get_buffer()->get_text(get_buffer()->begin(), iter); auto line_nr=iter.get_line()+1; auto column_nr=iter.get_line_offset()+1; - while((buffer.back()>='a' && buffer.back()<='z') || (buffer.back()>='A' && buffer.back()<='Z') || (buffer.back()>='0' && buffer.back()<='9') || buffer.back()=='_') { - buffer.pop_back(); - column_nr--; + unsigned c=1; + if(c<=buffer.size()) { + char *chr=&buffer[buffer.size()-c]; + while((*chr>='a' && *chr<='z') || (*chr>='A' && *chr<='Z') || (*chr>='0' && *chr<='9') || *chr=='_') { + *chr=' '; + column_nr--; + c++; + if(c>buffer.size()) + break; + chr--; + } } - buffer+="\n"; + buffer+=get_buffer()->get_text(iter, get_buffer()->end()); set_status("autocomplete..."); if(autocomplete_thread.joinable()) autocomplete_thread.join(); From bc6785fcee3a0da64e2dfb92841de3c75f2d12d9 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 08:10:23 +0200 Subject: [PATCH 43/60] Some cleanup. --- src/cmake.cc | 1 - src/terminal.cc | 98 ++++++++++++++++++++++----------------------- src/terminal_win.cc | 17 ++++---- src/window.cc | 3 -- 4 files changed, 57 insertions(+), 62 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index 521eefa..d112a26 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -46,7 +46,6 @@ CMake::CMake(const boost::filesystem::path &path) { bool CMake::create_compile_commands(const boost::filesystem::path &path) { Singleton::terminal()->print("Creating "+path.string()+"/compile_commands.json\n"); - //TODO: Windows... if(Singleton::terminal()->execute(Singleton::Config::terminal()->cmake_command+" . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==EXIT_SUCCESS) { #ifdef _WIN32 //Temporary fix to MSYS2's libclang auto compile_commands_path=path; diff --git a/src/terminal.cc b/src/terminal.cc index 4df8e24..aed5906 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -8,57 +8,74 @@ #include //TODO: remove using namespace std; //TODO: remove -//TODO: Windows... //A working implementation of popen3, with all pipes getting closed properly. //TODO: Eidheim is going to publish this one on his github, along with example uses -pid_t popen3(const char *command, int &stdin_fd, int &stdout_fd, int &stderr_fd) { +pid_t popen3(const std::string &command, const std::string &path, int *stdin_fd, int *stdout_fd, int *stderr_fd) { pid_t pid; - int p_stdin[2], p_stdout[2], p_stderr[2]; + int stdin_p[2], stdout_p[2], stderr_p[2]; - if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0 || pipe(p_stderr) != 0) { - close(p_stdin[0]); - close(p_stdout[0]); - close(p_stderr[0]); - close(p_stdin[1]); - close(p_stdout[1]); - close(p_stderr[1]); + if(stdin_fd!=nullptr && pipe(stdin_p)!=0) { + close(stdin_p[0]); + close(stdin_p[1]); return -1; } - + if(stdout_fd!=nullptr && pipe(stdout_p)!=0) { + if(stdin_fd!=nullptr) close(stdin_p[0]); + if(stdin_fd!=nullptr) close(stdin_p[1]); + close(stdout_p[0]); + close(stdout_p[1]); + return -1; + } + if(stderr_fd!=nullptr && pipe(stderr_p)!=0) { + if(stdin_fd!=nullptr) close(stdin_p[0]); + if(stdin_fd!=nullptr) close(stdin_p[1]); + if(stdout_fd!=nullptr) close(stdout_p[0]); + if(stdout_fd!=nullptr) close(stdout_p[1]); + close(stderr_p[0]); + close(stderr_p[1]); + return -1; + } + pid = fork(); if (pid < 0) { - close(p_stdin[0]); - close(p_stdout[0]); - close(p_stderr[0]); - close(p_stdin[1]); - close(p_stdout[1]); - close(p_stderr[1]); + if(stdin_fd!=nullptr) close(stdin_p[0]); + if(stdin_fd!=nullptr) close(stdin_p[1]); + if(stdout_fd!=nullptr) close(stdout_p[0]); + if(stdout_fd!=nullptr) close(stdout_p[1]); + if(stderr_fd!=nullptr) close(stderr_p[0]); + if(stderr_fd!=nullptr) close(stderr_p[1]); return pid; } else if (pid == 0) { - close(p_stdin[1]); - close(p_stdout[0]); - close(p_stderr[0]); - dup2(p_stdin[0], 0); - dup2(p_stdout[1], 1); - dup2(p_stderr[1], 2); + if(stdin_fd!=nullptr) close(stdin_p[1]); + if(stdout_fd!=nullptr) close(stdout_p[0]); + if(stderr_fd!=nullptr) close(stderr_p[0]); + if(stdin_fd!=nullptr) dup2(stdin_p[0], 0); + if(stdout_fd!=nullptr) dup2(stdout_p[1], 1); + if(stderr_fd!=nullptr) dup2(stderr_p[1], 2); setpgid(0, 0); //TODO: See here on how to emulate tty for colors: http://stackoverflow.com/questions/1401002/trick-an-application-into-thinking-its-stdin-is-interactive-not-a-pipe //TODO: One solution is: echo "command;exit"|script -q /dev/null - execl("/bin/sh", "sh", "-c", command, NULL); + std::string cd_path_and_command; + if(path!="") { + cd_path_and_command="cd \""+path+"\" && "+command; + } + else + cd_path_and_command=command; + execl("/bin/sh", "sh", "-c", cd_path_and_command.c_str(), NULL); perror("execl"); exit(EXIT_FAILURE); } - close(p_stdin[0]); - close(p_stdout[1]); - close(p_stderr[1]); + if(stdin_fd!=nullptr) close(stdin_p[0]); + if(stdout_fd!=nullptr) close(stdout_p[1]); + if(stderr_fd!=nullptr) close(stderr_p[1]); - stdin_fd = p_stdin[1]; - stdout_fd = p_stdout[0]; - stderr_fd = p_stderr[0]; + if(stdin_fd!=nullptr) *stdin_fd = stdin_p[1]; + if(stdout_fd!=nullptr) *stdout_fd = stdout_p[0]; + if(stderr_fd!=nullptr) *stderr_fd = stderr_p[0]; return pid; } @@ -137,16 +154,8 @@ Terminal::Terminal() { } int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { - std::string cd_path_and_command; - if(path!="") { - //TODO: Windows... - cd_path_and_command="cd \""+path.string()+"\" && "+command; - } - else - cd_path_and_command=command; - int stdin_fd, stdout_fd, stderr_fd; - auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); + auto pid=popen3(command, path.string(), &stdin_fd, &stdout_fd, &stderr_fd); if (pid<=0) { async_print("Error: Failed to run command: " + command + "\n"); @@ -189,19 +198,10 @@ int Terminal::execute(const std::string &command, const boost::filesystem::path void Terminal::async_execute(const std::string &command, const boost::filesystem::path &path, std::function callback) { std::thread async_execute_thread([this, command, path, callback](){ - std::string cd_path_and_command; - if(path!="") { - - //TODO: Windows... - cd_path_and_command="cd \""+path.string()+"\" && "+command; - } - else - cd_path_and_command=command; - int stdin_fd, stdout_fd, stderr_fd; async_executes_mutex.lock(); stdin_buffer.clear(); - auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); + auto pid=popen3(command, path.string(), &stdin_fd, &stdout_fd, &stderr_fd); async_executes.emplace_back(pid, stdin_fd); async_executes_mutex.unlock(); diff --git a/src/terminal_win.cc b/src/terminal_win.cc index 2a8b2de..e79014d 100644 --- a/src/terminal_win.cc +++ b/src/terminal_win.cc @@ -10,7 +10,7 @@ using namespace std; //TODO: remove #define BUFSIZE 1024 -HANDLE popen3(const std::string &command, const boost::filesystem::path &path, HANDLE &stdin_h, HANDLE &stdout_h, HANDLE &stderr_h) { +HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin_h, HANDLE *stdout_h, HANDLE *stderr_h) { HANDLE g_hChildStd_IN_Rd = NULL; HANDLE g_hChildStd_IN_Wr = NULL; HANDLE g_hChildStd_OUT_Rd = NULL; @@ -76,9 +76,8 @@ HANDLE popen3(const std::string &command, const boost::filesystem::path &path, H if(path=="") path_ptr=NULL; else { - auto path_str=path.string(); - path_ptr=new char[path_str.size()+1]; - std::strcpy(path_ptr, path_str.c_str()); + path_ptr=new char[path.size()+1]; + std::strcpy(path_ptr, path.c_str()); } char* command_cstr=new char[command.size()+1]; std::strcpy(command_cstr, command.c_str()); @@ -112,9 +111,9 @@ HANDLE popen3(const std::string &command, const boost::filesystem::path &path, H CloseHandle(g_hChildStd_ERR_Wr); } - stdin_h=g_hChildStd_IN_Wr; - stdout_h=g_hChildStd_OUT_Rd; - stderr_h=g_hChildStd_ERR_Rd; + *stdin_h=g_hChildStd_IN_Wr; + *stdout_h=g_hChildStd_OUT_Rd; + *stderr_h=g_hChildStd_ERR_Rd; return process_info.hProcess; } @@ -195,7 +194,7 @@ Terminal::Terminal() { int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { HANDLE stdin_h, stdout_h, stderr_h; - auto process=popen3(command, path, stdin_h, stdout_h, stderr_h); + auto process=popen3(command, path.string(), &stdin_h, &stdout_h, &stderr_h); if(process==NULL) { async_print("Error: Failed to run command: " + command + "\n"); return -1; @@ -249,7 +248,7 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem async_executes_mutex.lock(); stdin_buffer.clear(); - auto process=popen3(command, path, stdin_h, stdout_h, stderr_h); + auto process=popen3(command, path.string(), &stdin_h, &stdout_h, &stderr_h); if(process==NULL) { async_executes_mutex.unlock(); async_print("Error: Failed to run command: " + command + "\n"); diff --git a/src/window.cc b/src/window.cc index 75c528a..b3a7b18 100644 --- a/src/window.cc +++ b/src/window.cc @@ -229,12 +229,10 @@ void Window::create_menu() { if(executable_path!="") { compiling=true; Singleton::terminal()->print("Compiling and running "+executable_path.string()+"\n"); - //TODO: Windows... auto project_path=cmake.project_path; 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) { - //TODO: Windows... auto executable_path_spaces_fixed=executable_path.string(); char last_char=0; for(size_t c=0;cprint("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; }); From 1858cc2311ddf6192c7a800aef9209e720cb7c94 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 09:10:36 +0200 Subject: [PATCH 44/60] Cleanup of autocomplete buffer creation. --- src/source.cc | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/source.cc b/src/source.cc index 202b17e..de8146d 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1206,24 +1206,17 @@ void Source::ClangViewAutocomplete::autocomplete() { }); std::shared_ptr > buffer_map=std::make_shared >(); - auto& buffer=(*buffer_map)[this->file_path.string()]; + auto ustr=get_buffer()->get_text(); auto iter=get_buffer()->get_insert()->get_iter(); - buffer=get_buffer()->get_text(get_buffer()->begin(), iter); auto line_nr=iter.get_line()+1; auto column_nr=iter.get_line_offset()+1; - unsigned c=1; - if(c<=buffer.size()) { - char *chr=&buffer[buffer.size()-c]; - while((*chr>='a' && *chr<='z') || (*chr>='A' && *chr<='Z') || (*chr>='0' && *chr<='9') || *chr=='_') { - *chr=' '; - column_nr--; - c++; - if(c>buffer.size()) - break; - chr--; - } + auto pos=iter.get_offset()-1; + while(pos>=0 && ((ustr[pos]>='a' && ustr[pos]<='z') || (ustr[pos]>='A' && ustr[pos]<='Z') || (ustr[pos]>='0' && ustr[pos]<='9') || ustr[pos]=='_')) { + ustr.replace(pos, 1, " "); + column_nr--; + pos--; } - buffer+=get_buffer()->get_text(iter, get_buffer()->end()); + (*buffer_map)[this->file_path.string()]=std::move(ustr); //TODO: does this work? set_status("autocomplete..."); if(autocomplete_thread.joinable()) autocomplete_thread.join(); From d0e77f2397426f5443b11f7641658ba6965dd8e0 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 09:17:21 +0200 Subject: [PATCH 45/60] Now scrolls to the point where undo or redo happens. --- src/window.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/window.cc b/src/window.cc index b3a7b18..eb8585f 100644 --- a/src/window.cc +++ b/src/window.cc @@ -165,6 +165,7 @@ void Window::create_menu() { auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); if (undo_manager->can_undo()) { undo_manager->undo(); + notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert()); } } INFO("Done undo"); @@ -175,6 +176,7 @@ void Window::create_menu() { auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); if(undo_manager->can_redo()) { undo_manager->redo(); + notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert()); } } INFO("Done Redo"); From 4eb85d90c6903fb37b3f6bcd69a5b504fce2a504 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 11:35:50 +0200 Subject: [PATCH 46/60] Added spellcheck using aspell to comments and strings. Please install (lib)aspell(-dev) and rm ~/.juci to test. --- docs/install.md | 6 ++-- src/CMakeLists.txt | 6 +++- src/config.cc | 2 ++ src/files.h | 1 + src/source.cc | 76 +++++++++++++++++++++++++++++++++++++++------- src/source.h | 6 ++++ 6 files changed, 82 insertions(+), 15 deletions(-) diff --git a/docs/install.md b/docs/install.md index 2e8837b..12062d5 100644 --- a/docs/install.md +++ b/docs/install.md @@ -4,7 +4,7 @@ Before installation, please install libclangmm, see [installation guide](http:// ## Debian/Ubuntu ```sh -sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev +sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev libaspell-dev ``` ```sh git clone http://github.com/cppit/jucipp.git @@ -16,7 +16,7 @@ sudo make install ## OS X with Homebrew (http://brew.sh/) ```sh -brew install pkg-config boost gtkmm3 gtksourceviewmm3 +brew install pkg-config boost gtkmm3 gtksourceviewmm3 aspell ``` ```sh @@ -36,7 +36,7 @@ Please wait until the following TODOs are resolved: Install dependencies(replace [arch] with i686 or x86_64 depending on your MSYS2 install): ```sh -pacman -S patch autoconf automake-wrapper mingw-w64-[arch]-gtkmm3 mingw-w64-[arch]-boost +pacman -S patch autoconf automake-wrapper mingw-w64-[arch]-gtkmm3 mingw-w64-[arch]-boost mingw-w64-[arch]-aspell ``` Get juCi++ source: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d15e8e1..3dcada4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,6 +56,8 @@ validate(${GTKMM_FOUND} "gtkmm" "libgtkmm-dev" "gtkmm") pkg_check_modules(GTKSVMM gtksourceviewmm-3.0) validate(${GTKSVMM_FOUND} "gtksvmm" "libgtksvmm-dev" "gtkmmsv") +find_package(ASPELL REQUIRED) + set(source_files juci.h juci.cc menu.h @@ -105,7 +107,8 @@ if(${validation}) ${GTKMM_INCLUDE_DIRS} ${GTKSVMM_INCLUDE_DIRS} ${LCL_INCLUDE_DIRS} - ${LIBCLANG_INCLUDE_DIRS}) + ${LIBCLANG_INCLUDE_DIRS} + ${ASPELL_INCLUDE_DIR}) link_directories( ${GTKMM_LIBRARY_DIRS} @@ -128,6 +131,7 @@ if(${validation}) ${GTKMM_LIBRARIES} ${GTKSVMM_LIBRARIES} ${Boost_LIBRARIES} + ${ASPELL_LIBRARIES} # ${PYTHON_LIBRARIES} ) diff --git a/src/config.cc b/src/config.cc index 0de059c..7d6da88 100644 --- a/src/config.cc +++ b/src/config.cc @@ -46,6 +46,8 @@ void MainConfig::GenerateSource() { auto source_cfg = Singleton::Config::source(); auto source_json = cfg.get_child("source"); + source_cfg->spellcheck_language = source_json.get("spellcheck_language"); + 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"); diff --git a/src/files.h b/src/files.h index 7b390a1..516cf05 100644 --- a/src/files.h +++ b/src/files.h @@ -17,6 +17,7 @@ const std::string configjson = #endif #endif "//Use \"\" for default font, and for instance \"Monospace 12\" to also set size.\n" +" \"spellcheck_language\": \"en_US\", \n" " \"clang_types\": {\n" " \"8\": \"def:function\",\n" " \"21\": \"def:function\",\n" diff --git a/src/source.cc b/src/source.cc index de8146d..82168b0 100644 --- a/src/source.cc +++ b/src/source.cc @@ -7,14 +7,16 @@ #include "singletons.h" #include #include +#include -#include //TODO: remove using namespace std; //TODO: remove namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE } +AspellConfig* spellcheck_config=NULL; + Glib::RefPtr Source::guess_language(const boost::filesystem::path &file_path) { auto language_manager=Gsv::LanguageManager::get_default(); bool result_uncertain = false; @@ -98,18 +100,43 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat tabs_regex=std::regex(std::string("^(")+tab_char+"*)(.*)$"); - get_buffer()->signal_changed().connect([this](){ - auto iter=get_buffer()->get_insert()->get_iter(); - if(iter.backward_char()) { - auto context_iter=iter; - if(context_iter.backward_char()) { - if(get_source_buffer()->iter_has_context_class(context_iter, "comment")) { - //TODO: get word, and spellcheck - //cout << "comment: " << (char)*iter << endl; + if(spellcheck_config==NULL) { + spellcheck_config=new_aspell_config(); + aspell_config_replace(spellcheck_config, "lang", Singleton::Config::source()->spellcheck_language.c_str()); + } + + spellcheck_possible_err=new_aspell_speller(spellcheck_config); + spellcheck_checker=NULL; + if (aspell_error_number(spellcheck_possible_err) != 0) + std::cerr << "Spell check error: " << aspell_error_message(spellcheck_possible_err) << std::endl; + else { + spellcheck_checker = to_aspell_speller(spellcheck_possible_err); + + auto tag=get_buffer()->create_tag("spellcheck_error"); + tag->property_underline()=Pango::Underline::UNDERLINE_ERROR; + + get_buffer()->signal_changed().connect([this](){ + auto iter=get_buffer()->get_insert()->get_iter(); + if(iter.backward_char()) { + auto context_iter=iter; + if(context_iter.backward_char()) { + if(get_source_buffer()->iter_has_context_class(context_iter, "comment") || get_source_buffer()->iter_has_context_class(context_iter, "string")) { + if(*iter==32) { //Might have used space 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); + spellcheck(first); + spellcheck(second); + } + } + else + spellcheck(iter); + } } } - } - }); + }); + } } void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data) { @@ -121,6 +148,8 @@ void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* pro Source::View::~View() { g_clear_object(&search_context); g_clear_object(&search_settings); + + delete_aspell_speller(spellcheck_checker); } void Source::View::search_highlight(const std::string &text, bool case_sensitive, bool regex) { @@ -477,6 +506,31 @@ std::pair Source::View::find_tab_char_and_size() { return {found_tab_char, found_tab_size}; } +void Source::View::spellcheck(Gtk::TextIter iter) { + auto start=iter; + auto end=iter; + + while((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter==95 || *iter>=128) { + start=iter; + if(!iter.backward_char()) + break; + } + while((*end>=48 && *end<=57) || (*end>=65 && *end<=90) || (*end>=97 && *end<=122) || *end==95 || *end>=128) { + if(!end.forward_char()) + break; + } + auto word=get_buffer()->get_text(start, end); + std::vector words; + if(word.size()>0) { + auto correct = aspell_speller_check(spellcheck_checker, word.data(), word.bytes()); + if(correct==0) + get_buffer()->apply_tag_by_name("spellcheck_error", start, end); + else + get_buffer()->remove_tag_by_name("spellcheck_error", start, end); + } +} + + ///////////////////// //// GenericView //// ///////////////////// diff --git a/src/source.h b/src/source.h index 20185f9..9a8dd15 100644 --- a/src/source.h +++ b/src/source.h @@ -15,6 +15,7 @@ #include "selectiondialog.h" #include #include +#include namespace Source { Glib::RefPtr guess_language(const boost::filesystem::path &file_path); @@ -23,6 +24,7 @@ namespace Source { public: std::string style; std::string font; + std::string spellcheck_language; bool auto_tab_char_and_size; char default_tab_char; unsigned default_tab_size; @@ -91,6 +93,10 @@ namespace Source { GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; static void search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data); + + AspellCanHaveError *spellcheck_possible_err; + AspellSpeller *spellcheck_checker; + void spellcheck(Gtk::TextIter iter); }; // class View class GenericView : public View { From b9e4699cbf9f3e36d65ea4b8706b65c2d97ca387 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 11:52:23 +0200 Subject: [PATCH 47/60] Had to install aspell-en on MSYS2. --- docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index 12062d5..a5e650d 100644 --- a/docs/install.md +++ b/docs/install.md @@ -36,7 +36,7 @@ Please wait until the following TODOs are resolved: Install dependencies(replace [arch] with i686 or x86_64 depending on your MSYS2 install): ```sh -pacman -S patch autoconf automake-wrapper mingw-w64-[arch]-gtkmm3 mingw-w64-[arch]-boost mingw-w64-[arch]-aspell +pacman -S patch autoconf automake-wrapper mingw-w64-[arch]-gtkmm3 mingw-w64-[arch]-boost mingw-w64-[arch]-aspell mingw-w64-[arch]-aspell-en ``` Get juCi++ source: From 19e5bf5c36144646ee8afe6cf6644911dce290be Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 11:56:56 +0200 Subject: [PATCH 48/60] Guess Linux also needs aspell-en. --- docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index a5e650d..7764368 100644 --- a/docs/install.md +++ b/docs/install.md @@ -4,7 +4,7 @@ Before installation, please install libclangmm, see [installation guide](http:// ## Debian/Ubuntu ```sh -sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev libaspell-dev +sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev ``` ```sh git clone http://github.com/cppit/jucipp.git From d101ebcb470d70fc269f0ce9da774ca3cbad5c79 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 14:51:37 +0200 Subject: [PATCH 49/60] Added spellcheck suggestions through tooltips. --- src/source.cc | 319 +++++++++++++++++++++++++++---------------------- src/source.h | 22 ++-- src/tooltips.h | 4 +- 3 files changed, 190 insertions(+), 155 deletions(-) diff --git a/src/source.cc b/src/source.cc index 82168b0..7492c27 100644 --- a/src/source.cc +++ b/src/source.cc @@ -77,6 +77,60 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat if(Singleton::Config::source()->font.size()>0) override_font(Pango::FontDescription(Singleton::Config::source()->font)); + //Create tags for diagnostic warnings and errors: + auto scheme = get_source_buffer()->get_style_scheme(); + auto tag_table=get_buffer()->get_tag_table(); + auto style=scheme->get_style("def:warning"); + auto diagnostic_tag=get_source_buffer()->create_tag("def:warning"); + auto diagnostic_tag_underline=get_source_buffer()->create_tag("def:warning_underline"); + if(style && (style->property_foreground_set() || style->property_background_set())) { + Glib::ustring warning_property; + if(style->property_foreground_set()) { + warning_property=style->property_foreground().get_value(); + diagnostic_tag->property_foreground() = warning_property; + } + else if(style->property_background_set()) + warning_property=style->property_background().get_value(); + + diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR; + auto tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions: + auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); + if(param_spec!=NULL) { + diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(warning_property)); + } + } + style=scheme->get_style("def:error"); + diagnostic_tag=get_source_buffer()->create_tag("def:error"); + diagnostic_tag_underline=get_source_buffer()->create_tag("def:error_underline"); + if(style && (style->property_foreground_set() || style->property_background_set())) { + Glib::ustring error_property; + if(style->property_foreground_set()) { + error_property=style->property_foreground().get_value(); + diagnostic_tag->property_foreground() = error_property; + } + else if(style->property_background_set()) + error_property=style->property_background().get_value(); + + diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR; + auto tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions: + auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); + if(param_spec!=NULL) { + diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(error_property)); + } + } + //TODO: clear tag_class and param_spec? + + //Add tooltip foreground and background + style = scheme->get_style("def:note"); + auto note_tag=get_source_buffer()->create_tag("def:note_background"); + if(style->property_background_set()) { + note_tag->property_background()=style->property_background(); + } + note_tag=get_source_buffer()->create_tag("def:note"); + if(style->property_foreground_set()) { + note_tag->property_foreground()=style->property_foreground(); + } + 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) { @@ -137,6 +191,80 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat } }); } + + set_tooltip_events(); +} + +void Source::View::set_tooltip_events() { + signal_motion_notify_event().connect([this](GdkEventMotion* event) { + if(on_motion_last_x!=event->x || on_motion_last_y!=event->y) { + delayed_tooltips_connection.disconnect(); + if(event->state==0) { + gdouble x=event->x; + gdouble y=event->y; + delayed_tooltips_connection=Glib::signal_timeout().connect([this, x, y]() { + Tooltips::init(); + Gdk::Rectangle rectangle(x, y, 1, 1); + if(source_readable) { + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + spellcheck_tooltips.show(rectangle); + return false; + }, 100); + } + type_tooltips.hide(); + diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); + } + on_motion_last_x=event->x; + on_motion_last_y=event->y; + return false; + }); + + get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { + if(get_buffer()->get_has_selection() && mark->get_name()=="selection_bound") + delayed_tooltips_connection.disconnect(); + + if(mark->get_name()=="insert") { + delayed_tooltips_connection.disconnect(); + delayed_tooltips_connection=Glib::signal_timeout().connect([this]() { + Tooltips::init(); + Gdk::Rectangle rectangle; + get_iter_location(get_buffer()->get_insert()->get_iter(), rectangle); + int location_window_x, location_window_y; + buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_window_x, location_window_y); + rectangle.set_x(location_window_x-2); + rectangle.set_y(location_window_y); + rectangle.set_width(4); + if(source_readable) { + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + spellcheck_tooltips.show(rectangle); + return false; + }, 500); + type_tooltips.hide(); + diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); + } + }); + + signal_scroll_event().connect([this](GdkEventScroll* event) { + delayed_tooltips_connection.disconnect(); + type_tooltips.hide(); + diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); + return false; + }); + + signal_focus_out_event().connect([this](GdkEventFocus* event) { + delayed_tooltips_connection.disconnect(); + type_tooltips.hide(); + diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); + return false; + }); } void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data) { @@ -510,21 +638,47 @@ void Source::View::spellcheck(Gtk::TextIter iter) { auto start=iter; auto end=iter; - while((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter==95 || *iter>=128) { + while((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter>=128) { start=iter; if(!iter.backward_char()) break; } - while((*end>=48 && *end<=57) || (*end>=65 && *end<=90) || (*end>=97 && *end<=122) || *end==95 || *end>=128) { + while((*end>=48 && *end<=57) || (*end>=65 && *end<=90) || (*end>=97 && *end<=122) || *end>=128) { if(!end.forward_char()) break; } + for(auto it=spellcheck_tooltips.begin();it!=spellcheck_tooltips.end();it++) { + if(it->start_mark->get_iter()==start || it->start_mark->get_iter()==it->end_mark->get_iter()) + it=spellcheck_tooltips.erase(it); + } auto word=get_buffer()->get_text(start, end); std::vector words; if(word.size()>0) { auto correct = aspell_speller_check(spellcheck_checker, word.data(), word.bytes()); - if(correct==0) + if(correct==0) { get_buffer()->apply_tag_by_name("spellcheck_error", start, end); + + const AspellWordList *suggestions = aspell_speller_suggest(spellcheck_checker, word.data(), word.bytes()); + AspellStringEnumeration *elements = aspell_word_list_elements(suggestions); + + auto words=std::make_shared(); + const char *word; + while ((word = aspell_string_enumeration_next(elements))!= NULL) { + if(words->size()==0) + *words="Suggestions:"; + (*words)+=std::string("\n")+word; + } + delete_aspell_string_enumeration(elements); + + if(words->size()>0) { + auto create_tooltip_buffer=[this, words]() { + auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), *words, "def:note"); + return tooltip_buffer; + }; + spellcheck_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); + } + } else get_buffer()->remove_tag_by_name("spellcheck_error", start, end); } @@ -577,59 +731,7 @@ Source::View(file_path), project_path(project_path) { DEBUG("Style " + item.second + " not found in " + scheme->get_name()); } } - INFO("Tagtable filled"); - - //Create tags for diagnostic warnings and errors: - auto style=scheme->get_style("def:warning"); - auto diagnostic_tag=get_source_buffer()->create_tag("def:warning"); - auto diagnostic_tag_underline=get_source_buffer()->create_tag("def:warning_underline"); - if(style && (style->property_foreground_set() || style->property_background_set())) { - Glib::ustring warning_property; - if(style->property_foreground_set()) { - warning_property=style->property_foreground().get_value(); - diagnostic_tag->property_foreground() = warning_property; - } - else if(style->property_background_set()) - warning_property=style->property_background().get_value(); - - diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR; - auto tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions: - auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); - if(param_spec!=NULL) { - diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(warning_property)); - } - } - style=scheme->get_style("def:error"); - diagnostic_tag=get_source_buffer()->create_tag("def:error"); - diagnostic_tag_underline=get_source_buffer()->create_tag("def:error_underline"); - if(style && (style->property_foreground_set() || style->property_background_set())) { - Glib::ustring error_property; - if(style->property_foreground_set()) { - error_property=style->property_foreground().get_value(); - diagnostic_tag->property_foreground() = error_property; - } - else if(style->property_background_set()) - error_property=style->property_background().get_value(); - - diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR; - auto tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions: - auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); - if(param_spec!=NULL) { - diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(error_property)); - } - } - //TODO: clear tag_class and param_spec? - - //Add tooltip foreground and background - style = scheme->get_style("def:note"); - auto note_tag=get_source_buffer()->create_tag("def:note_background"); - if(style->property_background_set()) { - note_tag->property_background()=style->property_background(); - } - note_tag=get_source_buffer()->create_tag("def:note"); - if(style->property_foreground_set()) { - note_tag->property_foreground()=style->property_foreground(); - } + 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 @@ -649,7 +751,7 @@ Source::View(file_path), project_path(project_path) { update_syntax(); update_diagnostics(); update_types(); - clang_readable=true; + source_readable=true; set_status(""); parsing_mutex.unlock(); INFO("Syntax updated"); @@ -666,10 +768,9 @@ Source::View(file_path), project_path(project_path) { start_reparse(); type_tooltips.hide(); diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); }); - 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) *$"); @@ -678,8 +779,9 @@ Source::View(file_path), project_path(project_path) { void Source::ClangViewParse::init_parse() { type_tooltips.hide(); diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); get_buffer()->remove_all_tags(get_buffer()->begin(), get_buffer()->end()); - clang_readable=false; + source_readable=false; parse_thread_go=true; parse_thread_mapped=false; parse_thread_stop=false; @@ -743,10 +845,10 @@ std::map Source::ClangViewParse::get_buffer_map() cons void Source::ClangViewParse::start_reparse() { parse_thread_mapped=false; - clang_readable=false; + source_readable=false; delayed_reparse_connection.disconnect(); delayed_reparse_connection=Glib::signal_timeout().connect([this]() { - clang_readable=false; + source_readable=false; parse_thread_go=true; set_status("parsing..."); return false; @@ -915,70 +1017,6 @@ void Source::ClangViewParse::update_types() { } } -bool Source::ClangViewParse::on_motion_notify_event(GdkEventMotion* event) { - if(on_motion_last_x!=event->x || on_motion_last_y!=event->y) { - delayed_tooltips_connection.disconnect(); - if(event->state==0) { - gdouble x=event->x; - gdouble y=event->y; - delayed_tooltips_connection=Glib::signal_timeout().connect([this, x, y]() { - if(clang_readable) { - Gdk::Rectangle rectangle(x, y, 1, 1); - Tooltips::init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); - } - return false; - }, 100); - } - type_tooltips.hide(); - diagnostic_tooltips.hide(); - } - on_motion_last_x=event->x; - on_motion_last_y=event->y; - return Source::View::on_motion_notify_event(event); -} - -void Source::ClangViewParse::on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { - if(get_buffer()->get_has_selection() && mark->get_name()=="selection_bound") - delayed_tooltips_connection.disconnect(); - - if(mark->get_name()=="insert") { - delayed_tooltips_connection.disconnect(); - delayed_tooltips_connection=Glib::signal_timeout().connect([this]() { - if(clang_readable) { - Gdk::Rectangle rectangle; - get_iter_location(get_buffer()->get_insert()->get_iter(), rectangle); - int location_window_x, location_window_y; - buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_window_x, location_window_y); - rectangle.set_x(location_window_x-2); - rectangle.set_y(location_window_y); - rectangle.set_width(4); - Tooltips::init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); - } - return false; - }, 500); - type_tooltips.hide(); - diagnostic_tooltips.hide(); - } -} - -bool Source::ClangViewParse::on_focus_out_event(GdkEventFocus* event) { - delayed_tooltips_connection.disconnect(); - type_tooltips.hide(); - diagnostic_tooltips.hide(); - return Source::View::on_focus_out_event(event); -} - -bool Source::ClangViewParse::on_scroll_event(GdkEventScroll* event) { - delayed_tooltips_connection.disconnect(); - type_tooltips.hide(); - diagnostic_tooltips.hide(); - return Source::View::on_scroll_event(event); -} - //Clang indentation //TODO: replace indentation methods with a better implementation or maybe use libclang bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { @@ -1128,6 +1166,14 @@ Source::ClangViewParse(file_path, project_path), autocomplete_cancel_starting(fa return false; }, false); + signal_focus_out_event().connect([this](GdkEventFocus* event) { + autocomplete_cancel_starting=true; + if(completion_dialog_shown) { + completion_dialog->hide(); + } + + return false; + }); } bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { @@ -1139,15 +1185,6 @@ bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { return ClangViewParse::on_key_press_event(key); } -bool Source::ClangViewAutocomplete::on_focus_out_event(GdkEventFocus* event) { - autocomplete_cancel_starting=true; - if(completion_dialog_shown) { - completion_dialog->hide(); - } - - return Source::ClangViewParse::on_focus_out_event(event); -} - void Source::ClangViewAutocomplete::start_autocomplete() { if(!has_focus()) return; @@ -1333,7 +1370,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { }); get_token=[this]() -> std::string { - if(clang_readable) { + if(source_readable) { auto iter=get_buffer()->get_insert()->get_iter(); auto line=(unsigned)iter.get_line(); auto index=(unsigned)iter.get_line_index(); @@ -1351,7 +1388,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { }; get_token_name=[this]() -> std::string { - if(clang_readable) { + if(source_readable) { auto iter=get_buffer()->get_insert()->get_iter(); auto line=(unsigned)iter.get_line(); auto index=(unsigned)iter.get_line_index(); @@ -1367,7 +1404,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { }; tag_similar_tokens=[this](const std::string &usr){ - if(clang_readable) { + if(source_readable) { if(usr.size()>0 && last_similar_tokens_tagged!=usr) { get_buffer()->remove_tag(similar_tokens_tag, get_buffer()->begin(), get_buffer()->end()); auto offsets=clang_tokens->get_similar_token_offsets(usr); @@ -1385,7 +1422,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { rename_similar_tokens=[this](const std::string &usr, const std::string &text) { size_t number=0; - if(clang_readable) { + if(source_readable) { auto offsets=clang_tokens->get_similar_token_offsets(usr); std::vector, Glib::RefPtr > > marks; for(auto &offset: offsets) { @@ -1419,7 +1456,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { get_declaration_location=[this](){ std::pair location; - if(clang_readable) { + if(source_readable) { auto iter=get_buffer()->get_insert()->get_iter(); auto line=(unsigned)iter.get_line(); auto index=(unsigned)iter.get_line_index(); @@ -1440,7 +1477,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { }; goto_method=[this](){ - if(clang_readable) { + if(source_readable) { selection_dialog=std::unique_ptr(new SelectionDialog(*this, get_buffer()->create_mark(get_buffer()->get_insert()->get_iter()))); auto rows=std::make_shared >(); auto methods=clang_tokens->get_cxx_methods(); diff --git a/src/source.h b/src/source.h index 9a8dd15..8df142e 100644 --- a/src/source.h +++ b/src/source.h @@ -76,11 +76,20 @@ namespace Source { std::function on_update_status; std::string status; protected: + bool source_readable; + Tooltips diagnostic_tooltips; + Tooltips type_tooltips; + Tooltips spellcheck_tooltips; + gdouble on_motion_last_x; + gdouble on_motion_last_y; + sigc::connection delayed_tooltips_connection; + void set_tooltip_events(); + void set_status(const std::string &status); std::string get_line(size_t line_number); std::string get_line_before_insert(); - + bool on_key_press_event(GdkEventKey* key); bool on_button_press_event(GdkEventButton *event); @@ -112,13 +121,10 @@ namespace Source { protected: void init_parse(); bool on_key_press_event(GdkEventKey* key); - bool on_focus_out_event(GdkEventFocus* event); std::unique_ptr clang_tu; std::mutex parsing_mutex; std::unique_ptr clang_tokens; - bool clang_readable; sigc::connection delayed_reparse_connection; - sigc::connection delayed_tooltips_connection; std::shared_ptr parsing_in_progress; std::thread parse_thread; @@ -136,14 +142,7 @@ namespace Source { std::set last_syntax_tags; void update_diagnostics(); void update_types(); - Tooltips diagnostic_tooltips; - Tooltips type_tooltips; - bool on_motion_notify_event(GdkEventMotion* event); - gdouble on_motion_last_x; - gdouble on_motion_last_y; - void on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); - bool on_scroll_event(GdkEventScroll* event); static clang::Index clang_index; std::vector get_compilation_commands(); @@ -160,7 +159,6 @@ namespace Source { ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); protected: bool on_key_press_event(GdkEventKey* key); - bool on_focus_out_event(GdkEventFocus* event); std::thread autocomplete_thread; private: void start_autocomplete(); diff --git a/src/tooltips.h b/src/tooltips.h index 3d52c27..9330394 100644 --- a/src/tooltips.h +++ b/src/tooltips.h @@ -14,13 +14,13 @@ public: Gdk::Rectangle activation_rectangle; std::unique_ptr window; + Glib::RefPtr start_mark; + Glib::RefPtr end_mark; private: void wrap_lines(Glib::RefPtr text_buffer); std::function()> create_tooltip_buffer; std::unique_ptr tooltip_widget; - Glib::RefPtr start_mark; - Glib::RefPtr end_mark; Gtk::TextView& text_view; int tooltip_width, tooltip_height; }; From db0b67ceb7440cd749a7b2c8f98aa08849b7060c Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 15:13:10 +0200 Subject: [PATCH 50/60] Spellcheck suggestions now separated with ', ' instead of newline. --- src/source.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/source.cc b/src/source.cc index 7492c27..860c593 100644 --- a/src/source.cc +++ b/src/source.cc @@ -664,9 +664,12 @@ void Source::View::spellcheck(Gtk::TextIter iter) { auto words=std::make_shared(); const char *word; while ((word = aspell_string_enumeration_next(elements))!= NULL) { - if(words->size()==0) - *words="Suggestions:"; - (*words)+=std::string("\n")+word; + if(words->size()==0) { + *words="Suggestions:\n"; + (*words)+=word; + } + else + (*words)+=std::string(", ")+word; } delete_aspell_string_enumeration(elements); From cfc01bfe52329bdea05da84236485bcfa093fc6f Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 16:32:27 +0200 Subject: [PATCH 51/60] Added spell checking. --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 40ec707..cdd9210 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,14 @@ towards libclang with speed in mind. ## Features * Fast and responsive -* Syntax highlighing (even C++11/14, and 118 other file types) +* Syntax highlighing (even C++11/14, and more than 100 other file types) * C++ warnings and errors on the fly * Fast C++ autocomletion (even external libraries) * Tooltips showing type information and doxygen documentation * Accurate refactoring across files -* Basic editor functionallity * Highlighting of similar types +* Spell checking of comments and strings +* Basic editor functionallity * Write your own plugins in python (disabled at the moment) ## Dependencies ## @@ -24,7 +25,8 @@ towards libclang with speed in mind. * libboost-system-dev * libgtkmm-3.0-dev * libgtksourceview2.0-dev -* libgtksourceviewmm-3.0-dev +* libgtksourceviewmm-3.0-dev +* libaspell-dev * libclang-dev * [libclangmm](http://github.com/cppit/libclangmm/) From db6f5847624c8de04562351431d407c60be3f825 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 17:52:25 +0200 Subject: [PATCH 52/60] Fixed CMakeLists so that the CMAKE_INSTALL_PREFIX can be used (for making MSYS2 package for instance). --- CMakeLists.txt | 7 ----- .../{ => mingw-w64-gtksourceview3}/LICENSE | 0 .../mingw-w64-gtksourceviewmm3/LICENSE | 27 +++++++++++++++++++ docs/install.md | 2 +- src/CMakeLists.txt | 5 ++-- 5 files changed, 31 insertions(+), 10 deletions(-) rename MINGW-packages/{ => mingw-w64-gtksourceview3}/LICENSE (100%) create mode 100644 MINGW-packages/mingw-w64-gtksourceviewmm3/LICENSE diff --git a/CMakeLists.txt b/CMakeLists.txt index 045f920..f80481f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,13 +3,6 @@ cmake_minimum_required (VERSION 2.8.4) set(project_name juci) #set(module juci_to_python_api) -if(MSYS) - string(TOLOWER "/$ENV{MSYSTEM}" MSYS_PATH) - set(bin_install_path "${MSYS_PATH}/bin") -else() - set(bin_install_path "/usr/local/bin") -endif() - #set(lib_install_path "/usr/local/lib/python2.7/dist-packages/") project (${project_name}) diff --git a/MINGW-packages/LICENSE b/MINGW-packages/mingw-w64-gtksourceview3/LICENSE similarity index 100% rename from MINGW-packages/LICENSE rename to MINGW-packages/mingw-w64-gtksourceview3/LICENSE diff --git a/MINGW-packages/mingw-w64-gtksourceviewmm3/LICENSE b/MINGW-packages/mingw-w64-gtksourceviewmm3/LICENSE new file mode 100644 index 0000000..e0f07ba --- /dev/null +++ b/MINGW-packages/mingw-w64-gtksourceviewmm3/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013, Алексей +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/docs/install.md b/docs/install.md index 7764368..534a930 100644 --- a/docs/install.md +++ b/docs/install.md @@ -58,7 +58,7 @@ cd ../../ Compile and install juCi++ source: ```sh -cmake -G"MSYS Makefiles" . +cmake -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=/mingw[32 or 64] . make make install ``` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3dcada4..2d43bff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,8 +39,9 @@ validate(${LCL_FOUND} "clangmm" "clangmm" "clangmm") find_package(LibClang) validate(${LIBCLANG_FOUND} "clang" "libclang-dev" "llvm") +#TODO: till clang is fixed on MSYS2 ((lib)clang.dll.a is missing): if(MSYS) - set(LIBCLANG_LIBRARIES "${MSYS_PATH}/bin/clang.dll") + set(LIBCLANG_LIBRARIES "${CMAKE_INSTALL_PREFIX}/bin/clang.dll") endif() #find_package(PythonLibs 2.7) @@ -137,7 +138,7 @@ if(${validation}) # install(TARGETS ${project_name} ${module} install(TARGETS ${project_name} - RUNTIME DESTINATION ${bin_install_path} + RUNTIME DESTINATION bin # LIBRARY DESTINATION ${lib_install_path} ) endif(${validation}) From a78aef928afbb10111dfb90fed37221a84b848cf Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 29 Aug 2015 10:24:18 +0200 Subject: [PATCH 53/60] make install now works on Windows. --- docs/install.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index 534a930..8ddcac3 100644 --- a/docs/install.md +++ b/docs/install.md @@ -62,7 +62,6 @@ cmake -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=/mingw[32 or 64] . make make install ``` -**You might have to install juci manually**