Browse Source

Added Debug Set Run Arguments and fixed escaping of paths and arguments

merge-requests/365/head
eidheim 10 years ago
parent
commit
56eb3ddae1
  1. 4
      src/cmake.cc
  2. 69
      src/debug.cc
  3. 4
      src/debug.h
  4. 14
      src/filesystem.cc
  5. 6
      src/filesystem.h
  6. 81
      src/window.cc

4
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<Dialog::Message>(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)

69
src/debug.cc

@ -1,8 +1,12 @@
#include "debug.h"
#include <stdio.h>
#ifdef __APPLE__
#include <stdlib.h>
#include <boost/filesystem.hpp>
#endif
#include <iostream>
#include "terminal.h"
#include "filesystem.h"
#include <lldb/API/SBTarget.h>
#include <lldb/API/SBProcess.h>
@ -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<std::vector<std::pair<boost::filesystem::path, int> > > breakpoints, const boost::filesystem::path &executable,
const boost::filesystem::path &path, std::function<void(int exit_status)> callback,
void Debug::start(const std::string &command, const boost::filesystem::path &path,
std::shared_ptr<std::vector<std::pair<boost::filesystem::path, int> > > breakpoints,
std::function<void(int exit_status)> callback,
std::function<void(const std::string &status)> status_callback,
std::function<void(const boost::filesystem::path &file_path, int line_nr, int line_index)> 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<std::string> 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<command.size() && start_pos==std::string::npos && command[c]!=' ')
start_pos=c;
}
const char *argv[arguments.size()+1];
for(size_t c=0;c<arguments.size();c++)
argv[c]=arguments[c].c_str();
argv[arguments.size()]=NULL;
auto target=debugger.CreateTarget(executable.c_str());
if(!target.IsValid()) {
Terminal::get().async_print("Error (debug): Could not create debug target to: "+executable.string()+'\n', true);
Terminal::get().async_print("Error (debug): Could not create debug target to: "+executable+'\n', true);
if(callback)
callback(-1);
return;
}
for(auto &breakpoint: *breakpoints) {
if(!(target.BreakpointCreateByLocation(breakpoint.first.string().c_str(), breakpoint.second)).IsValid()) {
Terminal::get().async_print("Error (debug): Could not create breakpoint at: "+breakpoint.first.string()+":"+std::to_string(breakpoint.second)+'\n', true);
return;
//Set breakpoints
if(breakpoints) {
for(auto &breakpoint: *breakpoints) {
if(!(target.BreakpointCreateByLocation(breakpoint.first.string().c_str(), breakpoint.second)).IsValid()) {
Terminal::get().async_print("Error (debug): Could not create breakpoint at: "+breakpoint.first.string()+":"+std::to_string(breakpoint.second)+'\n', true);
if(callback)
callback(-1);
return;
}
}
}
lldb::SBError error;
process = std::unique_ptr<lldb::SBProcess>(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<lldb::SBProcess>(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())

4
src/debug.h

@ -18,8 +18,8 @@ public:
return singleton;
}
void start(std::shared_ptr<std::vector<std::pair<boost::filesystem::path, int> > > 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<std::vector<std::pair<boost::filesystem::path, int> > > breakpoints=nullptr,
std::function<void(int exit_status)> callback=nullptr,
std::function<void(const std::string &status)> status_callback=nullptr,
std::function<void(const boost::filesystem::path &file_path, int line_nr, int line_index)> stop_callback=nullptr);

14
src/filesystem.cc

@ -136,8 +136,8 @@ bool filesystem::write(const std::string &path, Glib::RefPtr<Gtk::TextBuffer> 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;
}

6
src/filesystem.h

@ -25,8 +25,8 @@ public:
static bool write(const std::string &path, Glib::RefPtr<Gtk::TextBuffer> text_buffer);
static bool write(const boost::filesystem::path &path, Glib::RefPtr<Gtk::TextBuffer> 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_

81
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<boost::filesystem::path>(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<std::vector<std::pair<boost::filesystem::path, int> > >();
for(int c=0;c<notebook.size();c++) {
@ -782,7 +841,7 @@ void Window::set_menu_actions() {
if(exit_status!=EXIT_SUCCESS)
debugging=false;
else {
Debug::get().start(breakpoints, filesystem::unescape(command), debug_build_path, [this, command](int exit_status){
Debug::get().start(command, debug_build_path, breakpoints, [this, command](int exit_status){
debugging=false;
Terminal::get().async_print(command+" returned: "+std::to_string(exit_status)+'\n');
}, [this](const std::string &status) {

Loading…
Cancel
Save