From 4a83a004f4ccca11c479657ecd98ca6c6c550d1f Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 9 Aug 2015 14:12:06 +0200 Subject: [PATCH 01/22] Added run command, and kill process items in menu. Remember to delete ~/.juci. Also cleaned up use of std::string instead of boost::filesystem::path. --- src/cmake.cc | 8 ++++---- src/cmake.h | 2 +- src/directories.cc | 6 +++--- src/directories.h | 4 ++-- src/files.h | 8 +++++++- src/juci.cc | 6 +++++- src/notebook.cc | 47 ++++++++++++++++++++++------------------------ src/notebook.h | 3 +-- src/source.cc | 47 +++++++++++++++++++++++----------------------- src/source.h | 18 +++++++++--------- src/sourcefile.h | 2 ++ src/terminal.cc | 38 ++++++++++++++++++++++++------------- src/terminal.h | 11 ++++++----- src/window.cc | 42 ++++++++++++++++++++++++++++++----------- src/window.h | 1 + 15 files changed, 142 insertions(+), 101 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index 0d9fefc..d2ecfe6 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -40,14 +40,14 @@ CMake::CMake(const boost::filesystem::path &path) { } if(project_path!="") { if(boost::filesystem::exists(project_path.string()+"/CMakeLists.txt") && !boost::filesystem::exists(project_path.string()+"/compile_commands.json")) - create_compile_commands(project_path.string()); + create_compile_commands(project_path); } } -bool CMake::create_compile_commands(const std::string &path) { - Singleton::terminal()->print("Creating "+boost::filesystem::path(path+"/compile_commands.json").string()+"\n"); +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 2>&1", path)==EXIT_SUCCESS) + if(Singleton::terminal()->execute("cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==EXIT_SUCCESS) return true; return false; } diff --git a/src/cmake.h b/src/cmake.h index f300f15..8be9d13 100644 --- a/src/cmake.h +++ b/src/cmake.h @@ -8,7 +8,7 @@ class CMake { public: CMake(const boost::filesystem::path &path); std::vector > > get_functions_parameters(const std::string &name); - static bool create_compile_commands(const std::string &path); + static bool create_compile_commands(const boost::filesystem::path &path); std::vector paths; std::vector files; diff --git a/src/directories.cc b/src/directories.cc index 088a0f7..82d9dba 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -72,14 +72,14 @@ void Directories::open_folder(const boost::filesystem::path& dir_path) { current_path=new_path; - if(selected_path.size()>0) + if(selected_path!="") select_path(selected_path); DEBUG("Folder opened"); } -void Directories::select_path(const std::string &path) { +void Directories::select_path(const boost::filesystem::path &path) { tree_store->foreach_iter([this, &path](const Gtk::TreeModel::iterator& iter){ - if(iter->get_value(column_record.path)==path) { + if(iter->get_value(column_record.path)==path.string()) { auto tree_path=Gtk::TreePath(iter); tree_view.expand_to_path(tree_path); tree_view.set_cursor(tree_path); diff --git a/src/directories.h b/src/directories.h index 57d36da..d8dcb77 100644 --- a/src/directories.h +++ b/src/directories.h @@ -29,7 +29,7 @@ public: Directories(); void open_folder(const boost::filesystem::path& dir_path=""); - void select_path(const std::string &path); + void select_path(const boost::filesystem::path &path); std::function on_row_activated; std::unique_ptr cmake; @@ -41,7 +41,7 @@ private: Gtk::TreeView tree_view; Glib::RefPtr tree_store; ColumnRecord column_record; - std::string selected_path; + boost::filesystem::path selected_path; }; #endif // JUCI_DIRECTORIES_H_ diff --git a/src/files.h b/src/files.h index 14a3610..ee3bc53 100644 --- a/src/files.h +++ b/src/files.h @@ -53,7 +53,10 @@ const std::string configjson = " \"source_goto_method\": \"m\",\n" " \"source_rename\": \"r\",\n" " \"compile_and_run\": \"Return\",\n" -" \"compile\": \"Return\"\n" +" \"compile\": \"Return\",\n" +" \"run_command\": \"Return\",\n" +" \"kill_last_running\": \"Escape\",\n" +" \"force_kill_last_running\": \"Escape\"\n" " },\n" " \"directoryfilter\": {\n" " \"ignore\": [\n" @@ -103,6 +106,9 @@ const std::string menuxml = " \n" " \n" " \n" +" \n" +" \n" +" \n" " \n" " \n" " \n" diff --git a/src/juci.cc b/src/juci.cc index 83d8f14..4cdde32 100644 --- a/src/juci.cc +++ b/src/juci.cc @@ -1,5 +1,6 @@ #include "juci.h" #include "singletons.h" +#include void init_logging() { add_common_attributes(); @@ -18,13 +19,16 @@ int Juci::on_command_line(const Glib::RefPtr &cmd) ctx.parse(argc, argv); if(argc>=2) { for(int c=1;cfile_path) { + if(file_path==get_view(c)->file_path) { set_current_page(c); get_current_view()->grab_focus(); return; } } - std::ifstream can_read(path); + std::ifstream can_read(file_path.string()); if(!can_read) { - Singleton::terminal()->print("Error: could not open "+path+"\n"); + Singleton::terminal()->print("Error: could not open "+file_path.string()+"\n"); return; } can_read.close(); - auto language=Source::guess_language(path); + auto language=Source::guess_language(file_path); if(language && (language->get_id()=="chdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) { - std::string project_path; + boost::filesystem::path project_path; if(directories.cmake && directories.cmake->project_path!="") - project_path=directories.cmake->project_path.string(); + project_path=directories.cmake->project_path; else { - auto parent_path=boost::filesystem::path(path).parent_path(); - project_path=parent_path.string(); - CMake cmake(parent_path); + project_path=file_path.parent_path(); + CMake cmake(project_path); if(cmake.project_path!="") { - project_path=cmake.project_path.string(); - Singleton::terminal()->print("Project path for "+path+" set to "+project_path+"\n"); + project_path=cmake.project_path; + Singleton::terminal()->print("Project path for "+file_path.string()+" set to "+project_path.string()+"\n"); } else - Singleton::terminal()->print("Error: could not find project path for "+path+"\n"); + Singleton::terminal()->print("Error: could not find project path for "+file_path.string()+"\n"); } - source_views.emplace_back(new Source::ClangView(path, project_path)); + source_views.emplace_back(new Source::ClangView(file_path, project_path)); } else - source_views.emplace_back(new Source::GenericView(path, language)); + source_views.emplace_back(new Source::GenericView(file_path, language)); scrolled_windows.emplace_back(new Gtk::ScrolledWindow()); hboxes.emplace_back(new Gtk::HBox()); scrolled_windows.back()->add(*source_views.back()); hboxes.back()->pack_start(*scrolled_windows.back(), true, true); - boost::filesystem::path file_path(source_views.back()->file_path); std::string title=file_path.filename().string(); append_page(*hboxes.back(), title); show_all_children(); @@ -89,8 +87,7 @@ void Notebook::open(std::string path) { //Add star on tab label when the page is not saved: auto source_view=get_current_view(); get_current_view()->get_buffer()->signal_modified_changed().connect([this, source_view]() { - boost::filesystem::path file_path(source_view->file_path); - std::string title=file_path.filename().string(); + std::string title=source_view->file_path.filename().string(); if(source_view->get_buffer()->get_modified()) title+="*"; int page=-1; @@ -117,20 +114,20 @@ bool Notebook::save(int page) { if (view->file_path != "" && view->get_buffer()->get_modified()) { if(juci::filesystem::write(view->file_path, view->get_buffer())) { view->get_buffer()->set_modified(false); - Singleton::terminal()->print("File saved to: " +view->file_path+"\n"); + Singleton::terminal()->print("File saved to: " +view->file_path.string()+"\n"); //If CMakeLists.txt have been modified: //TODO: recreate cmake even without directories open? - if(boost::filesystem::path(view->file_path).filename().string()=="CMakeLists.txt") { - if(directories.cmake && directories.cmake->project_path!="" && boost::filesystem::path(view->file_path)>=directories.cmake->project_path && CMake::create_compile_commands(directories.cmake->project_path.string())) { + if(view->file_path.filename()=="CMakeLists.txt") { + if(directories.cmake && directories.cmake->project_path!="" && view->file_path>=directories.cmake->project_path && 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) { if(source_clang_view->restart_parse()) - Singleton::terminal()->print("Reparsing "+source_clang_view->file_path+"\n"); + Singleton::terminal()->async_print("Reparsing "+source_clang_view->file_path.string()+"\n"); else - Singleton::terminal()->print("Already reparsing "+source_clang_view->file_path+". Please reopen the file manually.\n"); + Singleton::terminal()->async_print("Already reparsing "+source_clang_view->file_path.string()+". Please reopen the file manually.\n"); } } } @@ -139,7 +136,7 @@ bool Notebook::save(int page) { return true; } - Singleton::terminal()->print("Error: could not save file " +view->file_path+"\n"); + Singleton::terminal()->print("Error: could not save file " +view->file_path.string()+"\n"); } return false; } @@ -177,7 +174,7 @@ bool Notebook::close_current_page() { bool Notebook::save_modified_dialog() { INFO("Notebook::save_modified_dialog"); Gtk::MessageDialog dialog((Gtk::Window&)(*get_toplevel()), "Save file!", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO); - dialog.set_secondary_text("Do you want to save: " + get_current_view()->file_path+" ?"); + dialog.set_secondary_text("Do you want to save: " + get_current_view()->file_path.string()+" ?"); int result = dialog.run(); if(result==Gtk::RESPONSE_YES) { save_current(); diff --git a/src/notebook.h b/src/notebook.h index 8ad8480..a77040f 100644 --- a/src/notebook.h +++ b/src/notebook.h @@ -17,12 +17,11 @@ public: int size(); Source::View* get_current_view(); bool close_current_page(); - void open(std::string filename); + void open(const boost::filesystem::path &file_path); bool save(int page); bool save_current(); private: - bool make_compile_commands(const std::string &path); bool save_modified_dialog(); Directories &directories; std::vector source_views; //Is NOT freed in destructor, this is intended for quick program exit. diff --git a/src/source.cc b/src/source.cc index 70df906..dc66986 100644 --- a/src/source.cc +++ b/src/source.cc @@ -15,18 +15,17 @@ namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE } -Glib::RefPtr Source::guess_language(const std::string &file_path) { +Glib::RefPtr Source::guess_language(const boost::filesystem::path &file_path) { auto language_manager=Gsv::LanguageManager::get_default(); bool result_uncertain = false; - auto content_type = Gio::content_type_guess(file_path, NULL, 0, result_uncertain); + auto content_type = Gio::content_type_guess(file_path.string(), NULL, 0, result_uncertain); if(result_uncertain) { content_type.clear(); } - auto language=language_manager->guess_language(file_path, content_type); + auto language=language_manager->guess_language(file_path.string(), content_type); if(!language) { - auto path=boost::filesystem::path(file_path); - auto filename=path.filename().string(); - auto extension=path.extension(); + auto filename=file_path.filename().string(); + auto extension=file_path.extension(); if(filename=="CMakeLists.txt") language=language_manager->get_language("cmake"); } @@ -36,7 +35,7 @@ Glib::RefPtr Source::guess_language(const std::string &file_path) ////////////// //// View //// ////////////// -Source::View::View(const std::string& file_path): file_path(file_path) { +Source::View::View(const boost::filesystem::path &file_path): file_path(file_path) { set_smart_home_end(Gsv::SMART_HOME_END_BEFORE); set_show_line_numbers(Singleton::Config::source()->show_line_numbers); set_highlight_current_line(Singleton::Config::source()->highlight_current_line); @@ -247,7 +246,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { ///////////////////// //// GenericView //// ///////////////////// -Source::GenericView::GenericView(const std::string& file_path, Glib::RefPtr language) : View(file_path) { +Source::GenericView::GenericView(const boost::filesystem::path &file_path, Glib::RefPtr language) : View(file_path) { auto style_scheme_manager=Gsv::StyleSchemeManager::get_default(); //TODO: add?: style_scheme_manager->prepend_search_path("~/.juci/"); auto scheme=style_scheme_manager->get_scheme("classic"); @@ -260,7 +259,7 @@ Source::GenericView::GenericView(const std::string& file_path, Glib::RefPtrset_language(language); - Singleton::terminal()->print("Language for file "+file_path+" set to "+language->get_name()+".\n"); + Singleton::terminal()->print("Language for file "+file_path.string()+" set to "+language->get_name()+".\n"); } auto completion=get_completion(); auto completion_words=Gsv::CompletionWords::create("", Glib::RefPtr()); @@ -276,7 +275,7 @@ Source::GenericView::GenericView(const std::string& file_path, Glib::RefPtrfont)); override_background_color(Gdk::RGBA(Singleton::Config::source()->background)); @@ -306,7 +305,7 @@ Source::View(file_path), project_path(project_path) { } //TODO: clear tag_class and param_spec? - parsing_in_progress=Singleton::terminal()->print_in_progress("Parsing "+file_path); + parsing_in_progress=Singleton::terminal()->print_in_progress("Parsing "+file_path.string()); //GTK-calls must happen in main thread, so the parse_thread //sends signals to the main thread that it is to call the following functions: parse_start.connect([this]{ @@ -360,7 +359,7 @@ void Source::ClangViewParse::init_parse() { int end_offset = get_source_buffer()->end().get_offset(); auto buffer_map=get_buffer_map(); //Remove includes for first parse for initial syntax highlighting - auto& str=buffer_map[file_path]; + auto& str=buffer_map[file_path.string()]; std::size_t pos=0; while((pos=str.find("#include", pos))!=std::string::npos) { auto start_pos=pos; @@ -408,15 +407,15 @@ init_syntax_highlighting(const std::map int end_offset) { std::vector arguments = get_compilation_commands(); clang_tu = std::unique_ptr(new clang::TranslationUnit(clang_index, - file_path, + file_path.string(), arguments, buffers)); - clang_tokens=clang_tu->get_tokens(0, buffers.find(file_path)->second.size()-1); + clang_tokens=clang_tu->get_tokens(0, buffers.find(file_path.string())->second.size()-1); } std::map Source::ClangViewParse::get_buffer_map() const { std::map buffer_map; - buffer_map[file_path]=get_source_buffer()->get_text().raw(); + buffer_map[file_path.string()]=get_source_buffer()->get_text().raw(); return buffer_map; } @@ -434,13 +433,13 @@ void Source::ClangViewParse::start_reparse() { int Source::ClangViewParse::reparse(const std::map &buffer) { int status = clang_tu->ReparseTranslationUnit(buffer); - clang_tokens=clang_tu->get_tokens(0, parse_thread_buffer_map.find(file_path)->second.size()-1); + clang_tokens=clang_tu->get_tokens(0, parse_thread_buffer_map.find(file_path.string())->second.size()-1); return status; } std::vector Source::ClangViewParse::get_compilation_commands() { - clang::CompilationDatabase db(project_path); - clang::CompileCommands commands(file_path, db); + clang::CompilationDatabase db(project_path.string()); + clang::CompileCommands commands(file_path.string(), db); std::vector cmds = commands.get_commands(); std::vector arguments; for (auto &i : cmds) { @@ -449,7 +448,7 @@ std::vector Source::ClangViewParse::get_compilation_commands() { arguments.emplace_back(lol[a]); } } - if(boost::filesystem::path(file_path).extension()==".h") //TODO: temporary fix for .h-files (parse as c++) + if(file_path.extension()==".h") //TODO: temporary fix for .h-files (parse as c++) arguments.emplace_back("-xc++"); return arguments; } @@ -496,7 +495,7 @@ void Source::ClangViewParse::update_diagnostics() { get_buffer()->remove_tag_by_name("diagnostic_error_underline", get_buffer()->begin(), get_buffer()->end()); auto diagnostics=clang_tu->get_diagnostics(); for(auto &diagnostic: diagnostics) { - if(diagnostic.path==file_path) { + if(diagnostic.path==file_path.string()) { auto start=get_buffer()->get_iter_at_offset(diagnostic.offsets.first); auto end=get_buffer()->get_iter_at_offset(diagnostic.offsets.second); std::string diagnostic_tag_name; @@ -701,7 +700,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { ////////////////////////////// //// ClangViewAutocomplete /// ////////////////////////////// -Source::ClangViewAutocomplete::ClangViewAutocomplete(const std::string& file_path, const std::string& project_path): +Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path): Source::ClangViewParse(file_path, project_path), autocomplete_cancel_starting(false) { get_buffer()->signal_changed().connect([this](){ if(completion_dialog_shown) @@ -862,7 +861,7 @@ void Source::ClangViewAutocomplete::autocomplete() { }); std::shared_ptr > buffer_map=std::make_shared >(); - auto& buffer=(*buffer_map)[this->file_path]; + auto& buffer=(*buffer_map)[this->file_path.string()]; buffer=get_buffer()->get_text(get_buffer()->begin(), get_buffer()->get_insert()->get_iter()); auto iter = get_source_buffer()->get_insert()->get_iter(); auto line_nr=iter.get_line()+1; @@ -921,7 +920,7 @@ get_autocomplete_suggestions(int line_number, int column, std::mapcreate_tag(); similar_tokens_tag->property_weight()=Pango::WEIGHT_BOLD; @@ -1053,7 +1052,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { }; } -Source::ClangView::ClangView(const std::string& file_path, const std::string& project_path): ClangViewRefactor(file_path, project_path) { +Source::ClangView::ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path): ClangViewRefactor(file_path, project_path) { do_delete_object.connect([this](){ if(delete_thread.joinable()) delete_thread.join(); diff --git a/src/source.h b/src/source.h index ed434cd..dba74ec 100644 --- a/src/source.h +++ b/src/source.h @@ -16,7 +16,7 @@ #include namespace Source { - Glib::RefPtr guess_language(const std::string &file_path); + Glib::RefPtr guess_language(const boost::filesystem::path &file_path); class Config { public: @@ -46,7 +46,7 @@ namespace Source { class View : public Gsv::View { public: - View(const std::string& file_path); + View(const boost::filesystem::path &file_path); ~View(); void search_highlight(const std::string &text, bool case_sensitive, bool regex); @@ -57,7 +57,7 @@ namespace Source { void replace_backward(const std::string &replacement); void replace_all(const std::string &replacement); - std::string file_path; + boost::filesystem::path file_path; std::function()> get_declaration_location; std::function goto_method; @@ -83,13 +83,13 @@ namespace Source { class GenericView : public View { public: - GenericView(const std::string& file_path, Glib::RefPtr language); + GenericView(const boost::filesystem::path &file_path, Glib::RefPtr language); }; class ClangViewParse : public View { public: - ClangViewParse(const std::string& file_path, const std::string& project_path); - std::string project_path; + ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); + boost::filesystem::path project_path; protected: void init_parse(); void start_reparse(); @@ -136,7 +136,7 @@ namespace Source { class ClangViewAutocomplete : public ClangViewParse { public: - ClangViewAutocomplete(const std::string& file_path, const std::string& project_path); + 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); @@ -158,7 +158,7 @@ namespace Source { class ClangViewRefactor : public ClangViewAutocomplete { public: - ClangViewRefactor(const std::string& file_path, const std::string& project_path); + ClangViewRefactor(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); private: Glib::RefPtr similar_tokens_tag; std::string last_similar_tokens_tagged; @@ -168,7 +168,7 @@ namespace Source { class ClangView : public ClangViewRefactor { public: - ClangView(const std::string& file_path, const std::string& project_path); + ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); void async_delete(); bool restart_parse(); private: diff --git a/src/sourcefile.h b/src/sourcefile.h index aabe617..d1ee608 100644 --- a/src/sourcefile.h +++ b/src/sourcefile.h @@ -11,6 +11,7 @@ namespace juci { static std::string read(const std::string &path); static std::string read(const boost::filesystem::path &path) { return read(path.string()); } static bool read(const std::string &path, Glib::RefPtr text_buffer); + static bool read(const boost::filesystem::path &path, Glib::RefPtr text_buffer) { return read(path.string(), text_buffer); } static std::vector read_lines(const std::string &path); static std::vector read_lines(const boost::filesystem::path &path) { return read_lines(path.string()); }; @@ -20,6 +21,7 @@ namespace juci { static bool write(const std::string &path) { return write(path, ""); }; static bool write(const boost::filesystem::path &path) { return write(path, ""); }; static bool write(const std::string &path, Glib::RefPtr text_buffer); + static bool write(const boost::filesystem::path &path, Glib::RefPtr text_buffer) { return write(path.string(), text_buffer); } }; } // namepace juci #endif // JUCI_SOURCEFILE_H_ diff --git a/src/terminal.cc b/src/terminal.cc index 50d6990..2641b0b 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -125,14 +125,11 @@ Terminal::Terminal() { }); } -int Terminal::execute(const std::string &command, const std::string &path) { - boost::filesystem::path boost_path; +int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { std::string cd_path_and_command; if(path!="") { - boost_path=boost::filesystem::path(path); - //TODO: Windows... - cd_path_and_command="cd "+boost_path.string()+" && "+command; + cd_path_and_command="cd "+path.string()+" && "+command; } else cd_path_and_command=command; @@ -179,15 +176,13 @@ int Terminal::execute(const std::string &command, const std::string &path) { } } -void Terminal::async_execute(const std::string &command, const std::string &path, std::function callback) { +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](){ - boost::filesystem::path boost_path; std::string cd_path_and_command; if(path!="") { - boost_path=boost::filesystem::path(path); //TODO: Windows... - cd_path_and_command="cd "+boost_path.string()+" && "+command; + cd_path_and_command="cd "+path.string()+" && "+command; } else cd_path_and_command=command; @@ -195,7 +190,7 @@ void Terminal::async_execute(const std::string &command, const std::string &path int stdin, stdout, stderr; async_execute_pids_mutex.lock(); auto pid=popen3(cd_path_and_command.c_str(), stdin, stdout, stderr); - async_execute_pids.emplace(pid); + async_execute_pids.emplace_back(pid); async_execute_pids_mutex.unlock(); if (pid<=0) { @@ -231,7 +226,12 @@ void Terminal::async_execute(const std::string &command, const std::string &path int exit_code; waitpid(pid, &exit_code, 0); async_execute_pids_mutex.lock(); - async_execute_pids.erase(pid); + for(auto it=async_execute_pids.begin();it!=async_execute_pids.end();it++) { + if(*it==pid) { + async_execute_pids.erase(it); + break; + } + } async_execute_pids_mutex.unlock(); close(stdin); close(stdout); @@ -244,10 +244,22 @@ void Terminal::async_execute(const std::string &command, const std::string &path async_execute_thread.detach(); } -void Terminal::kill_executing() { +void Terminal::kill_last_async_execute(bool force) { + async_execute_pids_mutex.lock(); + if(force) + kill(-async_execute_pids.back(), SIGTERM); + else + kill(-async_execute_pids.back(), SIGINT); + async_execute_pids_mutex.unlock(); +} + +void Terminal::kill_async_executes(bool force) { async_execute_pids_mutex.lock(); for(auto &pid: async_execute_pids) { - kill(-pid, SIGINT); + if(force) + kill(-pid, SIGTERM); + else + kill(-pid, SIGINT); } async_execute_pids_mutex.unlock(); } diff --git a/src/terminal.h b/src/terminal.h index 4559473..3b14de0 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include class Terminal : public Gtk::HBox { public: @@ -26,9 +26,10 @@ public: }; Terminal(); - int execute(const std::string &command, const std::string &path=""); - void async_execute(const std::string &command, const std::string &path="", std::function callback=nullptr); - void kill_executing(); + int execute(const std::string &command, const boost::filesystem::path &path=""); + void async_execute(const std::string &command, const boost::filesystem::path &path="", std::function callback=nullptr); + void kill_last_async_execute(bool force=false); + void kill_async_executes(bool force=false); int print(const std::string &message, bool bold=false); void print(int line_nr, const std::string &message, bool bold=false); @@ -44,7 +45,7 @@ private: Glib::RefPtr bold_tag; std::mutex async_execute_pids_mutex; - std::unordered_set async_execute_pids; + std::list async_execute_pids; }; #endif // JUCI_TERMINAL_H_ diff --git a/src/window.cc b/src/window.cc index 5f1ff4e..fb90243 100644 --- a/src/window.cc +++ b/src/window.cc @@ -204,24 +204,22 @@ void Window::create_menu() { CMake cmake(notebook.get_current_view()->file_path); directories.open_folder(); auto executables = cmake.get_functions_parameters("add_executable"); - std::string executable; boost::filesystem::path path; if(executables.size()>0 && executables[0].second.size()>0) { - executable=executables[0].second[0]; path=executables[0].first.parent_path(); path+="/"+executables[0].second[0]; } if(cmake.project_path!="") { if(path!="") { compiling=true; - Singleton::terminal()->print("Compiling and executing "+path.string()+"\n"); + Singleton::terminal()->print("Compiling and running "+path.string()+"\n"); //TODO: Windows... - Singleton::terminal()->async_execute("make", cmake.project_path.string(), [this, path](int exit_code){ + Singleton::terminal()->async_execute("make", cmake.project_path, [this, path](int exit_code){ compiling=false; if(exit_code==EXIT_SUCCESS) { compile_success(); //TODO: Windows... - Singleton::terminal()->async_execute(path.string(), path.parent_path().string(), [this, path](int exit_code){ + Singleton::terminal()->async_execute(path.string(), "", [this, path](int exit_code){ Singleton::terminal()->async_print(path.string()+" returned: "+std::to_string(exit_code)+'\n'); }); } @@ -240,13 +238,37 @@ void Window::create_menu() { compiling=true; Singleton::terminal()->print("Compiling project "+cmake.project_path.string()+"\n"); //TODO: Windows... - Singleton::terminal()->async_execute("make 2>&1", cmake.project_path.string(), [this](int exit_code){ + Singleton::terminal()->async_execute("make", cmake.project_path, [this](int exit_code){ compiling=false; if(exit_code==EXIT_SUCCESS) compile_success(); }); } }); + menu.action_group->add(Gtk::Action::create("ProjectRunCommand", "Run Command"), Gtk::AccelKey(menu.key_map["run_command"]), [this]() { + entry_box.clear(); + entry_box.entries.emplace_back(last_run_command, [this](const std::string& content){ + if(content!="") { + last_run_command=content; + Singleton::terminal()->async_print("Running: "+content+'\n'); + Singleton::terminal()->async_execute(content, directories.current_path, [this, content](int exit_code){ + Singleton::terminal()->async_print(content+" returned: "+std::to_string(exit_code)+'\n'); + }); + } + entry_box.hide(); + }); + auto entry_it=entry_box.entries.begin(); + entry_box.buttons.emplace_back("Run command", [this, entry_it](){ + entry_it->activate(); + }); + entry_box.show(); + }); + menu.action_group->add(Gtk::Action::create("ProjectKillLastRunning", "Kill Last Process"), Gtk::AccelKey(menu.key_map["kill_last_running"]), [this]() { + Singleton::terminal()->kill_last_async_execute(); + }); + menu.action_group->add(Gtk::Action::create("ProjectForceKillLastRunning", "Force Kill Last Process"), Gtk::AccelKey(menu.key_map["force_kill_last_running"]), [this]() { + 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]() { notebook.close_current_page(); @@ -258,8 +280,6 @@ void Window::create_menu() { bool Window::on_key_press_event(GdkEventKey *event) { if(event->keyval==GDK_KEY_Escape) { - if(entry_box.entries.size()==0) - Singleton::terminal()->kill_executing(); entry_box.hide(); } #ifdef __APPLE__ //For Apple's Command-left, right, up, down keys @@ -303,7 +323,7 @@ void Window::hide() { if(!notebook.close_current_page()) return; } - Singleton::terminal()->kill_executing(); + Singleton::terminal()->kill_async_executes(); Gtk::Window::hide(); } @@ -417,7 +437,7 @@ void Window::save_file_dialog() { if(directories.current_path!="") directories.open_folder(); notebook.open(path); - Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path+"\n"); + Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n"); } else Singleton::terminal()->print("Error saving file\n"); @@ -564,7 +584,7 @@ void Window::rename_token_entry() { if(notebook.get_view(c)->rename_similar_tokens) { auto number=notebook.get_view(c)->rename_similar_tokens(*token, content); if(number>0) { - Singleton::terminal()->print("Replaced "+std::to_string(number)+" occurrences in file "+notebook.get_view(c)->file_path+"\n"); + Singleton::terminal()->print("Replaced "+std::to_string(number)+" occurrences in file "+notebook.get_view(c)->file_path.string()+"\n"); notebook.save(c); } } diff --git a/src/window.h b/src/window.h index f14f731..c5c0e09 100644 --- a/src/window.h +++ b/src/window.h @@ -40,6 +40,7 @@ private: void rename_token_entry(); std::string last_search; std::string last_replace; + std::string last_run_command; bool case_sensitive_search=true; bool regex_search=false; bool search_entry_shown=false; From de23e8c8649364908de42410c06c490c884f857d Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 9 Aug 2015 18:57:58 +0200 Subject: [PATCH 02/22] Terminal now handles input, although only the most basic keys are handled. --- src/terminal.cc | 100 ++++++++++++++++++++++++++++++++---------------- src/terminal.h | 13 ++++--- src/window.cc | 3 +- src/window.h | 1 + 4 files changed, 77 insertions(+), 40 deletions(-) diff --git a/src/terminal.cc b/src/terminal.cc index 2641b0b..84787ab 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -102,17 +102,15 @@ void Terminal::InProgress::cancel(const std::string& msg) { } Terminal::Terminal() { - text_view.set_editable(false); - scrolled_window.add(text_view); - add(scrolled_window); + set_editable(false); - text_view.signal_size_allocate().connect([this](Gtk::Allocation& allocation){ - auto end=text_view.get_buffer()->create_mark(text_view.get_buffer()->end()); - text_view.scroll_to(end); - text_view.get_buffer()->delete_mark(end); + signal_size_allocate().connect([this](Gtk::Allocation& allocation){ + auto end=get_buffer()->create_mark(get_buffer()->end()); + scroll_to(end); + get_buffer()->delete_mark(end); }); - bold_tag=text_view.get_buffer()->create_tag(); + bold_tag=get_buffer()->create_tag(); bold_tag->property_weight()=PANGO_WEIGHT_BOLD; async_print_dispatcher.connect([this](){ async_print_strings_mutex.lock(); @@ -188,10 +186,11 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem cd_path_and_command=command; int stdin, stdout, stderr; - async_execute_pids_mutex.lock(); + async_executes_mutex.lock(); + stdin_buffer.clear(); auto pid=popen3(cd_path_and_command.c_str(), stdin, stdout, stderr); - async_execute_pids.emplace_back(pid); - async_execute_pids_mutex.unlock(); + async_executes.emplace_back(pid, stdin); + async_executes_mutex.unlock(); if (pid<=0) { async_print("Error: Failed to run command: " + command + "\n"); @@ -225,17 +224,18 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem int exit_code; waitpid(pid, &exit_code, 0); - async_execute_pids_mutex.lock(); - for(auto it=async_execute_pids.begin();it!=async_execute_pids.end();it++) { - if(*it==pid) { - async_execute_pids.erase(it); + async_executes_mutex.lock(); + for(auto it=async_executes.begin();it!=async_executes.end();it++) { + if(it->first==pid) { + async_executes.erase(it); break; } } - async_execute_pids_mutex.unlock(); + stdin_buffer.clear(); close(stdin); close(stdout); close(stderr); + async_executes_mutex.unlock(); if(callback) callback(exit_code); @@ -245,43 +245,45 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem } void Terminal::kill_last_async_execute(bool force) { - async_execute_pids_mutex.lock(); - if(force) - kill(-async_execute_pids.back(), SIGTERM); - else - kill(-async_execute_pids.back(), SIGINT); - async_execute_pids_mutex.unlock(); + 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_execute_pids_mutex.lock(); - for(auto &pid: async_execute_pids) { + async_executes_mutex.lock(); + for(auto &async_execute: async_executes) { if(force) - kill(-pid, SIGTERM); + kill(-async_execute.first, SIGTERM); else - kill(-pid, SIGINT); + kill(-async_execute.first, SIGINT); } - async_execute_pids_mutex.unlock(); + async_executes_mutex.unlock(); } int Terminal::print(const std::string &message, bool bold){ INFO("Terminal: PrintMessage"); if(bold) - text_view.get_buffer()->insert_with_tag(text_view.get_buffer()->end(), message, bold_tag); + get_buffer()->insert_with_tag(get_buffer()->end(), message, bold_tag); else - text_view.get_buffer()->insert(text_view.get_buffer()->end(), message); - return text_view.get_buffer()->end().get_line(); + get_buffer()->insert(get_buffer()->end(), message); + return get_buffer()->end().get_line(); } void Terminal::print(int line_nr, const std::string &message, bool bold){ INFO("Terminal: PrintMessage at line " << line_nr); - auto iter=text_view.get_buffer()->get_iter_at_line(line_nr); + auto iter=get_buffer()->get_iter_at_line(line_nr); while(!iter.ends_line()) iter++; if(bold) - text_view.get_buffer()->insert_with_tag(iter, message, bold_tag); + get_buffer()->insert_with_tag(iter, message, bold_tag); else - text_view.get_buffer()->insert(iter, message); + get_buffer()->insert(iter, message); } std::shared_ptr Terminal::print_in_progress(std::string start_msg) { @@ -299,3 +301,35 @@ void Terminal::async_print(const std::string &message, bool bold) { if(dispatch) async_print_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)); + stdin_buffer.clear(); + scroll_to(get_buffer()->get_insert()); + } + } + async_executes_mutex.unlock(); + return true; +} diff --git a/src/terminal.h b/src/terminal.h index 3b14de0..4e01852 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -9,7 +9,7 @@ #include #include -class Terminal : public Gtk::HBox { +class Terminal : public Gtk::TextView { public: class InProgress { public: @@ -35,17 +35,18 @@ public: void print(int line_nr, const std::string &message, bool bold=false); std::shared_ptr print_in_progress(std::string start_msg); void async_print(const std::string &message, bool bold=false); +protected: + bool on_key_press_event(GdkEventKey *event); private: - Gtk::TextView text_view; - Gtk::ScrolledWindow scrolled_window; - Glib::Dispatcher async_print_dispatcher; std::vector > async_print_strings; std::mutex async_print_strings_mutex; Glib::RefPtr bold_tag; - std::mutex async_execute_pids_mutex; - std::list async_execute_pids; + std::mutex async_executes_mutex; + std::list > async_executes; + + std::string stdin_buffer; }; #endif // JUCI_TERMINAL_H_ diff --git a/src/window.cc b/src/window.cc index fb90243..40d0628 100644 --- a/src/window.cc +++ b/src/window.cc @@ -32,7 +32,8 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil vpaned.set_position(300); vpaned.pack1(directory_and_notebook_panes, true, false); - terminal_vbox.pack_start(*Singleton::terminal()); + terminal_scrolled_window.add(*Singleton::terminal()); + terminal_vbox.pack_start(terminal_scrolled_window); status_hbox.pack_end(*Singleton::status(), Gtk::PACK_SHRINK); terminal_vbox.pack_end(status_hbox, Gtk::PACK_SHRINK); vpaned.pack2(terminal_vbox, true, true); diff --git a/src/window.h b/src/window.h index c5c0e09..1307b96 100644 --- a/src/window.h +++ b/src/window.h @@ -22,6 +22,7 @@ private: Gtk::Paned directory_and_notebook_panes; Gtk::VBox notebook_vbox; Gtk::VBox terminal_vbox; + Gtk::ScrolledWindow terminal_scrolled_window; Gtk::HBox status_hbox; EntryBox entry_box; Menu menu; From 7936941dfc675db93fb1185be8da1dee774d8136 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 9 Aug 2015 20:02:09 +0200 Subject: [PATCH 03/22] Fixed backspace indenting abit (for python especially), will rewrite some of the indenting in a day or two. --- src/source.cc | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/source.cc b/src/source.cc index dc66986..bcefc3e 100644 --- a/src/source.cc +++ b/src/source.cc @@ -224,17 +224,19 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { } //"Smart" backspace key else if(key->keyval==GDK_KEY_BackSpace && !get_buffer()->get_has_selection()) { - Gtk::TextIter insert_it=get_source_buffer()->get_insert()->get_iter(); + auto insert_it=get_source_buffer()->get_insert()->get_iter(); int line_nr=insert_it.get_line(); - if(line_nr>0) { + auto line_it=get_source_buffer()->get_iter_at_line(line_nr); + if(line_it!=insert_it) { string line=get_line(line_nr); - string previous_line=get_line(line_nr-1); smatch sm; - if(std::regex_match(previous_line, sm, spaces_regex)) { - if(line==sm[1] || line==(std::string(sm[1])+config->tab) || (line+config->tab==sm[1])) { - Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr); - get_source_buffer()->erase(line_it, insert_it); - } + if(std::regex_match(line, sm, spaces_regex) && sm[1].str().size()>=config->tab_size) { + auto insert_minus_tab_it=insert_it; + for(unsigned c=0;ctab_size;c++) + insert_minus_tab_it--; + get_source_buffer()->erase(insert_minus_tab_it, insert_it); + get_source_buffer()->end_user_action(); + return true; } } } @@ -692,6 +694,25 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { get_source_buffer()->end_user_action(); return Source::View::on_key_press_event(key); } + //"Smart" backspace key + else if(key->keyval==GDK_KEY_BackSpace && !get_buffer()->get_has_selection()) { + Gtk::TextIter insert_it=get_source_buffer()->get_insert()->get_iter(); + int line_nr=insert_it.get_line(); + if(line_nr>0) { + string line=get_line(line_nr); + string previous_line=get_line(line_nr-1); + smatch sm; + if(std::regex_match(previous_line, sm, spaces_regex)) { + if(line==sm[1] || line==(std::string(sm[1])+config->tab) || (line+config->tab==sm[1])) { + auto line_it = get_source_buffer()->get_iter_at_line(line_nr); + line_it--; + get_source_buffer()->erase(line_it, insert_it); + get_source_buffer()->end_user_action(); + return true; + } + } + } + } get_source_buffer()->end_user_action(); return Source::View::on_key_press_event(key); From e47bc94bea6dab201526cc753cef706ed91d23ab Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 9 Aug 2015 22:51:01 +0200 Subject: [PATCH 04/22] Indenting fix. --- src/source.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index bcefc3e..70c2ad2 100644 --- a/src/source.cc +++ b/src/source.cc @@ -227,7 +227,14 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { auto insert_it=get_source_buffer()->get_insert()->get_iter(); int line_nr=insert_it.get_line(); auto line_it=get_source_buffer()->get_iter_at_line(line_nr); - if(line_it!=insert_it) { + bool only_tabs_before_cursor=true; + for(auto it=line_it;it!=insert_it;it++) { + if(*it!=config->tab_char) { + only_tabs_before_cursor=false; + break; + } + } + if(only_tabs_before_cursor && line_it!=insert_it) { string line=get_line(line_nr); smatch sm; if(std::regex_match(line, sm, spaces_regex) && sm[1].str().size()>=config->tab_size) { From d07c5a92c43b47377a6bbd28802012a8696158cf Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 10 Aug 2015 10:31:15 +0200 Subject: [PATCH 05/22] Added TODO on how to get colors in terminal, for instance from cmake and make. --- src/terminal.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/terminal.cc b/src/terminal.cc index 84787ab..59262d2 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -45,6 +45,8 @@ pid_t popen3(const char *command, int &stdin, int &stdout, int &stderr) { dup2(p_stderr[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); perror("execl"); exit(EXIT_FAILURE); From 0d6633428c8e525a6ad4b4bd7d88357d2b414a87 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 11 Aug 2015 08:50:40 +0200 Subject: [PATCH 06/22] Slightly improved compile and run. --- src/window.cc | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/window.cc b/src/window.cc index 40d0628..bce688b 100644 --- a/src/window.cc +++ b/src/window.cc @@ -205,29 +205,33 @@ void Window::create_menu() { CMake cmake(notebook.get_current_view()->file_path); directories.open_folder(); auto executables = cmake.get_functions_parameters("add_executable"); - boost::filesystem::path path; + boost::filesystem::path executable_path; if(executables.size()>0 && executables[0].second.size()>0) { - path=executables[0].first.parent_path(); - path+="/"+executables[0].second[0]; + executable_path=executables[0].first.parent_path(); + executable_path+="/"+executables[0].second[0]; } if(cmake.project_path!="") { - if(path!="") { + if(executable_path!="") { compiling=true; - Singleton::terminal()->print("Compiling and running "+path.string()+"\n"); + Singleton::terminal()->print("Compiling and running "+executable_path.string()+"\n"); //TODO: Windows... - Singleton::terminal()->async_execute("make", cmake.project_path, [this, path](int exit_code){ + auto project_path=cmake.project_path; + Singleton::terminal()->async_execute("make", cmake.project_path, [this, executable_path, project_path](int exit_code){ compiling=false; if(exit_code==EXIT_SUCCESS) { compile_success(); //TODO: Windows... - Singleton::terminal()->async_execute(path.string(), "", [this, path](int exit_code){ - Singleton::terminal()->async_print(path.string()+" returned: "+std::to_string(exit_code)+'\n'); + Singleton::terminal()->async_execute(executable_path.string(), project_path, [this, executable_path](int exit_code){ + Singleton::terminal()->async_print(executable_path.string()+" returned: "+std::to_string(exit_code)+'\n'); }); } }); } - else - Singleton::terminal()->print("Could not find an executable, please use add_executable in CMakeLists.txt\n"); + else { + Singleton::terminal()->print("Could not find add_executable in the following paths:\n"); + for(auto &path: cmake.paths) + Singleton::terminal()->print(" "+path.string()+"\n"); + } } }); menu.action_group->add(Gtk::Action::create("ProjectCompile", "Compile"), Gtk::AccelKey(menu.key_map["compile"]), [this]() { From d0f61ecfbab2219776a3574cf3d2a97a82ab1b27 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 11 Aug 2015 09:57:52 +0200 Subject: [PATCH 07/22] Improved indenting. --- src/source.cc | 72 ++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/src/source.cc b/src/source.cc index 70c2ad2..6c595e5 100644 --- a/src/source.cc +++ b/src/source.cc @@ -161,14 +161,17 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { 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()) { - int line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); - string line(get_line_before_insert()); + 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((line_nr+1)get_line_count()) { + 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(std::regex_match(next_line, sm2, spaces_regex)) { + if(insert_it==line_end_iter && std::regex_match(next_line, sm2, spaces_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()); @@ -203,9 +206,14 @@ 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; for(int line_nr=line_start;line_nr<=line_end;line_nr++) { string line=get_line(line_nr); - if(!(line.size()>=config->tab_size && line.substr(0, config->tab_size)==config->tab)) { + std::smatch sm; + if(std::regex_match(line, sm, spaces_regex) && sm[1].str().size()>0) { + indent_left_steps=std::min(indent_left_steps, (unsigned)sm[1].str().size()); + } + else { get_source_buffer()->end_user_action(); return true; } @@ -215,7 +223,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr); Gtk::TextIter line_plus_it=line_it; - for(unsigned c=0;ctab_size;c++) + for(unsigned c=0;cerase(line_it, line_plus_it); } @@ -224,20 +232,27 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { } //"Smart" backspace key else if(key->keyval==GDK_KEY_BackSpace && !get_buffer()->get_has_selection()) { - auto insert_it=get_source_buffer()->get_insert()->get_iter(); + auto insert_it=get_buffer()->get_insert()->get_iter(); int line_nr=insert_it.get_line(); - auto line_it=get_source_buffer()->get_iter_at_line(line_nr); - bool only_tabs_before_cursor=true; - for(auto it=line_it;it!=insert_it;it++) { - if(*it!=config->tab_char) { - only_tabs_before_cursor=false; - break; + auto line=get_line_before_insert(); + std::smatch sm; + if(std::regex_match(line, sm, spaces_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(sm[1].str().size()==sm2[1].str().size() || sm[1].str().size()==sm2[1].str().size()+config->tab_size) { + auto previous_line_end_it=insert_it; + for(unsigned c=0;cerase(previous_line_end_it, insert_it); + get_source_buffer()->end_user_action(); + return true; + } + } } - } - if(only_tabs_before_cursor && line_it!=insert_it) { - string line=get_line(line_nr); - smatch sm; - if(std::regex_match(line, sm, spaces_regex) && sm[1].str().size()>=config->tab_size) { + if(line.size()>=config->tab_size) { auto insert_minus_tab_it=insert_it; for(unsigned c=0;ctab_size;c++) insert_minus_tab_it--; @@ -247,6 +262,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { } } } + bool stop=Gsv::View::on_key_press_event(key); get_source_buffer()->end_user_action(); return stop; @@ -636,7 +652,6 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { } } } - //TODO: insert without moving mark backwards. get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->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++) @@ -701,25 +716,6 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { get_source_buffer()->end_user_action(); return Source::View::on_key_press_event(key); } - //"Smart" backspace key - else if(key->keyval==GDK_KEY_BackSpace && !get_buffer()->get_has_selection()) { - Gtk::TextIter insert_it=get_source_buffer()->get_insert()->get_iter(); - int line_nr=insert_it.get_line(); - if(line_nr>0) { - string line=get_line(line_nr); - string previous_line=get_line(line_nr-1); - smatch sm; - if(std::regex_match(previous_line, sm, spaces_regex)) { - if(line==sm[1] || line==(std::string(sm[1])+config->tab) || (line+config->tab==sm[1])) { - auto line_it = get_source_buffer()->get_iter_at_line(line_nr); - line_it--; - get_source_buffer()->erase(line_it, insert_it); - get_source_buffer()->end_user_action(); - return true; - } - } - } - } get_source_buffer()->end_user_action(); return Source::View::on_key_press_event(key); From 046cabf51351075a5b05cafb589915f17b912b2b Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 11 Aug 2015 10:09:35 +0200 Subject: [PATCH 08/22] Again, improved indenting in preparation for more complex clang-indenting. --- src/source.cc | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/source.cc b/src/source.cc index 6c595e5..5d1bbab 100644 --- a/src/source.cc +++ b/src/source.cc @@ -241,9 +241,9 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { string previous_line=get_line(line_nr-1); std::smatch sm2; if(std::regex_match(previous_line, sm2, spaces_regex)) { - if(sm[1].str().size()==sm2[1].str().size() || sm[1].str().size()==sm2[1].str().size()+config->tab_size) { + 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) { auto previous_line_end_it=insert_it; - for(unsigned c=0;cerase(previous_line_end_it, insert_it); @@ -651,15 +651,23 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { return true; } } + if(next_line!=sm[1].str()+"}") { + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->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++) + insert_it--; + scroll_to(get_source_buffer()->get_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()+config->tab); + scroll_to(get_source_buffer()->get_insert()); + get_source_buffer()->end_user_action(); + return true; + } } - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->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++) - insert_it--; - scroll_to(get_source_buffer()->get_insert()); - get_source_buffer()->place_cursor(insert_it); - get_source_buffer()->end_user_action(); - return true; } else if(std::regex_match(line, sm, no_bracket_statement_regex)) { get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); From 10c67037e6c631c845d378d29be1b5c84f7ddc5d Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 11 Aug 2015 11:56:51 +0200 Subject: [PATCH 09/22] Abit smarter paste implemented. --- src/source.cc | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/source.h | 2 ++ src/window.cc | 2 +- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index 5d1bbab..5f98680 100644 --- a/src/source.cc +++ b/src/source.cc @@ -132,6 +132,55 @@ void Source::View::replace_all(const std::string &replacement) { gtk_source_search_context_replace_all(search_context, replacement.c_str(), replacement.size(), NULL); } +void Source::View::paste() { + Gtk::Clipboard::get()->request_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; + if(std::regex_match(line, sm, spaces_regex) && sm[2].str().size()==0) { + prefix=sm[1].str(); + + Glib::ustring::size_type start_line=0; + Glib::ustring::size_type end_line=0; + bool paste_line=false; + bool first_paste_line=true; + size_t tabs=0; + get_source_buffer()->begin_user_action(); + for(Glib::ustring::size_type c=0;ctab_char) + tabs++; + else + break; + } + get_buffer()->insert_at_cursor(text.substr(start_line+tabs, end_line-start_line-tabs)); + } + else + get_buffer()->insert_at_cursor("\n"+prefix+text.substr(start_line+tabs, end_line-start_line-tabs)); + start_line=end_line+1; + first_paste_line=false; + paste_line=false; + } + } + get_source_buffer()->end_user_action(); + } + else + get_buffer()->paste_clipboard(Gtk::Clipboard::get()); + }); +} + void Source::View::set_status(const std::string &status) { this->status=status; if(on_update_status) diff --git a/src/source.h b/src/source.h index dba74ec..5d0df3a 100644 --- a/src/source.h +++ b/src/source.h @@ -56,6 +56,8 @@ namespace Source { void replace_forward(const std::string &replacement); void replace_backward(const std::string &replacement); void replace_all(const std::string &replacement); + + void paste(); boost::filesystem::path file_path; diff --git a/src/window.cc b/src/window.cc index bce688b..cbdccfb 100644 --- a/src/window.cc +++ b/src/window.cc @@ -138,7 +138,7 @@ void Window::create_menu() { if(auto entry=dynamic_cast(widget)) entry->paste_clipboard(); else if(notebook.get_current_page()!=-1) - notebook.get_current_view()->get_buffer()->paste_clipboard(Gtk::Clipboard::get()); + notebook.get_current_view()->paste(); }); menu.action_group->add(Gtk::Action::create("EditFind", "Find"), Gtk::AccelKey(menu.key_map["edit_find"]), [this]() { search_and_replace_entry(); From 33f428e1d9a012b47ff7dc69127f68096e2069bb Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 11 Aug 2015 12:04:11 +0200 Subject: [PATCH 10/22] Minor fixes to smart paste. --- src/source.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/source.cc b/src/source.cc index 5f98680..9712118 100644 --- a/src/source.cc +++ b/src/source.cc @@ -174,6 +174,8 @@ void Source::View::paste() { paste_line=false; } } + get_buffer()->place_cursor(get_buffer()->get_insert()->get_iter()); + scroll_to(get_buffer()->get_insert()); get_source_buffer()->end_user_action(); } else From 3c718b52f6efcf59537444afea96fc22c60ef57a Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 11 Aug 2015 13:42:12 +0200 Subject: [PATCH 11/22] Fixed crash in smart paste. --- src/source.cc | 26 +++++++++++++++++++++----- src/window.cc | 2 +- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/source.cc b/src/source.cc index 9712118..bd19bb7 100644 --- a/src/source.cc +++ b/src/source.cc @@ -145,7 +145,7 @@ void Source::View::paste() { Glib::ustring::size_type end_line=0; bool paste_line=false; bool first_paste_line=true; - size_t tabs=0; + size_t first_paste_line_tabs=0; get_source_buffer()->begin_user_action(); for(Glib::ustring::size_type c=0;ctab_char) - tabs++; + first_paste_line_tabs++; else break; } - get_buffer()->insert_at_cursor(text.substr(start_line+tabs, end_line-start_line-tabs)); + get_buffer()->insert_at_cursor(text.substr(start_line+first_paste_line_tabs, end_line-start_line-first_paste_line_tabs)); + } + else { + std::string line=text.substr(start_line, end_line-start_line); + size_t paste_line_tabs=0; + for(auto chr: line) { + if(chr==Singleton::Config::source()->tab_char) + paste_line_tabs++; + else + break; + } + if(paste_line_tabs>=first_paste_line_tabs) + get_buffer()->insert_at_cursor("\n"+prefix+text.substr(start_line+first_paste_line_tabs, end_line-start_line-first_paste_line_tabs)); + else { + size_t tabs=0; + if(prefix.size()>(first_paste_line_tabs-paste_line_tabs)) + tabs=prefix.size()-(first_paste_line_tabs-paste_line_tabs); + get_buffer()->insert_at_cursor("\n"+prefix.substr(0, tabs)+text.substr(start_line+paste_line_tabs, end_line-start_line-paste_line_tabs)); + } } - else - get_buffer()->insert_at_cursor("\n"+prefix+text.substr(start_line+tabs, end_line-start_line-tabs)); start_line=end_line+1; first_paste_line=false; paste_line=false; diff --git a/src/window.cc b/src/window.cc index cbdccfb..5c14c1d 100644 --- a/src/window.cc +++ b/src/window.cc @@ -92,7 +92,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil compile_success.connect([this](){ directories.open_folder(); - }); + }); INFO("Window created"); } // Window constructor From 82b8c6ed742a5f71042c7cf22a0a04fe63497188 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 11 Aug 2015 21:07:36 +0200 Subject: [PATCH 12/22] Smart paste got smarter. --- src/source.cc | 81 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/src/source.cc b/src/source.cc index bd19bb7..8c7e322 100644 --- a/src/source.cc +++ b/src/source.cc @@ -137,17 +137,17 @@ void Source::View::paste() { const std::regex spaces_regex(std::string("^(")+Singleton::Config::source()->tab_char+"*)(.*)$"); auto line=get_line_before_insert(); std::smatch sm; - std::string prefix; + std::string prefix_tabs; if(std::regex_match(line, sm, spaces_regex) && sm[2].str().size()==0) { - prefix=sm[1].str(); - + prefix_tabs=sm[1].str(); + Glib::ustring::size_type start_line=0; Glib::ustring::size_type end_line=0; bool paste_line=false; bool first_paste_line=true; - size_t first_paste_line_tabs=0; - get_source_buffer()->begin_user_action(); - for(Glib::ustring::size_type c=0;ctab_char) + tabs++; + else + break; + } if(first_paste_line) { - std::string line=text.substr(start_line, end_line-start_line); - for(auto chr: line) { - if(chr==Singleton::Config::source()->tab_char) - first_paste_line_tabs++; - else - break; + if(tabs!=0) { + first_paste_line_has_tabs=true; + paste_line_tabs=tabs; } - get_buffer()->insert_at_cursor(text.substr(start_line+first_paste_line_tabs, end_line-start_line-first_paste_line_tabs)); + first_paste_line=false; } - else { - std::string line=text.substr(start_line, end_line-start_line); - size_t paste_line_tabs=0; - for(auto chr: line) { - if(chr==Singleton::Config::source()->tab_char) - paste_line_tabs++; - else - break; - } - if(paste_line_tabs>=first_paste_line_tabs) - get_buffer()->insert_at_cursor("\n"+prefix+text.substr(start_line+first_paste_line_tabs, end_line-start_line-first_paste_line_tabs)); - else { - size_t tabs=0; - if(prefix.size()>(first_paste_line_tabs-paste_line_tabs)) - tabs=prefix.size()-(first_paste_line_tabs-paste_line_tabs); - get_buffer()->insert_at_cursor("\n"+prefix.substr(0, tabs)+text.substr(start_line+paste_line_tabs, end_line-start_line-paste_line_tabs)); - } + else + paste_line_tabs=std::min(paste_line_tabs, tabs); + + start_line=end_line+1; + paste_line=false; + } + } + if(paste_line_tabs==(size_t)-1) + paste_line_tabs=0; + start_line=0; + end_line=0; + paste_line=false; + first_paste_line=true; + get_source_buffer()->begin_user_action(); + for(Glib::ustring::size_type c=0;cinsert_at_cursor(text.substr(start_line+paste_line_tabs, end_line-start_line-paste_line_tabs)); + else + get_buffer()->insert_at_cursor(text.substr(start_line, end_line-start_line)); + first_paste_line=false; } + else + get_buffer()->insert_at_cursor('\n'+prefix_tabs+text.substr(start_line+paste_line_tabs, end_line-start_line-paste_line_tabs)); start_line=end_line+1; - first_paste_line=false; paste_line=false; } } From 39004e79c4341e0c361e8543cc03f905e55e37dc Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 11 Aug 2015 22:34:21 +0200 Subject: [PATCH 13/22] Terminal should now scroll to end (unless user is already scrolling window). --- src/terminal.cc | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/terminal.cc b/src/terminal.cc index 59262d2..cfcbeb8 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -104,14 +104,6 @@ void Terminal::InProgress::cancel(const std::string& msg) { } Terminal::Terminal() { - set_editable(false); - - signal_size_allocate().connect([this](Gtk::Allocation& allocation){ - auto end=get_buffer()->create_mark(get_buffer()->end()); - scroll_to(end); - get_buffer()->delete_mark(end); - }); - bold_tag=get_buffer()->create_tag(); bold_tag->property_weight()=PANGO_WEIGHT_BOLD; async_print_dispatcher.connect([this](){ @@ -274,6 +266,15 @@ int Terminal::print(const std::string &message, bool bold){ get_buffer()->insert_with_tag(get_buffer()->end(), message, bold_tag); else get_buffer()->insert(get_buffer()->end(), message); + + auto iter=get_buffer()->get_insert()->get_iter(); + if(iter.backward_char()) { + while(gtk_events_pending()) + gtk_main_iteration(); + scroll_to(iter); + while(gtk_events_pending()) + gtk_main_iteration(); + } return get_buffer()->end().get_line(); } @@ -313,7 +314,11 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { if(unicode>=32 && unicode<=126) { stdin_buffer+=chr; get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); + while(gtk_events_pending()) + gtk_main_iteration(); scroll_to(get_buffer()->get_insert()); + while(gtk_events_pending()) + gtk_main_iteration(); } else if(event->keyval==GDK_KEY_BackSpace) { if(stdin_buffer.size()>0 && get_buffer()->get_char_count()>0) { @@ -321,15 +326,23 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { iter--; stdin_buffer.pop_back(); get_buffer()->erase(iter, get_buffer()->end()); + while(gtk_events_pending()) + gtk_main_iteration(); scroll_to(get_buffer()->get_insert()); + while(gtk_events_pending()) + gtk_main_iteration(); } } 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)); - stdin_buffer.clear(); + while(gtk_events_pending()) + gtk_main_iteration(); scroll_to(get_buffer()->get_insert()); + while(gtk_events_pending()) + gtk_main_iteration(); + stdin_buffer.clear(); } } async_executes_mutex.unlock(); From e234733dcea88a89e9c5b882b01655e2f4f2b1a8 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 12 Aug 2015 09:19:51 +0200 Subject: [PATCH 14/22] New C++ project implemented. Also some fixes to terminal. --- src/files.h | 3 +++ src/terminal.cc | 12 +++--------- src/window.cc | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/window.h | 1 + 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/files.h b/src/files.h index ee3bc53..8831802 100644 --- a/src/files.h +++ b/src/files.h @@ -79,6 +79,9 @@ const std::string menuxml = " \n" " \n" " \n" +" \n" +" \n" +" \n" " \n" " \n" " \n" diff --git a/src/terminal.cc b/src/terminal.cc index cfcbeb8..280c98b 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -269,11 +269,11 @@ int Terminal::print(const std::string &message, bool bold){ auto iter=get_buffer()->get_insert()->get_iter(); if(iter.backward_char()) { + auto mark=get_buffer()->create_mark(iter); + scroll_to(mark, 0.0, 1.0, 1.0); while(gtk_events_pending()) gtk_main_iteration(); - scroll_to(iter); - while(gtk_events_pending()) - gtk_main_iteration(); + get_buffer()->delete_mark(mark); } return get_buffer()->end().get_line(); } @@ -314,8 +314,6 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { if(unicode>=32 && unicode<=126) { stdin_buffer+=chr; get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); - while(gtk_events_pending()) - gtk_main_iteration(); scroll_to(get_buffer()->get_insert()); while(gtk_events_pending()) gtk_main_iteration(); @@ -326,8 +324,6 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { iter--; stdin_buffer.pop_back(); get_buffer()->erase(iter, get_buffer()->end()); - while(gtk_events_pending()) - gtk_main_iteration(); scroll_to(get_buffer()->get_insert()); while(gtk_events_pending()) gtk_main_iteration(); @@ -337,8 +333,6 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { 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)); - while(gtk_events_pending()) - gtk_main_iteration(); scroll_to(get_buffer()->get_insert()); while(gtk_events_pending()) gtk_main_iteration(); diff --git a/src/window.cc b/src/window.cc index 5c14c1d..d1e4175 100644 --- a/src/window.cc +++ b/src/window.cc @@ -105,6 +105,10 @@ void Window::create_menu() { 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("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]() { open_file_dialog(); }); @@ -363,6 +367,46 @@ void Window::new_file_entry() { entry_box.show(); } +void Window::new_cpp_project_dialog() { + Gtk::FileChooserDialog dialog("Please create and/or choose a 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.add_button("_Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("Select", Gtk::RESPONSE_OK); + + int result = dialog.run(); + + if(result==Gtk::RESPONSE_OK) { + boost::filesystem::path project_path=dialog.get_filename(); + auto project_name=project_path.filename().string(); + auto cmakelists_path=project_path; + cmakelists_path+="/CMakeLists.txt"; + auto cpp_main_path=project_path; + cpp_main_path+="/main.cpp"; + if(boost::filesystem::exists(cmakelists_path)) { + Singleton::terminal()->print("Error: "+cmakelists_path.string()+" already exists.\n"); + return; + } + if(boost::filesystem::exists(cpp_main_path)) { + Singleton::terminal()->print("Error: "+cpp_main_path.string()+" already exists.\n"); + return; + } + std::string cmakelists="cmake_minimum_required(VERSION 2.8)\n\nproject("+project_name+")\n\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++1y\")\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); + notebook.open(cpp_main_path); + Singleton::terminal()->print("C++ project "+project_name+" created.\n"); + } + else + Singleton::terminal()->print("Error: Could not create project "+project_path.string()+"\n"); + } +} + void Window::open_folder_dialog() { Gtk::FileChooserDialog dialog("Please choose a folder", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); if(directories.current_path!="") diff --git a/src/window.h b/src/window.h index 1307b96..8255aa7 100644 --- a/src/window.h +++ b/src/window.h @@ -32,6 +32,7 @@ private: void create_menu(); void hide(); void new_file_entry(); + void new_cpp_project_dialog(); void open_folder_dialog(); void open_file_dialog(); void save_file_dialog(); From 65cb9faec969155a74a8949b7c7c80df3798fc00 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Wed, 12 Aug 2015 12:34:34 +0200 Subject: [PATCH 15/22] Disabled plugins since it lead to a crash on Arch Linux. We most likely have to rewrite the plugin system. --- src/api.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api.cc b/src/api.cc index 0cf4d8c..be1381d 100644 --- a/src/api.cc +++ b/src/api.cc @@ -13,7 +13,7 @@ PluginApi::PluginApi(Notebook* notebook, Menu* menu) { this->menu = menu; DEBUG("Initiating plugins(from plugins.py).."); #ifndef __APPLE__ - InitPlugins(); //TODO: fix this + //InitPlugins(); //TODO: fix this #endif DEBUG("Plugins initiated.."); } From 43903361313b62cbfa362af8891410fd105f00c9 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Wed, 12 Aug 2015 12:40:02 +0200 Subject: [PATCH 16/22] Fixed scrolling issue when moving mark in terminal. --- src/terminal.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/terminal.cc b/src/terminal.cc index 280c98b..ada93d2 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -267,7 +267,7 @@ int Terminal::print(const std::string &message, bool bold){ else get_buffer()->insert(get_buffer()->end(), message); - auto iter=get_buffer()->get_insert()->get_iter(); + 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); From ee7da8476bcfaec4552c21efa02bfd4f49c74b65 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Wed, 12 Aug 2015 12:51:46 +0200 Subject: [PATCH 17/22] Can now run more than one Juci applications on Linux. --- src/juci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/juci.h b/src/juci.h index 4ce2cb2..21c4447 100644 --- a/src/juci.h +++ b/src/juci.h @@ -6,7 +6,7 @@ class Juci : public Gtk::Application { public: - Juci(): Gtk::Application("no.sout.juci", Gio::APPLICATION_HANDLES_COMMAND_LINE) {} + Juci(): Gtk::Application("no.sout.juci", Gio::APPLICATION_NON_UNIQUE | Gio::APPLICATION_HANDLES_COMMAND_LINE) {} int on_command_line(const Glib::RefPtr &cmd); void on_activate(); From 6ecc5ba16f8a723722622dfba3a0b25ff95b5922 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 12 Aug 2015 16:07:04 +0200 Subject: [PATCH 18/22] Added option to change the make command (for instance to use more processes with -j [number]). --- src/config.cc | 3 +++ src/files.h | 3 +++ src/singletons.cc | 1 + src/singletons.h | 2 ++ src/terminal.h | 5 +++++ src/window.cc | 4 ++-- 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/config.cc b/src/config.cc index c2bf32f..3cfc808 100644 --- a/src/config.cc +++ b/src/config.cc @@ -5,12 +5,15 @@ #include "files.h" #include "sourcefile.h" +//TODO: add try-catch to json-get and get_child MainConfig::MainConfig(Menu &menu) : menu(menu) { find_or_create_config_files(); boost::property_tree::json_parser::read_json(Singleton::config_dir() + "config.json", cfg); GenerateSource(); GenerateKeybindings(); GenerateDirectoryFilter(); + + Singleton::Config::terminal()->make_command=cfg.get("project.make_command"); } void MainConfig::find_or_create_config_files() { diff --git a/src/files.h b/src/files.h index 8831802..464811e 100644 --- a/src/files.h +++ b/src/files.h @@ -58,6 +58,9 @@ const std::string configjson = " \"kill_last_running\": \"Escape\",\n" " \"force_kill_last_running\": \"Escape\"\n" " },\n" +" \"project\": {\n" +" \"make_command\": \"make -j 2\"\n" +" },\n" " \"directoryfilter\": {\n" " \"ignore\": [\n" " \"cmake\",\n" diff --git a/src/singletons.cc b/src/singletons.cc index ace0668..94d1a03 100644 --- a/src/singletons.cc +++ b/src/singletons.cc @@ -2,6 +2,7 @@ std::unique_ptr Singleton::Config::source_=std::unique_ptr(new Source::Config()); std::unique_ptr Singleton::Config::directories_=std::unique_ptr(new Directories::Config()); +std::unique_ptr Singleton::Config::terminal_=std::unique_ptr(new Terminal::Config()); std::unique_ptr Singleton::terminal_=std::unique_ptr(); Terminal *Singleton::terminal() { diff --git a/src/singletons.h b/src/singletons.h index e39453c..2a09fc3 100644 --- a/src/singletons.h +++ b/src/singletons.h @@ -15,9 +15,11 @@ public: public: static Source::Config *source() {return source_.get();} static Directories::Config *directories() {return directories_.get();} + static Terminal::Config *terminal() {return terminal_.get();} private: static std::unique_ptr source_; static std::unique_ptr directories_; + static std::unique_ptr terminal_; }; static std::string config_dir() { return std::string(getenv("HOME")) + "/.juci/config/"; } static std::string log_dir() { return std::string(getenv("HOME")) + "/.juci/log/"; } diff --git a/src/terminal.h b/src/terminal.h index 4e01852..838cd0d 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -11,6 +11,11 @@ class Terminal : public Gtk::TextView { public: + class Config { + public: + std::string make_command; + }; + class InProgress { public: InProgress(const std::string& start_msg); diff --git a/src/window.cc b/src/window.cc index d1e4175..1f2dc13 100644 --- a/src/window.cc +++ b/src/window.cc @@ -220,7 +220,7 @@ void Window::create_menu() { Singleton::terminal()->print("Compiling and running "+executable_path.string()+"\n"); //TODO: Windows... auto project_path=cmake.project_path; - Singleton::terminal()->async_execute("make", cmake.project_path, [this, executable_path, project_path](int exit_code){ + 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(); @@ -247,7 +247,7 @@ void Window::create_menu() { compiling=true; Singleton::terminal()->print("Compiling project "+cmake.project_path.string()+"\n"); //TODO: Windows... - Singleton::terminal()->async_execute("make", cmake.project_path, [this](int exit_code){ + 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(); From d21a679f5d5242b066c6c7f374970fd4ef6d08e5 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 12 Aug 2015 16:08:03 +0200 Subject: [PATCH 19/22] Remvoed -j 2 from make_command, since my virtual box ran out of memory. --- src/files.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/files.h b/src/files.h index 464811e..4ac51f0 100644 --- a/src/files.h +++ b/src/files.h @@ -59,7 +59,7 @@ const std::string configjson = " \"force_kill_last_running\": \"Escape\"\n" " },\n" " \"project\": {\n" -" \"make_command\": \"make -j 2\"\n" +" \"make_command\": \"make\"\n" " },\n" " \"directoryfilter\": {\n" " \"ignore\": [\n" From ebfc1fa18ba53d1ef9c42619c367f107ca2b1ffa Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 12 Aug 2015 18:12:50 +0200 Subject: [PATCH 20/22] Hopefully working scroll to end in terminal. --- src/terminal.cc | 51 +++++++++++++++++++++++++++++++++---------------- src/terminal.h | 5 ++++- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/terminal.cc b/src/terminal.cc index ada93d2..9dddab0 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -65,7 +65,7 @@ pid_t popen3(const char *command, int &stdin, int &stdout, int &stderr) { Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) { waiting_print.connect([this](){ - Singleton::terminal()->print(line_nr-1, "."); + Singleton::terminal()->async_print(line_nr-1, "."); }); start(start_msg); } @@ -92,21 +92,39 @@ void Terminal::InProgress::start(const std::string& msg) { void Terminal::InProgress::done(const std::string& msg) { if(!stop) { stop=true; - Singleton::terminal()->print(line_nr-1, msg); + Singleton::terminal()->async_print(line_nr-1, msg); } } void Terminal::InProgress::cancel(const std::string& msg) { if(!stop) { stop=true; - Singleton::terminal()->print(line_nr-1, msg); + 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_on_line_strings_mutex.lock(); + if(async_print_on_line_strings.size()>0) { + for(auto &string: async_print_on_line_strings) + print(string.first, string.second); + async_print_on_line_strings.clear(); + } + async_print_on_line_strings_mutex.unlock(); + async_print_strings_mutex.lock(); if(async_print_strings.size()>0) { for(auto &string_bold: async_print_strings) @@ -271,22 +289,18 @@ int Terminal::print(const std::string &message, bool bold){ if(iter.backward_char()) { auto mark=get_buffer()->create_mark(iter); scroll_to(mark, 0.0, 1.0, 1.0); - while(gtk_events_pending()) - gtk_main_iteration(); get_buffer()->delete_mark(mark); } + return get_buffer()->end().get_line(); } -void Terminal::print(int line_nr, const std::string &message, bool bold){ +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++; - if(bold) - get_buffer()->insert_with_tag(iter, message, bold_tag); - else - get_buffer()->insert(iter, message); + get_buffer()->insert(iter, message); } std::shared_ptr Terminal::print_in_progress(std::string start_msg) { @@ -305,6 +319,17 @@ void Terminal::async_print(const std::string &message, bool bold) { 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_dispatcher(); +} + bool Terminal::on_key_press_event(GdkEventKey *event) { async_executes_mutex.lock(); if(async_executes.size()>0) { @@ -315,8 +340,6 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { stdin_buffer+=chr; get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); scroll_to(get_buffer()->get_insert()); - while(gtk_events_pending()) - gtk_main_iteration(); } else if(event->keyval==GDK_KEY_BackSpace) { if(stdin_buffer.size()>0 && get_buffer()->get_char_count()>0) { @@ -325,8 +348,6 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { stdin_buffer.pop_back(); get_buffer()->erase(iter, get_buffer()->end()); scroll_to(get_buffer()->get_insert()); - while(gtk_events_pending()) - gtk_main_iteration(); } } else if(event->keyval==GDK_KEY_Return) { @@ -334,8 +355,6 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { 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()); - while(gtk_events_pending()) - gtk_main_iteration(); stdin_buffer.clear(); } } diff --git a/src/terminal.h b/src/terminal.h index 838cd0d..6d7c86f 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -37,15 +37,18 @@ public: void kill_async_executes(bool force=false); int print(const std::string &message, bool bold=false); - void print(int line_nr, const std::string &message, bool bold=false); + void print(int line_nr, const std::string &message); std::shared_ptr print_in_progress(std::string start_msg); void async_print(const std::string &message, bool bold=false); + void async_print(int line_nr, const std::string &message); protected: bool on_key_press_event(GdkEventKey *event); private: Glib::Dispatcher async_print_dispatcher; std::vector > async_print_strings; + std::vector > async_print_on_line_strings; std::mutex async_print_strings_mutex; + std::mutex async_print_on_line_strings_mutex; Glib::RefPtr bold_tag; std::mutex async_executes_mutex; From c73a86f72875c47b62c3370f909e5de8db9481c4 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 12 Aug 2015 22:15:03 +0200 Subject: [PATCH 21/22] Finally fixed the scrolling issue in terminal. --- src/terminal.cc | 19 ++++++++++--------- src/terminal.h | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/terminal.cc b/src/terminal.cc index 9dddab0..bb0663c 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -117,14 +117,6 @@ Terminal::Terminal() { }); async_print_dispatcher.connect([this](){ - async_print_on_line_strings_mutex.lock(); - if(async_print_on_line_strings.size()>0) { - for(auto &string: async_print_on_line_strings) - print(string.first, string.second); - async_print_on_line_strings.clear(); - } - async_print_on_line_strings_mutex.unlock(); - async_print_strings_mutex.lock(); if(async_print_strings.size()>0) { for(auto &string_bold: async_print_strings) @@ -133,6 +125,15 @@ Terminal::Terminal() { } 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) { @@ -327,7 +328,7 @@ void Terminal::async_print(int line_nr, const std::string &message) { async_print_on_line_strings.emplace_back(line_nr, message); async_print_on_line_strings_mutex.unlock(); if(dispatch) - async_print_dispatcher(); + async_print_on_line_dispatcher(); } bool Terminal::on_key_press_event(GdkEventKey *event) { diff --git a/src/terminal.h b/src/terminal.h index 6d7c86f..5bdbe1a 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -45,6 +45,7 @@ protected: bool on_key_press_event(GdkEventKey *event); private: Glib::Dispatcher async_print_dispatcher; + Glib::Dispatcher async_print_on_line_dispatcher; std::vector > async_print_strings; std::vector > async_print_on_line_strings; std::mutex async_print_strings_mutex; From 54829505e73de045a0c82ff1538258e560fa8b7d Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 13 Aug 2015 08:05:19 +0200 Subject: [PATCH 22/22] Now handles UTF-8 files on OS X. --- src/sourcefile.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sourcefile.cc b/src/sourcefile.cc index 7fedbd1..b6f0786 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -65,7 +65,7 @@ bool juci::filesystem::write(const std::string &path, Glib::RefPtrget_text(start_iter, end_iter); + output << buffer->get_text(start_iter, end_iter).c_str(); start_iter=end_iter; } output.close();