From 56eb3ddae167ae7c4ad484f1aced572b156d6708 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 2 Jan 2016 10:47:47 +0100 Subject: [PATCH] Added Debug Set Run Arguments and fixed escaping of paths and arguments --- src/cmake.cc | 4 +-- src/debug.cc | 69 ++++++++++++++++++++++++++++++++++------ src/debug.h | 4 +-- src/filesystem.cc | 14 +++++--- src/filesystem.h | 6 ++-- src/window.cc | 81 ++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 146 insertions(+), 32 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index c8bcff6..8a5ee2e 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -116,7 +116,7 @@ bool CMake::create_compile_commands(const boost::filesystem::path &project_path) auto compile_commands_path=default_build_path/"compile_commands.json"; Dialog::Message message("Creating "+compile_commands_path.string()); auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" "+ - filesystem::escape(project_path)+" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path); + filesystem::escape_argument(project_path)+" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path); message.hide(); if(exit_status==EXIT_SUCCESS) { #ifdef _WIN32 //Temporary fix to MSYS2's libclang @@ -146,7 +146,7 @@ bool CMake::create_debug_build(const boost::filesystem::path &project_path) { if(!boost::filesystem::exists(debug_build_path/"CMakeCache.txt")) message=std::unique_ptr(new Dialog::Message("Creating debug build")); auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" "+ - filesystem::escape(project_path)+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path); + filesystem::escape_argument(project_path)+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path); if(message) message->hide(); if(exit_status==EXIT_SUCCESS) diff --git a/src/debug.cc b/src/debug.cc index 51bbd59..88217f4 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -1,8 +1,12 @@ #include "debug.h" #include +#ifdef __APPLE__ #include +#include +#endif #include #include "terminal.h" +#include "filesystem.h" #include #include @@ -25,36 +29,81 @@ void log(const char *msg, void *) { Debug::Debug(): listener("juCi++ lldb listener"), state(lldb::StateType::eStateInvalid), buffer_size(131072) { #ifdef __APPLE__ - setenv("LLDB_DEBUGSERVER_PATH", "/usr/local/opt/llvm/bin/debugserver", 0); + auto debugserver_path=boost::filesystem::path("/usr/local/opt/llvm/bin/debugserver"); + if(boost::filesystem::exists(debugserver_path)) + setenv("LLDB_DEBUGSERVER_PATH", debugserver_path.string().c_str(), 0); #endif } -void Debug::start(std::shared_ptr > > breakpoints, const boost::filesystem::path &executable, - const boost::filesystem::path &path, std::function callback, +void Debug::start(const std::string &command, const boost::filesystem::path &path, + std::shared_ptr > > breakpoints, + std::function callback, std::function status_callback, std::function stop_callback) { if(!debugger.IsValid()) { lldb::SBDebugger::Initialize(); debugger=lldb::SBDebugger::Create(true, log, nullptr); } - auto target=debugger.CreateTarget(executable.string().c_str()); + //Create executable string and argument array + std::string executable; + std::vector arguments; + size_t start_pos=std::string::npos; + bool quote=false; + bool double_quote=false; + bool symbol=false; + for(size_t c=0;c<=command.size();c++) { + if(c==command.size() || (!quote && !double_quote && !symbol && command[c]==' ')) { + if(c>0 && start_pos!=std::string::npos) { + if(executable.empty()) + executable=filesystem::unescape(command.substr(start_pos, c-start_pos)); + else + arguments.emplace_back(filesystem::unescape(command.substr(start_pos, c-start_pos))); + start_pos=std::string::npos; + } + } + else if(command[c]=='\\' && !quote && !double_quote) + symbol=true; + else if(symbol) + symbol=false; + else if(command[c]=='\'' && !double_quote) + quote=!quote; + else if(command[c]=='"' && !quote) + double_quote=!double_quote; + if(c(new lldb::SBProcess(target.Launch(listener, nullptr, (const char**)environ, nullptr, nullptr, nullptr, path.string().c_str(), lldb::eLaunchFlagNone, false, error))); + process = std::unique_ptr(new lldb::SBProcess(target.Launch(listener, argv, (const char**)environ, nullptr, nullptr, nullptr, path.string().c_str(), lldb::eLaunchFlagNone, false, error))); if(error.Fail()) { Terminal::get().async_print(std::string("Error (debug): ")+error.GetCString()+'\n', true); + if(callback) + callback(-1); return; } if(debug_thread.joinable()) diff --git a/src/debug.h b/src/debug.h index 3f00eac..0174167 100644 --- a/src/debug.h +++ b/src/debug.h @@ -18,8 +18,8 @@ public: return singleton; } - void start(std::shared_ptr > > breakpoints, - const boost::filesystem::path &executable, const boost::filesystem::path &path="", + void start(const std::string &command, const boost::filesystem::path &path="", + std::shared_ptr > > breakpoints=nullptr, std::function callback=nullptr, std::function status_callback=nullptr, std::function stop_callback=nullptr); diff --git a/src/filesystem.cc b/src/filesystem.cc index e2a62ef..7c46dea 100644 --- a/src/filesystem.cc +++ b/src/filesystem.cc @@ -136,8 +136,8 @@ bool filesystem::write(const std::string &path, Glib::RefPtr bu return false; } -std::string filesystem::escape(const std::string &path) { - auto escaped=path; +std::string filesystem::escape_argument(const std::string &argument) { + auto escaped=argument; size_t pos=0; while((pos=escaped.find(' ', pos))!=std::string::npos) { escaped.replace(pos, 1, "\\ "); @@ -146,12 +146,18 @@ std::string filesystem::escape(const std::string &path) { return escaped; } -std::string filesystem::unescape(const std::string &path) { - auto escaped=path; +std::string filesystem::unescape(const std::string &argument) { + auto escaped=argument; size_t pos=0; while((pos=escaped.find("\\ ", pos))!=std::string::npos) { escaped.replace(pos, 2, " "); pos+=1; } + if(escaped.size()>=2) { + if((escaped[0]=='\'' && escaped[escaped.size()-1]=='\'') || + (escaped[0]=='"' && escaped[escaped.size()-1]=='"')) { + escaped=escaped.substr(1, escaped.size()-2); + } + } return escaped; } diff --git a/src/filesystem.h b/src/filesystem.h index f4a0e6d..d2b3e7a 100644 --- a/src/filesystem.h +++ b/src/filesystem.h @@ -25,8 +25,8 @@ public: 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); } - static std::string escape(const std::string &path); - static std::string escape(const boost::filesystem::path &path) { return escape(path.string()); }; - static std::string unescape(const std::string &path); + static std::string escape_argument(const std::string &argument); + static std::string escape_argument(const boost::filesystem::path &argument) { return escape_argument(argument.string()); }; + static std::string unescape(const std::string &argument); }; #endif // JUCI_FILESYSTEM_H_ diff --git a/src/window.cc b/src/window.cc index a88bc79..9a56018 100644 --- a/src/window.cc +++ b/src/window.cc @@ -590,10 +590,10 @@ void Window::set_menu_actions() { if(pos!=std::string::npos) executable.replace(pos, project_path.string().size(), default_build_path.string()); } - run_arguments=filesystem::escape(executable); + run_arguments=filesystem::escape_argument(executable); } else - run_arguments=cmake.project_path.string(); + run_arguments=filesystem::escape_argument(CMake::get_default_build_path(cmake.project_path)); } entry_box.clear(); @@ -644,12 +644,13 @@ void Window::set_menu_actions() { 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(command); + command=filesystem::escape_argument(command); } compiling=true; @@ -722,6 +723,63 @@ void Window::set_menu_actions() { }); #ifdef JUCI_ENABLE_DEBUG + menu.add_action("debug_set_run_arguments", [this]() { + auto cmake=get_cmake(); + if(!cmake) + return; + auto project_path=std::make_shared(cmake->project_path); + if(project_path->empty()) + return; + auto run_arguments_it=debug_run_arguments.find(project_path->string()); + std::string run_arguments; + if(run_arguments_it!=debug_run_arguments.end()) + run_arguments=run_arguments_it->second; + + if(run_arguments.empty()) { + boost::filesystem::path cmake_path; + if(notebook.get_current_page()!=-1) + cmake_path=notebook.get_current_view()->file_path.parent_path(); + else + cmake_path=Directories::get().current_path; + if(cmake_path.empty()) + return; + CMake cmake(cmake_path); + if(cmake.project_path.empty()) + return; + 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 debug_build_path=CMake::get_debug_build_path(project_path); + if(!debug_build_path.empty()) { + size_t pos=executable.find(project_path.string()); + if(pos!=std::string::npos) + executable.replace(pos, project_path.string().size(), debug_build_path.string()); + } + run_arguments=filesystem::escape_argument(executable); + } + else + run_arguments=filesystem::escape_argument(CMake::get_debug_build_path(cmake.project_path)); + } + + entry_box.clear(); + entry_box.labels.emplace_back(); + auto label_it=entry_box.labels.begin(); + label_it->update=[label_it](int state, const std::string& message){ + label_it->set_text("Leave empty to let juCi++ deduce executable"); + }; + label_it->update(0, ""); + entry_box.entries.emplace_back(run_arguments, [this, project_path](const std::string& content){ + debug_run_arguments[project_path->string()]=content; + entry_box.hide(); + }, 50); + auto entry_it=entry_box.entries.begin(); + entry_it->set_placeholder_text("Project: Set Run Arguments"); + entry_box.buttons.emplace_back("Project: set run arguments", [this, entry_it](){ + entry_it->activate(); + }); + entry_box.show(); + }); menu.add_action("debug_start_continue", [this](){ if(debugging) { Debug::get().continue_debug(); @@ -741,28 +799,29 @@ void Window::set_menu_actions() { if(!CMake::create_debug_build(project_path)) return; - /*auto run_arguments_it=project_run_arguments.find(project_path.string()); + auto run_arguments_it=debug_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_it!=debug_run_arguments.end()) + run_arguments=run_arguments_it->second; std::string command; - /*if(!run_arguments.empty()) { + if(!run_arguments.empty()) { command=run_arguments; } - else {*/ + 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 Debug 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(), debug_build_path.string()); - command=filesystem::escape(command); - //} + command=filesystem::escape_argument(command); + } auto breakpoints=std::make_shared > >(); for(int c=0;c