diff --git a/src/directories.cpp b/src/directories.cpp index d048a75..db36901 100644 --- a/src/directories.cpp +++ b/src/directories.cpp @@ -1,7 +1,10 @@ #include "directories.hpp" +#include "config.hpp" #include "entrybox.hpp" #include "filesystem.hpp" +#include "info.hpp" #include "notebook.hpp" +#include "project.hpp" #include "source.hpp" #include "terminal.hpp" #include "utility.hpp" @@ -144,9 +147,25 @@ Directories::Directories() : Gtk::ListViewText(1) { if(iter) { auto filesystem_path = iter->get_value(column_record.path); if(filesystem_path != "") { + GdkModifierType state; boost::system::error_code ec; if(boost::filesystem::is_directory(boost::filesystem::path(filesystem_path), ec)) row_expanded(path) ? collapse_row(path) : expand_row(path, false); + else if(gtk_get_current_event_state(&state) && (state & (GDK_CONTROL_MASK | GDK_MOD2_MASK))) { + if(Project::compiling || Project::debugging) { + Info::get().print("Compile or debug in progress"); + return; + } + + Project::current = Project::create(filesystem_path); + + if(Config::get().project.save_on_compile_or_run) + Project::save_files(!Project::current->build->project_path.empty() ? Project::current->build->project_path : filesystem_path.parent_path()); + + Project::current->compile_and_run(filesystem_path); + + set_cursor(path); + } else Notebook::get().open(filesystem_path); } diff --git a/src/project.cpp b/src/project.cpp index ed780fd..3c77ccb 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -167,22 +167,31 @@ void Project::debug_update_stop() { } } -std::shared_ptr Project::create() { +std::shared_ptr Project::create(const boost::filesystem::path &file_path) { std::unique_ptr build; - - if(auto view = Notebook::get().get_current_view()) { + std::string language_id; + if(!file_path.empty()) { + build = Build::create(file_path); + if(auto language = Source::guess_language(file_path)) + language_id = language->get_id(); + } + else if(auto view = Notebook::get().get_current_view()) { build = Build::create(view->file_path); - if(view->language_id == "markdown") + language_id = view->language_id; + } + + if(build) { + if(language_id == "markdown") return std::shared_ptr(new Project::Markdown(std::move(build))); - if(view->language_id == "js") + if(language_id == "js") return std::shared_ptr(new Project::JavaScript(std::move(build))); - if(view->language_id == "python") + if(language_id == "python") return std::shared_ptr(new Project::Python(std::move(build))); - if(view->language_id == "html") + if(language_id == "html") return std::shared_ptr(new Project::HTML(std::move(build))); - if(view->language_id == "go") + if(language_id == "go") return std::shared_ptr(new Project::Go(std::move(build))); - if(view->language_id == "julia") + if(language_id == "julia") return std::shared_ptr(new Project::Julia(std::move(build))); } else @@ -210,7 +219,7 @@ void Project::Base::compile() { Info::get().print("Could not find a supported project"); } -void Project::Base::compile_and_run() { +void Project::Base::compile_and_run(const boost::filesystem::path &file_path) { Info::get().print("Could not find a supported project"); } @@ -727,7 +736,7 @@ void Project::Clang::compile() { }); } -void Project::Clang::compile_and_run() { +void Project::Clang::compile_and_run(const boost::filesystem::path &file_path) { auto default_build_path = build->get_default_path(); if(default_build_path.empty() || !build->update_default()) return; @@ -740,8 +749,13 @@ void Project::Clang::compile_and_run() { arguments = run_arguments_it->second; if(arguments.empty()) { - auto view = Notebook::get().get_current_view(); - auto executable = build->get_executable(view ? view->file_path : Directories::get().path); + boost::filesystem::path executable; + if(!file_path.empty()) + executable = build->get_executable(file_path); + else { + auto view = Notebook::get().get_current_view(); + executable = build->get_executable(view ? view->file_path : Directories::get().path); + } if(executable.empty()) { if(!build->is_valid(default_build_path)) Terminal::get().print("\e[31mError\e[m: build folder no longer valid, please use Recreate Build in the Project menu.\n", true); @@ -844,25 +858,34 @@ void Project::Clang::recreate_build() { } -void Project::Markdown::compile_and_run() { - if(auto view = Notebook::get().get_current_view()) { - auto command = Config::get().project.markdown_command + ' ' + filesystem::escape_argument(filesystem::get_short_path(view->file_path).string()); - Terminal::get().async_process( - command, "", [command](int exit_status) { - if(exit_status == 127) - Terminal::get().print("\e[31mError\e[m: executable not found: " + command + "\n", true); - }, - true); - } +void Project::Markdown::compile_and_run(const boost::filesystem::path &file_path) { + std::string command; + if(!file_path.empty()) + command = Config::get().project.markdown_command + ' ' + filesystem::escape_argument(filesystem::get_short_path(file_path).string()); + else if(auto view = Notebook::get().get_current_view()) + command = Config::get().project.markdown_command + ' ' + filesystem::escape_argument(filesystem::get_short_path(view->file_path).string()); + else + return; + + Terminal::get().async_process( + command, "", [command](int exit_status) { + if(exit_status == 127) + Terminal::get().print("\e[31mError\e[m: executable not found: " + command + "\n", true); + }, + true); } -void Project::Python::compile_and_run() { +void Project::Python::compile_and_run(const boost::filesystem::path &file_path) { std::string command = Config::get().project.python_command + ' '; boost::filesystem::path path; if(dynamic_cast(build.get())) { command += filesystem::get_short_path(build->project_path).string(); path = build->project_path; } + else if(!file_path.empty()) { + command += filesystem::escape_argument(filesystem::get_short_path(file_path).string()); + path = file_path.parent_path(); + } else if(auto view = Notebook::get().get_current_view()) { command += filesystem::escape_argument(filesystem::get_short_path(view->file_path).string()); path = view->file_path.parent_path(); @@ -879,13 +902,17 @@ void Project::Python::compile_and_run() { }); } -void Project::JavaScript::compile_and_run() { +void Project::JavaScript::compile_and_run(const boost::filesystem::path &file_path) { std::string command; boost::filesystem::path path; if(dynamic_cast(build.get())) { command = "npm start"; path = build->project_path; } + else if(!file_path.empty()) { + command = "node " + filesystem::escape_argument(filesystem::get_short_path(file_path).string()); + path = file_path.parent_path(); + } else if(auto view = Notebook::get().get_current_view()) { command = "node " + filesystem::escape_argument(filesystem::get_short_path(view->file_path).string()); path = view->file_path.parent_path(); @@ -902,7 +929,7 @@ void Project::JavaScript::compile_and_run() { }); } -void Project::HTML::compile_and_run() { +void Project::HTML::compile_and_run(const boost::filesystem::path &file_path) { if(dynamic_cast(build.get())) { std::string command = "npm start"; @@ -914,6 +941,8 @@ void Project::HTML::compile_and_run() { Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); }); } + else if(!file_path.empty()) + Notebook::get().open_uri(std::string("file://") + file_path.string()); else if(auto view = Notebook::get().get_current_view()) Notebook::get().open_uri(std::string("file://") + view->file_path.string()); } @@ -944,7 +973,7 @@ void Project::Rust::compile() { }); } -void Project::Rust::compile_and_run() { +void Project::Rust::compile_and_run(const boost::filesystem::path &file_path) { compiling = true; if(Config::get().terminal.clear_on_compile) @@ -964,13 +993,17 @@ void Project::Rust::compile_and_run() { }); } -void Project::Go::compile_and_run() { +void Project::Go::compile_and_run(const boost::filesystem::path &file_path) { std::string command; boost::filesystem::path path; if(dynamic_cast(build.get())) { command = "go run ."; path = build->project_path; } + else if(!file_path.empty()) { + command = "go run " + filesystem::escape_argument(filesystem::get_short_path(file_path).string()); + path = file_path.parent_path(); + } else if(auto view = Notebook::get().get_current_view()) { command = "go run " + filesystem::escape_argument(filesystem::get_short_path(view->file_path).string()); path = view->file_path.parent_path(); @@ -987,17 +1020,25 @@ void Project::Go::compile_and_run() { }); } -void Project::Julia::compile_and_run() { +void Project::Julia::compile_and_run(const boost::filesystem::path &file_path) { + std::string command; + boost::filesystem::path path; + if(!file_path.empty()) { + command = "julia " + filesystem::escape_argument(filesystem::get_short_path(file_path).string()); + path = file_path.parent_path(); + } if(auto view = Notebook::get().get_current_view()) { - auto command = "julia " + filesystem::escape_argument(filesystem::get_short_path(Notebook::get().get_current_view()->file_path).string()); - auto path = view->file_path.parent_path(); + command = "julia " + filesystem::escape_argument(filesystem::get_short_path(view->file_path).string()); + path = view->file_path.parent_path(); + } + else + return; - if(Config::get().terminal.clear_on_compile) - Terminal::get().clear(); + if(Config::get().terminal.clear_on_compile) + Terminal::get().clear(); - Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); - Terminal::get().async_process(command, path, [command](int exit_status) { - Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); - }); - } + Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); + Terminal::get().async_process(command, path, [command](int exit_status) { + Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); + }); } diff --git a/src/project.hpp b/src/project.hpp index ecdb0f7..7f76d26 100644 --- a/src/project.hpp +++ b/src/project.hpp @@ -56,7 +56,7 @@ namespace Project { virtual std::pair get_run_arguments(); virtual void compile(); - virtual void compile_and_run(); + virtual void compile_and_run(const boost::filesystem::path &file_path = {}); virtual void recreate_build(); void show_symbols(); @@ -115,7 +115,7 @@ namespace Project { std::pair get_run_arguments() override; void compile() override; - void compile_and_run() override; + void compile_and_run(const boost::filesystem::path &file_path = {}) override; void recreate_build() override; }; @@ -123,14 +123,14 @@ namespace Project { public: Markdown(std::unique_ptr &&build) : Base(std::move(build)) {} - void compile_and_run() override; + void compile_and_run(const boost::filesystem::path &file_path = {}) override; }; class Python : public LanguageProtocol { public: Python(std::unique_ptr &&build) : Base(std::move(build)) {} - void compile_and_run() override; + void compile_and_run(const boost::filesystem::path &file_path = {}) override; std::string get_language_id() override { return "python"; } }; @@ -139,7 +139,7 @@ namespace Project { public: JavaScript(std::unique_ptr &&build) : Base(std::move(build)) {} - void compile_and_run() override; + void compile_and_run(const boost::filesystem::path &file_path = {}) override; std::string get_language_id() override { return "javascript"; } }; @@ -148,7 +148,7 @@ namespace Project { public: HTML(std::unique_ptr &&build) : Base(std::move(build)) {} - void compile_and_run() override; + void compile_and_run(const boost::filesystem::path &file_path = {}) override; }; class Rust : public LLDB, public LanguageProtocol { @@ -157,7 +157,7 @@ namespace Project { std::pair get_run_arguments() override; void compile() override; - void compile_and_run() override; + void compile_and_run(const boost::filesystem::path &file_path = {}) override; std::string get_language_id() override { return "rust"; } }; @@ -166,7 +166,7 @@ namespace Project { public: Go(std::unique_ptr &&build) : Base(std::move(build)) {} - void compile_and_run() override; + void compile_and_run(const boost::filesystem::path &file_path = {}) override; std::string get_language_id() override { return "go"; } }; @@ -175,11 +175,11 @@ namespace Project { public: Julia(std::unique_ptr &&build) : Base(std::move(build)) {} - void compile_and_run() override; + void compile_and_run(const boost::filesystem::path &file_path = {}) override; std::string get_language_id() override { return "julia"; } }; - std::shared_ptr create(); + std::shared_ptr create(const boost::filesystem::path &file_path = {}); extern std::shared_ptr current; }; // namespace Project diff --git a/tests/stubs/project.cpp b/tests/stubs/project.cpp index ac2183f..6902f51 100644 --- a/tests/stubs/project.cpp +++ b/tests/stubs/project.cpp @@ -2,7 +2,7 @@ std::shared_ptr Project::current; -std::shared_ptr Project::create() { return nullptr; } +std::shared_ptr Project::create(const boost::filesystem::path &file_path) { return nullptr; } std::pair Project::Base::get_run_arguments() { return std::make_pair("", ""); @@ -10,7 +10,7 @@ std::pair Project::Base::get_run_arguments() { void Project::Base::compile() {} -void Project::Base::compile_and_run() {} +void Project::Base::compile_and_run(const boost::filesystem::path &file_path) {} void Project::Base::recreate_build() {}