From 35ab8810716e89aa504a8b698c8d531aa9eac5f6 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 9 Feb 2016 13:11:27 +0100 Subject: [PATCH] Finished project cleanup --- src/debug.cc | 16 ++- src/debug.h | 2 +- src/notebook.cc | 8 +- src/notebook.h | 2 + src/project.cc | 284 ++++++++++++++++++++++++++++++++++++++++++-- src/project.h | 38 ++++-- src/window.cc | 305 +++++++----------------------------------------- src/window.h | 11 -- 8 files changed, 360 insertions(+), 306 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index ed27d14..6289da1 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -36,7 +36,7 @@ Debug::Debug(): state(lldb::StateType::eStateInvalid), buffer_size(131072) { } void Debug::start(const std::string &command, const boost::filesystem::path &path, - std::shared_ptr > > breakpoints, + const std::vector > &breakpoints, std::function callback, std::function status_callback, std::function stop_callback) { @@ -88,14 +88,12 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat } //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; - } + 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; } } diff --git a/src/debug.h b/src/debug.h index 07fd4d2..2d4471d 100644 --- a/src/debug.h +++ b/src/debug.h @@ -39,7 +39,7 @@ public: } void start(const std::string &command, const boost::filesystem::path &path="", - std::shared_ptr > > breakpoints=nullptr, + const std::vector > &breakpoints={}, std::function callback=nullptr, std::function status_callback=nullptr, std::function stop_callback=nullptr); diff --git a/src/notebook.cc b/src/notebook.cc index 68f8614..4ecf9cc 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -355,17 +355,13 @@ boost::filesystem::path Notebook::get_current_folder() { } std::unique_ptr Notebook::get_project() { - boost::filesystem::path file_path; - if(get_current_page()!=-1) - file_path=get_current_view()->file_path; - if(get_current_page()!=-1) { if(get_current_view()->language->get_id()=="markdown") { - return std::unique_ptr(new ProjectMarkDown(file_path)); + return std::unique_ptr(new ProjectMarkDown(*this)); } } - return std::unique_ptr(new ProjectClang(file_path)); + return std::unique_ptr(new ProjectClang(*this)); } bool Notebook::save_modified_dialog(int page) { diff --git a/src/notebook.h b/src/notebook.h index 2c15ad5..5f58308 100644 --- a/src/notebook.h +++ b/src/notebook.h @@ -10,6 +10,8 @@ #include #include +class Project; //Avoiding this would lead to bloated code + class Notebook : public Gtk::Notebook { class TabLabel : public Gtk::Box { public: diff --git a/src/project.cc b/src/project.cc index 4385b61..c9d8405 100644 --- a/src/project.cc +++ b/src/project.cc @@ -3,6 +3,9 @@ #include "terminal.h" #include "filesystem.h" #include +#ifdef JUCI_ENABLE_DEBUG +#include "debug.h" +#endif std::unordered_map Project::run_arguments; std::unordered_map Project::debug_run_arguments; @@ -11,8 +14,8 @@ std::atomic Project::debugging(false); std::unique_ptr ProjectClang::get_cmake() { boost::filesystem::path path; - if(!file_path.empty()) - path=file_path.parent_path(); + if(notebook.get_current_page()!=-1) + path=notebook.get_current_view()->file_path.parent_path(); else path=Directories::get().current_path; if(path.empty()) @@ -37,15 +40,15 @@ std::pair ProjectClang::get_run_arguments() { arguments=run_arguments_it->second; if(arguments.empty()) { - auto executable=cmake->get_executable(file_path).string(); + 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()) { + auto build_path=CMake::get_default_build_path(project_path); + if(!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()); + executable.replace(pos, project_path.string().size(), build_path.string()); } arguments=filesystem::escape_argument(executable); } @@ -87,7 +90,7 @@ void ProjectClang::compile_and_run() { arguments=run_arguments_it->second; if(arguments.empty()) { - arguments=cmake->get_executable(file_path).string(); + arguments=cmake->get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:"").string(); if(arguments.empty()) { Terminal::get().print("Could not find add_executable in the following paths:\n"); for(auto &path: cmake->paths) @@ -113,6 +116,271 @@ void ProjectClang::compile_and_run() { }); } +#ifdef JUCI_ENABLE_DEBUG +std::pair ProjectClang::debug_get_run_arguments() { + auto cmake=get_cmake(); + if(!cmake) + return {"", ""}; + + auto project_path=cmake->project_path.string(); + auto run_arguments_it=debug_run_arguments.find(project_path); + std::string arguments; + if(run_arguments_it!=debug_run_arguments.end()) + arguments=run_arguments_it->second; + + if(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 build_path=CMake::get_debug_build_path(project_path); + if(!build_path.empty()) { + size_t pos=executable.find(project_path.string()); + if(pos!=std::string::npos) + executable.replace(pos, project_path.string().size(), build_path.string()); + } + arguments=filesystem::escape_argument(executable); + } + else + arguments=filesystem::escape_argument(CMake::get_debug_build_path(cmake->project_path)); + } + + return {project_path, arguments}; +} + +void ProjectClang::debug_start(std::function status_callback, + std::function stop_callback) { + auto cmake=get_cmake(); + if(!cmake) + return; + auto project_path=cmake->project_path; + + auto debug_build_path=CMake::get_debug_build_path(project_path); + if(debug_build_path.empty()) + return; + if(!CMake::create_debug_build(project_path)) + 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()) { + run_arguments=cmake->get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:"").string(); + if(run_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 Debug Set Run Arguments, or open a source file within a directory where add_executable is set.\n", true); + return; + } + size_t pos=run_arguments.find(project_path.string()); + if(pos!=std::string::npos) + run_arguments.replace(pos, project_path.string().size(), debug_build_path.string()); + run_arguments=filesystem::escape_argument(run_arguments); + } + + auto breakpoints=std::make_shared > >(); + for(int c=0;cproject_path) { + auto iter=view->get_buffer()->begin(); + if(view->get_source_buffer()->get_source_marks_at_iter(iter, "debug_breakpoint").size()>0) + breakpoints->emplace_back(view->file_path, iter.get_line()+1); + while(view->get_source_buffer()->forward_iter_to_source_mark(iter, "debug_breakpoint")) + breakpoints->emplace_back(view->file_path, iter.get_line()+1); + } + } + + debugging=true; + Terminal::get().print("Compiling and debugging "+run_arguments+"\n"); + Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, breakpoints, run_arguments, debug_build_path, status_callback, stop_callback](int exit_status){ + if(exit_status!=EXIT_SUCCESS) + debugging=false; + else { + debug_start_mutex.lock(); + Debug::get().start(run_arguments, debug_build_path, *breakpoints, [this, run_arguments](int exit_status){ + debugging=false; + Terminal::get().async_print(run_arguments+" returned: "+std::to_string(exit_status)+'\n'); + }, status_callback, stop_callback); + debug_start_mutex.unlock(); + } + }); +} + +void ProjectClang::debug_continue() { + Debug::get().continue_debug(); +} + +void ProjectClang::debug_stop() { + if(debugging) + Debug::get().stop(); +} + +void ProjectClang::debug_kill() { + if(debugging) + Debug::get().kill(); +} + +void ProjectClang::debug_step_over() { + if(debugging) + Debug::get().step_over(); +} + +void ProjectClang::debug_step_into() { + if(debugging) + Debug::get().step_into(); +} + +void ProjectClang::debug_step_out() { + if(debugging) + Debug::get().step_out(); +} + +void ProjectClang::debug_backtrace() { + if(debugging && notebook.get_current_page()!=-1) { + auto backtrace=Debug::get().get_backtrace(); + + auto view=notebook.get_current_view(); + auto iter=view->get_iter_for_dialog(); + view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, view->get_buffer()->create_mark(iter), true, true)); + auto rows=std::make_shared >(); + if(backtrace.size()==0) + return; + + for(auto &frame: backtrace) { + std::string row=""+frame.module_filename+""; + + //Shorten frame.function_name if it is too long + if(frame.function_name.size()>120) { + frame.function_name=frame.function_name.substr(0, 58)+"...."+frame.function_name.substr(frame.function_name.size()-58); + } + if(frame.file_path.empty()) + row+=" - "+Glib::Markup::escape_text(frame.function_name); + else { + auto file_path=boost::filesystem::path(frame.file_path).filename().string(); + row+=":"+Glib::Markup::escape_text(file_path)+":"+std::to_string(frame.line_nr)+" - "+Glib::Markup::escape_text(frame.function_name); + } + (*rows)[row]=frame; + view->selection_dialog->add_row(row); + } + + view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { + auto frame=rows->at(selected); + if(!frame.file_path.empty()) { + notebook.open(frame.file_path); + if(notebook.get_current_page()!=-1) { + auto view=notebook.get_current_view(); + + Debug::get().select_frame(frame.index); + + view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(frame.line_nr-1, frame.line_index-1)); + + while(g_main_context_pending(NULL)) + g_main_context_iteration(NULL, false); + if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) + view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); + } + } + }; + view->selection_dialog->show(); + } +} + +void ProjectClang::debug_show_variables() { + if(debugging && notebook.get_current_page()!=-1) { + auto variables=Debug::get().get_variables(); + + auto view=notebook.get_current_view(); + auto iter=view->get_iter_for_dialog(); + view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, view->get_buffer()->create_mark(iter), true, true)); + auto rows=std::make_shared >(); + if(variables.size()==0) + return; + + for(auto &variable: variables) { + std::string row="#"+std::to_string(variable.thread_index_id)+":#"+std::to_string(variable.frame_index)+":"+variable.file_path.filename().string()+":"+std::to_string(variable.line_nr)+" - "+Glib::Markup::escape_text(variable.name)+""; + + (*rows)[row]=variable; + view->selection_dialog->add_row(row); + } + + view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { + auto variable=rows->at(selected); + if(!variable.file_path.empty()) { + notebook.open(variable.file_path); + if(notebook.get_current_page()!=-1) { + auto view=notebook.get_current_view(); + + Debug::get().select_frame(variable.frame_index, variable.thread_index_id); + + view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(variable.line_nr-1, variable.line_index-1)); + + while(g_main_context_pending(NULL)) + g_main_context_iteration(NULL, false); + if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) + view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); + } + } + }; + + view->selection_dialog->on_hide=[this]() { + debug_variable_tooltips.hide(); + debug_variable_tooltips.clear(); + }; + + view->selection_dialog->on_changed=[this, rows, iter](const std::string &selected) { + if(selected.empty()) { + debug_variable_tooltips.hide(); + return; + } + if(notebook.get_current_page()!=-1) { + auto view=notebook.get_current_view(); + debug_variable_tooltips.clear(); + auto create_tooltip_buffer=[this, rows, view, selected]() { + auto variable=rows->at(selected); + auto tooltip_buffer=Gtk::TextBuffer::create(view->get_buffer()->get_tag_table()); + + Glib::ustring value=variable.value; + if(!value.empty()) { + Glib::ustring::iterator iter; + while(!value.validate(iter)) { + auto next_char_iter=iter; + next_char_iter++; + value.replace(iter, next_char_iter, "?"); + } + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), value.substr(0, value.size()-1), "def:note"); + } + + return tooltip_buffer; + }; + + debug_variable_tooltips.emplace_back(create_tooltip_buffer, *view, view->get_buffer()->create_mark(iter), view->get_buffer()->create_mark(iter)); + + debug_variable_tooltips.show(true); + } + }; + + view->selection_dialog->show(); + } +} + +void ProjectClang::debug_run_command(const std::string &command) { + if(debugging) { + auto command_return=Debug::get().run_command(command); + Terminal::get().async_print(command_return.first); + Terminal::get().async_print(command_return.second, true); + } +} + +void ProjectClang::debug_delete() { + debug_start_mutex.lock(); + Debug::get().delete_debug(); + debug_start_mutex.unlock(); +} +#endif + ProjectMarkDown::~ProjectMarkDown() { if(!last_temp_path.empty()) { boost::filesystem::remove(last_temp_path); @@ -127,7 +395,7 @@ void ProjectMarkDown::compile_and_run() { } std::stringstream stdin_stream, stdout_stream; - auto exit_status=Terminal::get().process(stdin_stream, stdout_stream, "markdown "+file_path.string(), this->file_path.parent_path()); + auto exit_status=Terminal::get().process(stdin_stream, stdout_stream, "markdown "+notebook.get_current_view()->file_path.string()); if(exit_status==0) { boost::system::error_code ec; auto temp_path=boost::filesystem::temp_directory_path(ec); diff --git a/src/project.h b/src/project.h index eb74f85..9cbb183 100644 --- a/src/project.h +++ b/src/project.h @@ -1,17 +1,22 @@ #ifndef JUCI_PROJECT_H_ #define JUCI_PROJECT_H_ +#include "notebook.h" //Avoiding this circular include would lead to bloated code #include "cmake.h" #include #include "directories.h" #include +#include +#include "tooltips.h" + +class Notebook; //Avoiding this circular include would lead to bloated code class Project { public: - Project(const boost::filesystem::path &file_path) : file_path(file_path) {} + Project(Notebook ¬ebook) : notebook(notebook) {} virtual ~Project() {} - boost::filesystem::path file_path; + Notebook ¬ebook; static std::unordered_map run_arguments; static std::unordered_map debug_run_arguments; @@ -23,7 +28,10 @@ public: virtual void compile_and_run() {} virtual std::pair debug_get_run_arguments() {return {"", ""};} - virtual void debug_start_continue() {} + Tooltips debug_variable_tooltips; + virtual void debug_start(std::function status_callback, + std::function stop_callback) {} + virtual void debug_continue() {} virtual void debug_stop() {} virtual void debug_kill() {} virtual void debug_step_over() {} @@ -31,25 +39,39 @@ public: 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() {} + virtual void debug_run_command(const std::string &command) {} + virtual void debug_delete() {} }; class ProjectClang : public Project { public: - ProjectClang(const boost::filesystem::path &file_path) : Project(file_path) {} + ProjectClang(Notebook ¬ebook) : Project(notebook) {} std::unique_ptr get_cmake(); std::pair get_run_arguments() override; void compile() override; void compile_and_run() override; + + std::pair debug_get_run_arguments() override; + std::mutex debug_start_mutex; + void debug_start(std::function status_callback, + std::function stop_callback) override; + void debug_continue() override; + void debug_stop() override; + void debug_kill() override; + void debug_step_over() override; + void debug_step_into() override; + void debug_step_out() override; + void debug_backtrace() override; + void debug_show_variables() override; + void debug_run_command(const std::string &command) override; + void debug_delete() override; }; class ProjectMarkDown : public Project { public: - ProjectMarkDown(const boost::filesystem::path &file_path) : Project(file_path) {} + ProjectMarkDown(Notebook ¬ebook) : Project(notebook) {} ~ProjectMarkDown(); boost::filesystem::path last_temp_path; diff --git a/src/window.cc b/src/window.cc index 108ea41..8495edb 100644 --- a/src/window.cc +++ b/src/window.cc @@ -24,7 +24,7 @@ namespace sigc { #endif } -Window::Window() : compiling(false), debugging(false) { +Window::Window() { JDEBUG("start"); set_title("juCi++"); set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK|Gdk::LEAVE_NOTIFY_MASK); @@ -203,22 +203,6 @@ Window::Window() : compiling(false), debugging(false) { JDEBUG("end"); } // Window constructor -std::unique_ptr Window::get_cmake() { - boost::filesystem::path path; - if(notebook.get_current_page()!=-1) - path=notebook.get_current_view()->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; -} - void Window::configure() { Config::get().load(); auto style_context = Gtk::StyleContext::create(); @@ -672,32 +656,10 @@ void Window::set_menu_actions() { #ifdef JUCI_ENABLE_DEBUG menu.add_action("debug_set_run_arguments", [this]() { - auto cmake=get_cmake(); - if(!cmake) + project=notebook.get_project(); + auto run_arguments=std::make_shared >(project->debug_get_run_arguments()); + if(run_arguments->second.empty()) return; - - auto project_path=std::make_shared(cmake->project_path); - 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()) { - 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(); @@ -706,258 +668,76 @@ 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){ - debug_run_arguments[project_path->string()]=content; + entry_box.entries.emplace_back(run_arguments->second, [this, run_arguments](const std::string& content){ + Project::debug_run_arguments[run_arguments->first]=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->set_placeholder_text("Debug: Set Run Arguments"); + entry_box.buttons.emplace_back("Debug: 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(); + if(Project::debugging) { + project->debug_continue(); 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 debug_build_path=CMake::get_debug_build_path(project_path); - if(debug_build_path.empty()) - return; - if(!CMake::create_debug_build(project_path)) - 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; - - 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 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_argument(command); - } - - auto breakpoints=std::make_shared > >(); - for(int c=0;cproject_path) { - auto iter=view->get_buffer()->begin(); - if(view->get_source_buffer()->get_source_marks_at_iter(iter, "debug_breakpoint").size()>0) - breakpoints->emplace_back(view->file_path, iter.get_line()+1); - while(view->get_source_buffer()->forward_iter_to_source_mark(iter, "debug_breakpoint")) - breakpoints->emplace_back(view->file_path, iter.get_line()+1); - } - } + project=notebook.get_project(); - debugging=true; - Terminal::get().print("Compiling and debugging "+command+"\n"); - Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, breakpoints, command, debug_build_path](int exit_status){ - if(exit_status!=EXIT_SUCCESS) - debugging=false; - else { - debug_start_mutex.lock(); - 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) { - debug_status_mutex.lock(); - debug_status=status; - debug_status_mutex.unlock(); - debug_update_status(); - }, [this](const boost::filesystem::path &file_path, int line_nr, int line_index) { - debug_stop_mutex.lock(); - debug_stop.first=file_path; - debug_stop.second.first=line_nr; - debug_stop.second.second=line_index; - debug_stop_mutex.unlock(); - debug_update_stop(); - //Remove debug stop source mark - }); - debug_start_mutex.unlock(); - } + project->debug_start([this](const std::string &status) { + debug_status_mutex.lock(); + debug_status=status; + debug_status_mutex.unlock(); + debug_update_status(); + }, [this](const boost::filesystem::path &file_path, int line_nr, int line_index) { + debug_stop_mutex.lock(); + debug_stop.first=file_path; + debug_stop.second.first=line_nr; + debug_stop.second.second=line_index; + debug_stop_mutex.unlock(); + debug_update_stop(); }); }); menu.add_action("debug_stop", [this]() { - if(debugging) { - Debug::get().stop(); - } + if(project) + project->debug_stop(); }); menu.add_action("debug_kill", [this]() { - if(debugging) { - Debug::get().kill(); - } + if(project) + project->debug_kill(); }); menu.add_action("debug_step_over", [this]() { - if(debugging) - Debug::get().step_over(); + if(project) + project->debug_step_over(); }); menu.add_action("debug_step_into", [this]() { - if(debugging) - Debug::get().step_into(); + if(project) + project->debug_step_into(); }); menu.add_action("debug_step_out", [this]() { - if(debugging) - Debug::get().step_out(); + if(project) + project->debug_step_out(); }); menu.add_action("debug_backtrace", [this]() { - if(debugging && notebook.get_current_page()!=-1) { - auto backtrace=Debug::get().get_backtrace(); - - auto view=notebook.get_current_view(); - auto iter=view->get_iter_for_dialog(); - view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, view->get_buffer()->create_mark(iter), true, true)); - auto rows=std::make_shared >(); - if(backtrace.size()==0) - return; - - for(auto &frame: backtrace) { - std::string row=""+frame.module_filename+""; - - //Shorten frame.function_name if it is too long - if(frame.function_name.size()>120) { - frame.function_name=frame.function_name.substr(0, 58)+"...."+frame.function_name.substr(frame.function_name.size()-58); - } - if(frame.file_path.empty()) - row+=" - "+Glib::Markup::escape_text(frame.function_name); - else { - auto file_path=boost::filesystem::path(frame.file_path).filename().string(); - row+=":"+Glib::Markup::escape_text(file_path)+":"+std::to_string(frame.line_nr)+" - "+Glib::Markup::escape_text(frame.function_name); - } - (*rows)[row]=frame; - view->selection_dialog->add_row(row); - } - - view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { - auto frame=rows->at(selected); - if(!frame.file_path.empty()) { - notebook.open(frame.file_path); - if(notebook.get_current_page()!=-1) { - auto view=notebook.get_current_view(); - - Debug::get().select_frame(frame.index); - - view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(frame.line_nr-1, frame.line_index-1)); - - while(g_main_context_pending(NULL)) - g_main_context_iteration(NULL, false); - if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) - view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); - } - } - }; - view->selection_dialog->show(); - } + if(project) + project->debug_backtrace(); }); menu.add_action("debug_show_variables", [this]() { - if(debugging && notebook.get_current_page()!=-1) { - auto variables=Debug::get().get_variables(); - - auto view=notebook.get_current_view(); - auto iter=view->get_iter_for_dialog(); - view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, view->get_buffer()->create_mark(iter), true, true)); - auto rows=std::make_shared >(); - if(variables.size()==0) - return; - - for(auto &variable: variables) { - std::string row="#"+std::to_string(variable.thread_index_id)+":#"+std::to_string(variable.frame_index)+":"+variable.file_path.filename().string()+":"+std::to_string(variable.line_nr)+" - "+Glib::Markup::escape_text(variable.name)+""; - - (*rows)[row]=variable; - view->selection_dialog->add_row(row); - } - - view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { - auto variable=rows->at(selected); - if(!variable.file_path.empty()) { - notebook.open(variable.file_path); - if(notebook.get_current_page()!=-1) { - auto view=notebook.get_current_view(); - - Debug::get().select_frame(variable.frame_index, variable.thread_index_id); - - view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(variable.line_nr-1, variable.line_index-1)); - - while(g_main_context_pending(NULL)) - g_main_context_iteration(NULL, false); - if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) - view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); - } - } - }; - - view->selection_dialog->on_hide=[this]() { - debug_variable_tooltips.hide(); - debug_variable_tooltips.clear(); - }; - - view->selection_dialog->on_changed=[this, rows, iter](const std::string &selected) { - if(selected.empty()) { - debug_variable_tooltips.hide(); - return; - } - if(notebook.get_current_page()!=-1) { - auto view=notebook.get_current_view(); - debug_variable_tooltips.clear(); - auto create_tooltip_buffer=[this, rows, view, selected]() { - auto variable=rows->at(selected); - auto tooltip_buffer=Gtk::TextBuffer::create(view->get_buffer()->get_tag_table()); - - Glib::ustring value=variable.value; - if(!value.empty()) { - Glib::ustring::iterator iter; - while(!value.validate(iter)) { - auto next_char_iter=iter; - next_char_iter++; - value.replace(iter, next_char_iter, "?"); - } - tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), value.substr(0, value.size()-1), "def:note"); - } - - return tooltip_buffer; - }; - - debug_variable_tooltips.emplace_back(create_tooltip_buffer, *view, view->get_buffer()->create_mark(iter), view->get_buffer()->create_mark(iter)); - - debug_variable_tooltips.show(true); - } - }; - - view->selection_dialog->show(); - } + if(project) + project->debug_show_variables(); }); menu.add_action("debug_run_command", [this]() { entry_box.clear(); entry_box.entries.emplace_back(last_run_debug_command, [this](const std::string& content){ if(content!="") { - if(debugging) { - auto command_return=Debug::get().run_command(content); - Terminal::get().async_print(command_return.first); - Terminal::get().async_print(command_return.second, true); - } + if(project) + project->debug_run_command(content); last_run_debug_command=content; } entry_box.hide(); @@ -993,7 +773,7 @@ void Window::set_menu_actions() { } }); menu.add_action("debug_goto_stop", [this](){ - if(debugging) { + if(project && project->debugging) { debug_stop_mutex.lock(); auto debug_stop_copy=debug_stop; debug_stop_mutex.unlock(); @@ -1119,9 +899,8 @@ bool Window::on_delete_event(GdkEventAny *event) { } Terminal::get().kill_async_processes(); #ifdef JUCI_ENABLE_DEBUG - debug_start_mutex.lock(); - Debug::get().delete_debug(); - debug_start_mutex.unlock(); + if(project) + project->debug_delete(); #endif return false; } diff --git a/src/window.h b/src/window.h index a23ad39..b0a5991 100644 --- a/src/window.h +++ b/src/window.h @@ -5,7 +5,6 @@ #include "entrybox.h" #include "notebook.h" #include "cmake.h" -#include "tooltips.h" #include "project.h" #include @@ -37,12 +36,8 @@ private: std::unique_ptr project; - std::atomic compiling; - - std::atomic debugging; Gtk::Label debug_status_label; - std::mutex debug_start_mutex; std::pair > debug_stop; boost::filesystem::path debug_last_stop_file_path; std::mutex debug_stop_mutex; @@ -50,12 +45,6 @@ private: std::string debug_status; std::mutex debug_status_mutex; Glib::Dispatcher debug_update_status; - - Tooltips debug_variable_tooltips; - - std::unique_ptr get_cmake(); - std::unordered_map project_run_arguments; - std::unordered_map debug_run_arguments; void configure(); void set_menu_actions();