diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 533baf8..e98ca99 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -84,6 +84,8 @@ set(source_files juci.h cmake.h cmake.cc dialogs.cc + project.h + project.cc ../libclangmm/src/CodeCompleteResults.cc ../libclangmm/src/CompilationDatabase.cc diff --git a/src/notebook.cc b/src/notebook.cc index 9e3b73f..2cdc2d4 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -354,6 +354,14 @@ boost::filesystem::path Notebook::get_current_folder() { return current_path; } +std::unique_ptr Notebook::get_project() { + boost::filesystem::path file_path; + if(get_current_page()!=-1) + file_path=get_current_view()->file_path; + + return std::unique_ptr(new ProjectClang(file_path)); +} + bool Notebook::save_modified_dialog(int page) { Gtk::MessageDialog dialog((Gtk::Window&)(*get_toplevel()), "Save file!", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO); dialog.set_default_response(Gtk::RESPONSE_YES); diff --git a/src/notebook.h b/src/notebook.h index 1b6f2d8..2c15ad5 100644 --- a/src/notebook.h +++ b/src/notebook.h @@ -5,6 +5,7 @@ #include "gtkmm.h" #include "source.h" #include "source_clang.h" +#include "project.h" #include #include #include @@ -30,6 +31,7 @@ public: void save_project_files(); void configure(int view_nr); boost::filesystem::path get_current_folder(); + std::unique_ptr get_project(); Gtk::Label info; Gtk::Label status; diff --git a/src/project.cc b/src/project.cc new file mode 100644 index 0000000..b14dbcd --- /dev/null +++ b/src/project.cc @@ -0,0 +1,113 @@ +#include "project.h" +#include "config.h" +#include "terminal.h" +#include "filesystem.h" + +std::unordered_map Project::run_arguments; +std::unordered_map Project::debug_run_arguments; +std::atomic Project::compiling(false); +std::atomic Project::debugging(false); + +std::unique_ptr ProjectClang::get_cmake() { + boost::filesystem::path path; + if(!file_path.empty()) + path=file_path.parent_path(); + else + path=Directories::get().current_path; + if(path.empty()) + return nullptr; + auto cmake=std::unique_ptr(new CMake(path)); + if(cmake->project_path.empty()) + return nullptr; + if(!CMake::create_default_build(cmake->project_path)) + return nullptr; + return cmake; +} + +std::pair ProjectClang::get_run_arguments() { + auto cmake=get_cmake(); + if(!cmake) + return {"", ""}; + + auto project_path=cmake->project_path.string(); + auto run_arguments_it=run_arguments.find(project_path); + std::string arguments; + if(run_arguments_it!=run_arguments.end()) + arguments=run_arguments_it->second; + + if(arguments.empty()) { + auto executable=cmake->get_executable(file_path).string(); + + if(executable!="") { + auto project_path=cmake->project_path; + auto default_build_path=CMake::get_default_build_path(project_path); + if(!default_build_path.empty()) { + size_t pos=executable.find(project_path.string()); + if(pos!=std::string::npos) + executable.replace(pos, project_path.string().size(), default_build_path.string()); + } + arguments=filesystem::escape_argument(executable); + } + else + arguments=filesystem::escape_argument(CMake::get_default_build_path(cmake->project_path)); + } + + return {project_path, arguments}; +} + +void ProjectClang::compile() { + auto cmake=get_cmake(); + if(!cmake) + return; + + auto default_build_path=CMake::get_default_build_path(cmake->project_path); + if(default_build_path.empty()) + return; + compiling=true; + Terminal::get().print("Compiling project "+cmake->project_path.string()+"\n"); + Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this](int exit_status) { + compiling=false; + }); +} + +void ProjectClang::compile_and_run() { + auto cmake=get_cmake(); + if(!cmake) + return; + auto project_path=cmake->project_path; + + auto default_build_path=CMake::get_default_build_path(project_path); + if(default_build_path.empty()) + return; + + auto run_arguments_it=run_arguments.find(project_path.string()); + std::string arguments; + if(run_arguments_it!=run_arguments.end()) + arguments=run_arguments_it->second; + + if(arguments.empty()) { + arguments=cmake->get_executable(file_path).string(); + if(arguments.empty()) { + Terminal::get().print("Could not find add_executable in the following paths:\n"); + for(auto &path: cmake->paths) + Terminal::get().print(" "+path.string()+"\n"); + Terminal::get().print("Solution: either use Project Set Run Arguments, or open a source file within a directory where add_executable is set.\n", true); + return; + } + size_t pos=arguments.find(project_path.string()); + if(pos!=std::string::npos) + arguments.replace(pos, project_path.string().size(), default_build_path.string()); + arguments=filesystem::escape_argument(arguments); + } + + compiling=true; + Terminal::get().print("Compiling and running "+arguments+"\n"); + Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this, arguments, default_build_path](int exit_status){ + compiling=false; + if(exit_status==EXIT_SUCCESS) { + Terminal::get().async_process(arguments, default_build_path, [this, arguments](int exit_status){ + Terminal::get().async_print(arguments+" returned: "+std::to_string(exit_status)+'\n'); + }); + } + }); +} diff --git a/src/project.h b/src/project.h new file mode 100644 index 0000000..872f0b5 --- /dev/null +++ b/src/project.h @@ -0,0 +1,50 @@ +#ifndef JUCI_PROJECT_H_ +#define JUCI_PROJECT_H_ + +#include "cmake.h" +#include +#include "directories.h" +#include + +class Project { +public: + Project(const boost::filesystem::path &file_path) : file_path(file_path) {} + virtual ~Project() {} + + boost::filesystem::path file_path; + + static std::unordered_map run_arguments; + static std::unordered_map debug_run_arguments; + static std::atomic compiling; + static std::atomic debugging; + + virtual std::pair get_run_arguments() {return {"", ""};} + virtual void compile() {} + virtual void compile_and_run() {} + + virtual std::pair debug_get_run_arguments() {return {"", ""};} + virtual void debug_start_continue() {} + virtual void debug_stop() {} + virtual void debug_kill() {} + virtual void debug_step_over() {} + virtual void debug_step_into() {} + virtual void debug_step_out() {} + virtual void debug_backtrace() {} + virtual void debug_show_variables() {} + virtual void debug_run_command() {} + virtual void debug_toggle_breakpoint() {} + virtual void debug_goto_stop() {} +}; + +class ProjectClang : public Project { +public: + ProjectClang(const boost::filesystem::path &file_path) : Project(file_path) {} + + std::unique_ptr get_cmake(); + + std::pair get_run_arguments() override; + void compile() override; + void compile_and_run() override; +}; + +#endif // JUCI_PROJECT_H_ diff --git a/src/window.cc b/src/window.cc index ad492d6..108ea41 100644 --- a/src/window.cc +++ b/src/window.cc @@ -591,33 +591,11 @@ void Window::set_menu_actions() { }); menu.add_action("project_set_run_arguments", [this]() { - auto cmake=get_cmake(); - if(!cmake) + project=notebook.get_project(); + auto run_arguments=std::make_shared >(project->get_run_arguments()); + if(run_arguments->second.empty()) return; - auto project_path=std::make_shared(cmake->project_path); - auto run_arguments_it=project_run_arguments.find(project_path->string()); - std::string run_arguments; - if(run_arguments_it!=project_run_arguments.end()) - run_arguments=run_arguments_it->second; - - if(run_arguments.empty()) { - auto executable=cmake->get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:"").string(); - - if(executable!="") { - auto project_path=cmake->project_path; - auto default_build_path=CMake::get_default_build_path(project_path); - if(!default_build_path.empty()) { - size_t pos=executable.find(project_path.string()); - if(pos!=std::string::npos) - executable.replace(pos, project_path.string().size(), default_build_path.string()); - } - run_arguments=filesystem::escape_argument(executable); - } - else - run_arguments=filesystem::escape_argument(CMake::get_default_build_path(cmake->project_path)); - } - entry_box.clear(); entry_box.labels.emplace_back(); auto label_it=entry_box.labels.begin(); @@ -625,8 +603,8 @@ void Window::set_menu_actions() { label_it->set_text("Set empty to let juCi++ deduce executable"); }; label_it->update(0, ""); - entry_box.entries.emplace_back(run_arguments, [this, project_path](const std::string& content){ - project_run_arguments[project_path->string()]=content; + entry_box.entries.emplace_back(run_arguments->second, [this, run_arguments](const std::string& content){ + Project::run_arguments[run_arguments->first]=content; entry_box.hide(); }, 50); auto entry_it=entry_box.entries.begin(); @@ -637,75 +615,24 @@ void Window::set_menu_actions() { entry_box.show(); }); menu.add_action("compile_and_run", [this]() { - if(compiling) + if(Project::compiling) return; if(Config::get().window.save_on_compile_or_run) notebook.save_project_files(); - - auto cmake=get_cmake(); - if(!cmake) - return; - auto project_path=cmake->project_path; - - auto default_build_path=CMake::get_default_build_path(project_path); - if(default_build_path.empty()) - return; - - auto run_arguments_it=project_run_arguments.find(project_path.string()); - std::string run_arguments; - if(run_arguments_it!=project_run_arguments.end()) - run_arguments=run_arguments_it->second; - - std::string command; - if(!run_arguments.empty()) { - command=run_arguments; - } - else { - command=cmake->get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:"").string(); - if(command.empty()) { - Terminal::get().print("Could not find add_executable in the following paths:\n"); - for(auto &path: cmake->paths) - Terminal::get().print(" "+path.string()+"\n"); - Terminal::get().print("Solution: either use Project Set Run Arguments, or open a source file within a directory where add_executable is set.\n", true); - return; - } - size_t pos=command.find(project_path.string()); - if(pos!=std::string::npos) - command.replace(pos, project_path.string().size(), default_build_path.string()); - command=filesystem::escape_argument(command); - } - - compiling=true; - Terminal::get().print("Compiling and running "+command+"\n"); - Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this, command, default_build_path](int exit_status){ - compiling=false; - if(exit_status==EXIT_SUCCESS) { - Terminal::get().async_process(command, default_build_path, [this, command](int exit_status){ - Terminal::get().async_print(command+" returned: "+std::to_string(exit_status)+'\n'); - }); - } - }); + + project=notebook.get_project(); + project->compile_and_run(); }); menu.add_action("compile", [this]() { - if(compiling) + if(Project::compiling) return; if(Config::get().window.save_on_compile_or_run) notebook.save_project_files(); - - auto cmake=get_cmake(); - if(!cmake) - return; - - auto default_build_path=CMake::get_default_build_path(cmake->project_path); - if(default_build_path.empty()) - return; - compiling=true; - Terminal::get().print("Compiling project "+cmake->project_path.string()+"\n"); - Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this](int exit_status){ - compiling=false; - }); + + project=notebook.get_project(); + project->compile(); }); menu.add_action("run_command", [this]() { diff --git a/src/window.h b/src/window.h index a3485a2..a23ad39 100644 --- a/src/window.h +++ b/src/window.h @@ -6,6 +6,7 @@ #include "notebook.h" #include "cmake.h" #include "tooltips.h" +#include "project.h" #include class Window : public Gtk::ApplicationWindow { @@ -34,6 +35,8 @@ private: Gtk::AboutDialog about; EntryBox entry_box; + std::unique_ptr project; + std::atomic compiling; std::atomic debugging;