From b23a2deec17d99a8f8a94498e58c21166d982ecc Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 28 Dec 2015 13:00:18 +0100 Subject: [PATCH 01/90] Work in progress: debug integration --- src/CMakeLists.txt | 4 ++ src/cmake.cc | 94 +++++++++++++++++++++++-- src/cmake.h | 18 +++-- src/config.cc | 1 + src/config.h | 1 + src/debug.cc | 86 +++++++++++++++++++++++ src/debug.h | 25 +++++++ src/files.h | 7 +- src/menu.cc | 16 +++++ src/notebook.cc | 15 ++++ src/source.cc | 9 ++- src/window.cc | 168 +++++++++++++++++++++++++++++++-------------- 12 files changed, 376 insertions(+), 68 deletions(-) create mode 100644 src/debug.cc create mode 100644 src/debug.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 86bb96a..25ea8dd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,7 @@ endif() INCLUDE(FindPkgConfig) find_package(LibClang REQUIRED) +string(REPLACE libclang liblldb LLDB_LIBRARIES "${LIBCLANG_LIBRARIES}") #find_package(PythonLibs 2.7) @@ -72,6 +73,8 @@ set(source_files juci.h cmake.h cmake.cc dialogs.cc + debug.h + debug.cc ../libclangmm/src/CodeCompleteResults.cc ../libclangmm/src/CompilationDatabase.cc @@ -136,6 +139,7 @@ target_link_libraries(${project_name} ${GTKSVMM_LIBRARIES} ${Boost_LIBRARIES} ${ASPELL_LIBRARIES} + ${LLDB_LIBRARIES} #${PYTHON_LIBRARIES} ) diff --git a/src/cmake.cc b/src/cmake.cc index 0d8ab02..21d6960 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -39,13 +39,13 @@ CMake::CMake(const boost::filesystem::path &path) { } } -boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::path &path) { +boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::path &project_path) { boost::filesystem::path default_build_path=Config::get().terminal.default_build_path; const std::string path_variable_project_directory_name=""; size_t pos=0; auto default_build_path_string=default_build_path.string(); - auto path_filename_string=path.filename().string(); + auto path_filename_string=project_path.filename().string(); while((pos=default_build_path_string.find(path_variable_project_directory_name, pos))!=std::string::npos) { default_build_path_string.replace(pos, path_variable_project_directory_name.size(), path_filename_string); pos+=path_filename_string.size(); @@ -54,7 +54,7 @@ boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::p default_build_path=default_build_path_string; if(default_build_path.is_relative()) - default_build_path=path/default_build_path; + default_build_path=project_path/default_build_path; if(!boost::filesystem::exists(default_build_path)) { boost::system::error_code ec; @@ -68,14 +68,55 @@ boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::p return default_build_path; } -bool CMake::create_compile_commands(const boost::filesystem::path &path) { - auto default_build_path=get_default_build_path(path); +boost::filesystem::path CMake::get_debug_build_path(const boost::filesystem::path &project_path) { + boost::filesystem::path debug_build_path=Config::get().terminal.debug_build_path; + + const std::string path_variable_project_directory_name=""; + size_t pos=0; + auto debug_build_path_string=debug_build_path.string(); + auto path_filename_string=project_path.filename().string(); + while((pos=debug_build_path_string.find(path_variable_project_directory_name, pos))!=std::string::npos) { + debug_build_path_string.replace(pos, path_variable_project_directory_name.size(), path_filename_string); + pos+=path_filename_string.size(); + } + if(pos!=0) + debug_build_path=debug_build_path_string; + + const std::string path_variable_default_build_path=""; + pos=0; + debug_build_path_string=debug_build_path.string(); + auto default_build_path=Config::get().terminal.default_build_path; + while((pos=debug_build_path_string.find(path_variable_default_build_path, pos))!=std::string::npos) { + debug_build_path_string.replace(pos, path_variable_default_build_path.size(), default_build_path); + pos+=default_build_path.size(); + } + if(pos!=0) + debug_build_path=debug_build_path_string; + + + if(debug_build_path.is_relative()) + debug_build_path=project_path/debug_build_path; + + if(!boost::filesystem::exists(debug_build_path)) { + boost::system::error_code ec; + boost::filesystem::create_directories(debug_build_path, ec); + if(ec) { + Terminal::get().print("Error: could not create "+debug_build_path.string()+": "+ec.message()+"\n", true); + return boost::filesystem::path(); + } + } + + return debug_build_path; +} + +bool CMake::create_compile_commands(const boost::filesystem::path &project_path) { + auto default_build_path=get_default_build_path(project_path); if(default_build_path.empty()) return false; 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+" "+ - path.string()+" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path); + project_path.string()+" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path); message.hide(); if(exit_status==EXIT_SUCCESS) { #ifdef _WIN32 //Temporary fix to MSYS2's libclang @@ -97,6 +138,47 @@ bool CMake::create_compile_commands(const boost::filesystem::path &path) { return false; } +bool CMake::create_debug_build(const boost::filesystem::path &project_path) { + auto debug_build_path=get_debug_build_path(project_path); + if(debug_build_path.empty()) + return false; + std::unique_ptr message; + 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+" "+ + project_path.string()+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path); + if(message) + message->hide(); + if(exit_status==EXIT_SUCCESS) + return true; + return false; +} + +boost::filesystem::path CMake::get_executable(const boost::filesystem::path &file_path) { + auto executables = get_functions_parameters("add_executable"); + + //Attempt to find executable based add_executable files and opened tab + boost::filesystem::path executable_path; + if(!file_path.empty()) { + for(auto &executable: executables) { + if(executable.second.size()>1) { + for(size_t c=1;c0 && executables[0].second.size()>0) + executable_path=executables[0].first.parent_path()/executables[0].second[0]; + + return executable_path; +} + void CMake::read_files() { for(auto &path: paths) files.emplace_back(filesystem::read(path)); diff --git a/src/cmake.h b/src/cmake.h index e995b23..e26c4cc 100644 --- a/src/cmake.h +++ b/src/cmake.h @@ -7,16 +7,20 @@ class CMake { public: CMake(const boost::filesystem::path &path); - std::vector > > get_functions_parameters(const std::string &name); - static boost::filesystem::path get_default_build_path(const boost::filesystem::path &path); - static bool create_compile_commands(const boost::filesystem::path &path); - + boost::filesystem::path project_path; std::vector paths; + + static boost::filesystem::path get_default_build_path(const boost::filesystem::path &project_path); + static boost::filesystem::path get_debug_build_path(const boost::filesystem::path &project_path); + static bool create_compile_commands(const boost::filesystem::path &project_path); + static bool create_debug_build(const boost::filesystem::path &project_path); + + boost::filesystem::path get_executable(const boost::filesystem::path &file_path); + + std::vector > > get_functions_parameters(const std::string &name); +private: std::vector files; - boost::filesystem::path project_path; std::unordered_map variables; -private: - void read_files(); void remove_tabs(); void remove_comments(); diff --git a/src/config.cc b/src/config.cc index 732344f..b04ec8a 100644 --- a/src/config.cc +++ b/src/config.cc @@ -86,6 +86,7 @@ void Config::retrieve_config() { window.default_size = {cfg.get("default_window_size.width"), cfg.get("default_window_size.height")}; terminal.default_build_path=cfg.get("project.default_build_path"); + terminal.debug_build_path=cfg.get("project.debug_build_path"); terminal.make_command=cfg.get("project.make_command"); terminal.cmake_command=cfg.get("project.cmake_command"); terminal.history_size=cfg.get("terminal_history_size"); diff --git a/src/config.h b/src/config.h index 6599c3a..8ebba6f 100644 --- a/src/config.h +++ b/src/config.h @@ -25,6 +25,7 @@ public: class Terminal { public: std::string default_build_path; + std::string debug_build_path; std::string cmake_command; std::string make_command; std::string clang_format_command; diff --git a/src/debug.cc b/src/debug.cc new file mode 100644 index 0000000..7dacc30 --- /dev/null +++ b/src/debug.cc @@ -0,0 +1,86 @@ +#include "debug.h" + +#include + +#include "lldb/API/SBTarget.h" +#include "lldb/API/SBProcess.h" +#include "lldb/API/SBListener.h" +#include "lldb/API/SBEvent.h" +#include "lldb/API/SBBreakpoint.h" +#include "lldb/API/SBThread.h" +#include "lldb/API/SBStream.h" + +#include //TODO: remove +using namespace std; + +void log(const char *msg, void *) { + cout << "debugger log: " << msg << endl; +} + +Debug::Debug() { + lldb::SBDebugger::Initialize(); + + debugger=lldb::SBDebugger::Create(true, log, nullptr); +} + +void Debug::start(const boost::filesystem::path &project_path, const boost::filesystem::path &executable, + const boost::filesystem::path &path, std::function callback) { + std::thread debug_thread([this, project_path, executable, path, callback]() { + auto target=debugger.CreateTarget(executable.string().c_str()); + auto listener=lldb::SBListener("juCi++ lldb listener"); + + if(!target.IsValid()) { + cerr << "Error: Could not create debug target to: " << executable << endl; //TODO: output to terminal instead + return; + } + + for(auto &breakpoint: breakpoints[project_path.string()]) { + if(!(target.BreakpointCreateByLocation(breakpoint.first.c_str(), breakpoint.second)).IsValid()) { + cerr << "Error: Could not create breakpoint at: " << breakpoint.first << ":" << breakpoint.second << endl; //TODO: fix output to terminal instead + return; + } + else + cerr << "Created breakpoint at: " << breakpoint.first << ":" << breakpoint.second << endl; + } + + lldb::SBError error; + auto process = target.Launch(listener, nullptr, nullptr, nullptr, nullptr, nullptr, path.string().c_str(), lldb::eLaunchFlagNone, false, error); + + if(error.Fail()) { + cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead + return; + } + + //Wait till stopped. TODO: add check if process.GetStateFromEvent(event)==lldb::StateType::eStateStopped after + lldb::SBEvent event; + while(listener.WaitForEvent(3, event) && process.GetStateFromEvent(event)!=lldb::StateType::eStateStopped) {} + + cout << "NumThreads: " << process.GetNumThreads() << endl; + for(uint32_t thread_index_id=0;thread_index_id +#include +#include "lldb/API/SBDebugger.h" + +class Debug { +private: + Debug(); +public: + static Debug &get() { + static Debug singleton; + return singleton; + } + + void start(const boost::filesystem::path &project_path, const boost::filesystem::path &executable, const boost::filesystem::path &path="", std::function callback=nullptr); + + std::unordered_map > > breakpoints; + +private: + lldb::SBDebugger debugger; +}; + +#endif diff --git a/src/files.h b/src/files.h index 1400e0f..945a2ba 100644 --- a/src/files.h +++ b/src/files.h @@ -2,7 +2,7 @@ #define JUCI_FILES_H_ #include -#define JUCI_VERSION "1.0.1" +#define JUCI_VERSION "1.0.2" const std::string configjson = "{\n" @@ -94,9 +94,12 @@ const std::string configjson = " \"source_apply_fix_its\": \"space\",\n" " \"compile_and_run\": \"Return\",\n" " \"compile\": \"Return\",\n" +" \"compile_and_run\": \"Return\",\n" " \"run_command\": \"Return\",\n" " \"kill_last_running\": \"Escape\",\n" " \"force_kill_last_running\": \"Escape\",\n" +" \"debug_start\": \"y\",\n" +" \"debug_toggle_breakpoint\": \"b\",\n" #ifdef __linux " \"next_tab\": \"Tab\",\n" " \"previous_tab\": \"Tab\",\n" @@ -109,6 +112,8 @@ const std::string configjson = " \"project\": {\n" " \"default_build_path_comment\": \"Use to insert the project top level directory name\",\n" " \"default_build_path\": \"./build\",\n" +" \"debug_build_path_comment\": \"Use to insert the project top level directory name, and to insert your default_build_path setting.\",\n" +" \"debug_build_path\": \"/debug\",\n" #ifdef _WIN32 " \"cmake_command\": \"cmake -G\\\"MSYS Makefiles\\\" -DCMAKE_INSTALL_PREFIX="+JUCI_CMAKE_INSTALL_PREFIX+"\",\n" #else diff --git a/src/menu.cc b/src/menu.cc index 36e23a7..ddc6f45 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -269,6 +269,22 @@ Menu::Menu() { " " "" " " + " _Debug" + "
" + " " + " _Start" + " app.debug_start" + +accels["debug_start"]+ //For Ubuntu... + " " + " " + " _Toggle _Breakpoint" + " app.debug_toggle_breakpoint" + +accels["debug_toggle_breakpoint"]+ //For Ubuntu... + " " + "
" + "
" + "" + " " " _Window" "
" " " diff --git a/src/notebook.cc b/src/notebook.cc index f42f022..88ee923 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -6,6 +6,7 @@ #include #include "cmake.h" #include "filesystem.h" +#include "debug.h" #if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 17 #include "gtksourceview-3.0/gtksourceview/gtksourcemap.h" @@ -307,7 +308,21 @@ bool Notebook::close(int page) { #if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 17 source_maps.erase(source_maps.begin()+index); #endif + auto source_view=source_views.at(index); + + //Remove breakpoints + auto it=Debug::get().breakpoints.find(source_view->project_path.string()); + if(it!=Debug::get().breakpoints.end()) { + auto filename=source_view->file_path.filename().string(); + for(auto it_bp=it->second.begin();it_bp!=it->second.end();) { + if(it_bp->first==filename) + it_bp=it->second.erase(it_bp); + else + it_bp++; + } + } + if(auto source_clang_view=dynamic_cast(source_view)) source_clang_view->async_delete(); else diff --git a/src/source.cc b/src/source.cc index 97413e7..88e5d30 100644 --- a/src/source.cc +++ b/src/source.cc @@ -121,7 +121,14 @@ Source::View::View(const boost::filesystem::path &file_path, const boost::filesy spellcheck_checker=NULL; auto tag=get_buffer()->create_tag("spellcheck_error"); tag->property_underline()=Pango::Underline::UNDERLINE_ERROR; - + + auto mark_attr=Gsv::MarkAttributes::create(); + Gdk::RGBA rgba; + rgba.set_red(1.0); + rgba.set_alpha(0.1); + mark_attr->set_background(rgba); + set_mark_attributes("breakpoint", mark_attr, 100); + get_buffer()->signal_changed().connect([this](){ if(spellcheck_checker==NULL) return; diff --git a/src/window.cc b/src/window.cc index 38896f4..761a515 100644 --- a/src/window.cc +++ b/src/window.cc @@ -6,6 +6,7 @@ //#include "api.h" #include "dialogs.h" #include "filesystem.h" +#include "debug.h" //TODO: remove namespace sigc { #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE @@ -516,64 +517,45 @@ void Window::set_menu_actions() { if(cmake_path.empty()) return; CMake cmake(cmake_path); - auto executables = cmake.get_functions_parameters("add_executable"); + if(cmake.project_path.empty()) + return; + auto executable_path=cmake.get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:""); - //Attempt to find executable based add_executable files and opened tab - boost::filesystem::path executable_path; - if(notebook.get_current_page()!=-1) { - for(auto &executable: executables) { - if(executable.second.size()>1) { - for(size_t c=1;cfile_path.filename()) { - executable_path=executable.first.parent_path()/executable.second[0]; - break; + if(executable_path!="") { + auto project_path=cmake.project_path; + auto default_build_path=CMake::get_default_build_path(project_path); + if(default_build_path.empty()) + return; + compiling=true; + auto executable_path_string=executable_path.string(); + size_t pos=executable_path_string.find(project_path.string()); + if(pos!=std::string::npos) { + executable_path_string.replace(pos, project_path.string().size(), default_build_path.string()); + executable_path=executable_path_string; + } + Terminal::get().print("Compiling and running "+executable_path.string()+"\n"); + Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this, executable_path, default_build_path](int exit_status){ + compiling=false; + if(exit_status==EXIT_SUCCESS) { + auto executable_path_spaces_fixed=executable_path.string(); + char last_char=0; + for(size_t c=0;c0 && executables[0].second.size()>0) - executable_path=executables[0].first.parent_path()/executables[0].second[0]; - - if(cmake.project_path!="") { - if(executable_path!="") { - auto project_path=cmake.project_path; - auto default_build_path=CMake::get_default_build_path(project_path); - if(default_build_path.empty()) - return; - compiling=true; - auto executable_path_string=executable_path.string(); - size_t pos=executable_path_string.find(project_path.string()); - if(pos!=std::string::npos) { - executable_path_string.replace(pos, project_path.string().size(), default_build_path.string()); - executable_path=executable_path_string; - } - Terminal::get().print("Compiling and running "+executable_path.string()+"\n"); - Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this, executable_path, default_build_path](int exit_status){ - compiling=false; - if(exit_status==EXIT_SUCCESS) { - auto executable_path_spaces_fixed=executable_path.string(); - char last_char=0; - for(size_t c=0;cfile_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_path=cmake.get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:""); + + if(executable_path!="") { + 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; + compiling=true; + auto executable_path_string=executable_path.string(); + size_t pos=executable_path_string.find(project_path.string()); + if(pos!=std::string::npos) { + executable_path_string.replace(pos, project_path.string().size(), debug_build_path.string()); + executable_path=executable_path_string; + } + Terminal::get().print("Compiling and running "+executable_path.string()+"\n"); + Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, project_path, executable_path, debug_build_path](int exit_status){ + compiling=false; + if(exit_status==EXIT_SUCCESS) { + auto executable_path_spaces_fixed=executable_path.string(); + char last_char=0; + for(size_t c=0;cproject_path.string(); + auto filename=view->file_path.filename().string(); + auto line_nr=view->get_buffer()->get_insert()->get_iter().get_line()+1; + + auto it=Debug::get().breakpoints.find(project_path_string); + if(it!=Debug::get().breakpoints.end()) { + for(auto it_bp=it->second.begin();it_bp!=it->second.end();it_bp++) { + if(it_bp->first==filename && it_bp->second==line_nr) { + //Remove breakpoint + it->second.erase(it_bp); + auto start_iter=view->get_buffer()->get_iter_at_line(line_nr-1); + auto end_iter=start_iter; + while(!end_iter.ends_line() && end_iter.forward_char()) {} + view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "breakpoint"); + return; + } + } + } + Debug::get().breakpoints[project_path_string].emplace_back(filename, line_nr); + auto mark=view->get_source_buffer()->create_source_mark("breakpoint", view->get_buffer()->get_insert()->get_iter()); + } + }); + menu.add_action("next_tab", [this]() { if(notebook.get_current_page()!=-1) { notebook.open(notebook.get_view((notebook.get_current_page()+1)%notebook.size())->file_path); From a6b19c9dbd9aa2aa18b6441a17180f94be18b190 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 28 Dec 2015 13:46:43 +0100 Subject: [PATCH 02/90] Work in progress, a somewhat usable debugger now implemented --- src/debug.cc | 79 ++++++++++++++++++++++++++++++++------------------- src/debug.h | 4 +++ src/files.h | 1 + src/menu.cc | 9 ++++++ src/window.cc | 7 ++++- 5 files changed, 69 insertions(+), 31 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 7dacc30..df21394 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -17,7 +17,7 @@ void log(const char *msg, void *) { cout << "debugger log: " << msg << endl; } -Debug::Debug() { +Debug::Debug(): stopped(false) { lldb::SBDebugger::Initialize(); debugger=lldb::SBDebugger::Create(true, log, nullptr); @@ -36,7 +36,7 @@ void Debug::start(const boost::filesystem::path &project_path, const boost::file for(auto &breakpoint: breakpoints[project_path.string()]) { if(!(target.BreakpointCreateByLocation(breakpoint.first.c_str(), breakpoint.second)).IsValid()) { - cerr << "Error: Could not create breakpoint at: " << breakpoint.first << ":" << breakpoint.second << endl; //TODO: fix output to terminal instead + cerr << "Error: Could not create breakpoint at: " << breakpoint.first << ":" << breakpoint.second << endl; //TODO: output to terminal instead return; } else @@ -44,43 +44,62 @@ void Debug::start(const boost::filesystem::path &project_path, const boost::file } lldb::SBError error; - auto process = target.Launch(listener, nullptr, nullptr, nullptr, nullptr, nullptr, path.string().c_str(), lldb::eLaunchFlagNone, false, error); + process = std::unique_ptr(new lldb::SBProcess(target.Launch(listener, nullptr, nullptr, nullptr, nullptr, nullptr, path.string().c_str(), lldb::eLaunchFlagNone, false, error))); if(error.Fail()) { cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead return; } - - //Wait till stopped. TODO: add check if process.GetStateFromEvent(event)==lldb::StateType::eStateStopped after + lldb::SBEvent event; - while(listener.WaitForEvent(3, event) && process.GetStateFromEvent(event)!=lldb::StateType::eStateStopped) {} - - cout << "NumThreads: " << process.GetNumThreads() << endl; - for(uint32_t thread_index_id=0;thread_index_idGetStateFromEvent(event); + bool expected=false; + if(state==lldb::StateType::eStateStopped && stopped.compare_exchange_strong(expected, true)) { + cout << "NumThreads: " << process->GetNumThreads() << endl; + for(uint32_t thread_index_id=0;thread_index_idGetNumThreads();thread_index_id++) { + auto thread=process->GetThreadAtIndex(thread_index_id); + cout << "NumFrames: " << thread.GetNumFrames() << endl; + for(uint32_t frame_index=0;frame_indexGetExitStatus(); + if(callback) + callback(exit_status); + process.reset(); + stopped=false; + return; + } + + else if(state==lldb::StateType::eStateCrashed) { + if(callback) + callback(-1); + process.reset(); + stopped=false; + return; } } + this_thread::sleep_for(std::chrono::milliseconds(200)); } - - process.Continue(); - - //Get exit status. TODO: add check if process.GetStateFromEvent(event)==lldb::StateType::eStateExited after - while(listener.WaitForEvent(3, event) && process.GetStateFromEvent(event)!=lldb::StateType::eStateExited) {} - auto exit_status=process.GetExitStatus(); - - if(callback) - callback(exit_status); }); debug_thread.detach(); } + +void Debug::continue_debug() { + bool expected=true; + if(stopped.compare_exchange_strong(expected, false)) + process->Continue(); +} diff --git a/src/debug.h b/src/debug.h index 59de421..cd18a21 100644 --- a/src/debug.h +++ b/src/debug.h @@ -4,6 +4,7 @@ #include #include #include "lldb/API/SBDebugger.h" +#include "lldb/API/SBProcess.h" class Debug { private: @@ -15,11 +16,14 @@ public: } void start(const boost::filesystem::path &project_path, const boost::filesystem::path &executable, const boost::filesystem::path &path="", std::function callback=nullptr); + void continue_debug(); //can't use continue as function name std::unordered_map > > breakpoints; private: lldb::SBDebugger debugger; + std::unique_ptr process; + std::atomic stopped; }; #endif diff --git a/src/files.h b/src/files.h index 945a2ba..91f2239 100644 --- a/src/files.h +++ b/src/files.h @@ -99,6 +99,7 @@ const std::string configjson = " \"kill_last_running\": \"Escape\",\n" " \"force_kill_last_running\": \"Escape\",\n" " \"debug_start\": \"y\",\n" +" \"debug_continue\": \"y\",\n" " \"debug_toggle_breakpoint\": \"b\",\n" #ifdef __linux " \"next_tab\": \"Tab\",\n" diff --git a/src/menu.cc b/src/menu.cc index ddc6f45..a3e8c32 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -276,6 +276,15 @@ Menu::Menu() { " app.debug_start" +accels["debug_start"]+ //For Ubuntu... " " + "
" + "
" + " " + " _Continue" + " app.debug_continue" + +accels["debug_continue"]+ //For Ubuntu... + " " + "
" + "
" " " " _Toggle _Breakpoint" " app.debug_toggle_breakpoint" diff --git a/src/window.cc b/src/window.cc index 761a515..fa7f955 100644 --- a/src/window.cc +++ b/src/window.cc @@ -6,7 +6,7 @@ //#include "api.h" #include "dialogs.h" #include "filesystem.h" -#include "debug.h" //TODO: remove +#include "debug.h" namespace sigc { #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE @@ -695,6 +695,11 @@ void Window::set_menu_actions() { auto mark=view->get_source_buffer()->create_source_mark("breakpoint", view->get_buffer()->get_insert()->get_iter()); } }); + menu.add_action("debug_continue", [this]() { + if(notebook.get_current_page()!=-1) { + Debug::get().continue_debug(); + } + }); menu.add_action("next_tab", [this]() { if(notebook.get_current_page()!=-1) { From 3244ec68f72182c7f9b8c095230034eb0191aa11 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 28 Dec 2015 18:40:52 +0100 Subject: [PATCH 03/90] Debug variables now in tooltips, still some work left before creating the debug integration branch though --- src/debug.cc | 56 ++++++++++++++++++++++++++++++++++++++------- src/debug.h | 3 +++ src/files.h | 1 + src/menu.cc | 5 ++++ src/source_clang.cc | 9 ++++++++ src/window.cc | 23 +++++++++++-------- src/window.h | 1 + 7 files changed, 81 insertions(+), 17 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index df21394..e79ca82 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -9,6 +9,7 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBStream.h" +#include "lldb/API/SBDeclaration.h" #include //TODO: remove using namespace std; @@ -57,19 +58,28 @@ void Debug::start(const boost::filesystem::path &project_path, const boost::file auto state=process->GetStateFromEvent(event); bool expected=false; if(state==lldb::StateType::eStateStopped && stopped.compare_exchange_strong(expected, true)) { - cout << "NumThreads: " << process->GetNumThreads() << endl; - for(uint32_t thread_index_id=0;thread_index_idGetNumThreads();thread_index_id++) { - auto thread=process->GetThreadAtIndex(thread_index_id); - cout << "NumFrames: " << thread.GetNumFrames() << endl; + for(uint32_t thread_index=0;thread_indexGetNumThreads();thread_index++) { + auto thread=process->GetThreadAtIndex(thread_index); for(uint32_t frame_index=0;frame_indexKill(); + if(error.Fail()) { + cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead + return; + } +} + void Debug::continue_debug() { bool expected=true; if(stopped.compare_exchange_strong(expected, false)) process->Continue(); } + +std::string Debug::get_value(const std::string &variable) { + if(stopped) { + for(uint32_t thread_index=0;thread_indexGetNumThreads();thread_index++) { + auto thread=process->GetThreadAtIndex(thread_index); + for(uint32_t frame_index=0;frame_index callback=nullptr); + void stop(); void continue_debug(); //can't use continue as function name + std::string get_value(const std::string &variable); + std::unordered_map > > breakpoints; private: diff --git a/src/files.h b/src/files.h index 91f2239..ef12530 100644 --- a/src/files.h +++ b/src/files.h @@ -99,6 +99,7 @@ const std::string configjson = " \"kill_last_running\": \"Escape\",\n" " \"force_kill_last_running\": \"Escape\",\n" " \"debug_start\": \"y\",\n" +" \"debug_stop\": \"\",\n" " \"debug_continue\": \"y\",\n" " \"debug_toggle_breakpoint\": \"b\",\n" #ifdef __linux diff --git a/src/menu.cc b/src/menu.cc index a3e8c32..21e19ac 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -276,6 +276,11 @@ Menu::Menu() { " app.debug_start" +accels["debug_start"]+ //For Ubuntu... " " + " " + " _Stop" + " app.debug_stop" + +accels["debug_stop"]+ //For Ubuntu... + " " "
" "
" " " diff --git a/src/source_clang.cc b/src/source_clang.cc index 8180d53..68dd90d 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -2,6 +2,7 @@ #include "config.h" #include "terminal.h" #include "cmake.h" +#include "debug.h" namespace sigc { #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE @@ -412,6 +413,14 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) auto brief_comment=token.get_cursor().get_brief_comments(); if(brief_comment!="") tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\n"+brief_comment, "def:note"); + auto debug_value=Debug::get().get_value(token.get_spelling()); + if(!debug_value.empty()) { + debug_value.pop_back(); + size_t pos=debug_value.find(" = "); + if(pos!=std::string::npos) + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\nDebug: "+debug_value.substr(pos+3), "def:note"); + } + return tooltip_buffer; }; diff --git a/src/window.cc b/src/window.cc index fa7f955..9f3dfd8 100644 --- a/src/window.cc +++ b/src/window.cc @@ -22,7 +22,7 @@ namespace sigc { #endif } -Window::Window() : compiling(false) { +Window::Window() : compiling(false), debugging(false) { JDEBUG("start"); set_title("juCi++"); set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK|Gdk::LEAVE_NOTIFY_MASK); @@ -617,7 +617,7 @@ void Window::set_menu_actions() { }); menu.add_action("debug_start", [this](){ - if(compiling) + if(debugging) return; boost::filesystem::path cmake_path; if(notebook.get_current_page()!=-1) @@ -638,7 +638,7 @@ void Window::set_menu_actions() { return; if(!CMake::create_debug_build(project_path)) return; - compiling=true; + debugging=true; auto executable_path_string=executable_path.string(); size_t pos=executable_path_string.find(project_path.string()); if(pos!=std::string::npos) { @@ -647,7 +647,6 @@ void Window::set_menu_actions() { } Terminal::get().print("Compiling and running "+executable_path.string()+"\n"); Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, project_path, executable_path, debug_build_path](int exit_status){ - compiling=false; if(exit_status==EXIT_SUCCESS) { auto executable_path_spaces_fixed=executable_path.string(); char last_char=0; @@ -659,6 +658,7 @@ void Window::set_menu_actions() { last_char=executable_path_spaces_fixed[c]; } Debug::get().start(project_path, executable_path_spaces_fixed, debug_build_path, [this, executable_path](int exit_status){ + debugging=false; Terminal::get().async_print(executable_path.string()+" returned: "+std::to_string(exit_status)+'\n'); }); } @@ -670,6 +670,16 @@ void Window::set_menu_actions() { Terminal::get().print(" "+path.string()+"\n"); } }); + menu.add_action("debug_stop", [this]() { + if(debugging) { + Debug::get().stop(); + } + }); + menu.add_action("debug_continue", [this]() { + if(notebook.get_current_page()!=-1 && debugging) { + Debug::get().continue_debug(); + } + }); menu.add_action("debug_toggle_breakpoint", [this](){ if(notebook.get_current_page()!=-1) { auto view=notebook.get_current_view(); @@ -695,11 +705,6 @@ void Window::set_menu_actions() { auto mark=view->get_source_buffer()->create_source_mark("breakpoint", view->get_buffer()->get_insert()->get_iter()); } }); - menu.add_action("debug_continue", [this]() { - if(notebook.get_current_page()!=-1) { - Debug::get().continue_debug(); - } - }); menu.add_action("next_tab", [this]() { if(notebook.get_current_page()!=-1) { diff --git a/src/window.h b/src/window.h index 2587348..45a592d 100644 --- a/src/window.h +++ b/src/window.h @@ -32,6 +32,7 @@ private: Gtk::AboutDialog about; EntryBox entry_box; std::atomic compiling; + std::atomic debugging; void configure(); void set_menu_actions(); From b30f2da8a4fade44ddb60f099663097244e32c88 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 28 Dec 2015 21:38:01 +0100 Subject: [PATCH 04/90] Debugging fixes --- src/debug.cc | 8 ++++---- src/debug.h | 4 +--- src/notebook.cc | 13 ------------- src/window.cc | 50 ++++++++++++++++++++++++++++++------------------- 4 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index e79ca82..ca4db81 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -24,9 +24,9 @@ Debug::Debug(): stopped(false) { debugger=lldb::SBDebugger::Create(true, log, nullptr); } -void Debug::start(const boost::filesystem::path &project_path, const boost::filesystem::path &executable, +void Debug::start(std::shared_ptr > > breakpoints, const boost::filesystem::path &executable, const boost::filesystem::path &path, std::function callback) { - std::thread debug_thread([this, project_path, executable, path, callback]() { + std::thread debug_thread([this, breakpoints, executable, path, callback]() { auto target=debugger.CreateTarget(executable.string().c_str()); auto listener=lldb::SBListener("juCi++ lldb listener"); @@ -35,8 +35,8 @@ void Debug::start(const boost::filesystem::path &project_path, const boost::file return; } - for(auto &breakpoint: breakpoints[project_path.string()]) { - if(!(target.BreakpointCreateByLocation(breakpoint.first.c_str(), breakpoint.second)).IsValid()) { + for(auto &breakpoint: *breakpoints) { + if(!(target.BreakpointCreateByLocation(breakpoint.first.string().c_str(), breakpoint.second)).IsValid()) { cerr << "Error: Could not create breakpoint at: " << breakpoint.first << ":" << breakpoint.second << endl; //TODO: output to terminal instead return; } diff --git a/src/debug.h b/src/debug.h index 971338a..7b4356c 100644 --- a/src/debug.h +++ b/src/debug.h @@ -15,14 +15,12 @@ public: return singleton; } - void start(const boost::filesystem::path &project_path, const boost::filesystem::path &executable, const boost::filesystem::path &path="", std::function callback=nullptr); + void start(std::shared_ptr > > breakpoints, const boost::filesystem::path &executable, const boost::filesystem::path &path="", std::function callback=nullptr); void stop(); void continue_debug(); //can't use continue as function name std::string get_value(const std::string &variable); - std::unordered_map > > breakpoints; - private: lldb::SBDebugger debugger; std::unique_ptr process; diff --git a/src/notebook.cc b/src/notebook.cc index 88ee923..744459b 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -310,19 +310,6 @@ bool Notebook::close(int page) { #endif auto source_view=source_views.at(index); - - //Remove breakpoints - auto it=Debug::get().breakpoints.find(source_view->project_path.string()); - if(it!=Debug::get().breakpoints.end()) { - auto filename=source_view->file_path.filename().string(); - for(auto it_bp=it->second.begin();it_bp!=it->second.end();) { - if(it_bp->first==filename) - it_bp=it->second.erase(it_bp); - else - it_bp++; - } - } - if(auto source_clang_view=dynamic_cast(source_view)) source_clang_view->async_delete(); else diff --git a/src/window.cc b/src/window.cc index 9f3dfd8..c4ac90d 100644 --- a/src/window.cc +++ b/src/window.cc @@ -645,8 +645,29 @@ void Window::set_menu_actions() { executable_path_string.replace(pos, project_path.string().size(), debug_build_path.string()); executable_path=executable_path_string; } + + 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, "breakpoint").size()>0) + breakpoints->emplace_back(view->file_path.filename(), iter.get_line()+1); + while(view->get_source_buffer()->forward_iter_to_source_mark(iter, "breakpoint")) + breakpoints->emplace_back(view->file_path.filename(), iter.get_line()+1); + } + } + /*for(int c=0;cproject_path) { + for(int line_nr=0;line_nrget_buffer()->get_line_count();line_nr++) { + //if(view->get_source_buffer()->get_source_marks_at_line(line_nr, "breakpoint").size()>0) + // breakpoints->emplace_back(view->file_path.filename(), line_nr+1); + } + } + }*/ Terminal::get().print("Compiling and running "+executable_path.string()+"\n"); - Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, project_path, executable_path, debug_build_path](int exit_status){ + Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, breakpoints, executable_path, debug_build_path](int exit_status){ if(exit_status==EXIT_SUCCESS) { auto executable_path_spaces_fixed=executable_path.string(); char last_char=0; @@ -657,7 +678,8 @@ void Window::set_menu_actions() { } last_char=executable_path_spaces_fixed[c]; } - Debug::get().start(project_path, executable_path_spaces_fixed, debug_build_path, [this, executable_path](int exit_status){ + + Debug::get().start(breakpoints, executable_path_spaces_fixed, debug_build_path, [this, executable_path](int exit_status){ debugging=false; Terminal::get().async_print(executable_path.string()+" returned: "+std::to_string(exit_status)+'\n'); }); @@ -683,26 +705,16 @@ void Window::set_menu_actions() { menu.add_action("debug_toggle_breakpoint", [this](){ if(notebook.get_current_page()!=-1) { auto view=notebook.get_current_view(); - auto &project_path_string=view->project_path.string(); - auto filename=view->file_path.filename().string(); auto line_nr=view->get_buffer()->get_insert()->get_iter().get_line()+1; - auto it=Debug::get().breakpoints.find(project_path_string); - if(it!=Debug::get().breakpoints.end()) { - for(auto it_bp=it->second.begin();it_bp!=it->second.end();it_bp++) { - if(it_bp->first==filename && it_bp->second==line_nr) { - //Remove breakpoint - it->second.erase(it_bp); - auto start_iter=view->get_buffer()->get_iter_at_line(line_nr-1); - auto end_iter=start_iter; - while(!end_iter.ends_line() && end_iter.forward_char()) {} - view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "breakpoint"); - return; - } - } + if(view->get_source_buffer()->get_source_marks_at_line(line_nr-1, "breakpoint").size()>0) { + auto start_iter=view->get_buffer()->get_iter_at_line(line_nr-1); + auto end_iter=start_iter; + while(!end_iter.ends_line() && end_iter.forward_char()) {} + view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "breakpoint"); } - Debug::get().breakpoints[project_path_string].emplace_back(filename, line_nr); - auto mark=view->get_source_buffer()->create_source_mark("breakpoint", view->get_buffer()->get_insert()->get_iter()); + else + view->get_source_buffer()->create_source_mark("breakpoint", view->get_buffer()->get_insert()->get_iter()); } }); From 8905f8fc757f55fac35f50c4780bbc9b587b4ee5 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 29 Dec 2015 12:35:04 +0100 Subject: [PATCH 05/90] Added debug status and now shows the line where the debug process is stopped --- src/debug.cc | 88 ++++++++++++++++++++++++++++++++++++--------------- src/debug.h | 9 ++++-- src/files.h | 6 ++-- src/menu.cc | 11 +++++-- src/source.cc | 11 +++++-- src/window.cc | 62 +++++++++++++++++++++++++----------- src/window.h | 3 ++ 7 files changed, 135 insertions(+), 55 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index ca4db81..b3ed6e3 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -25,8 +25,10 @@ Debug::Debug(): stopped(false) { } void Debug::start(std::shared_ptr > > breakpoints, const boost::filesystem::path &executable, - const boost::filesystem::path &path, std::function callback) { - std::thread debug_thread([this, breakpoints, executable, path, callback]() { + const boost::filesystem::path &path, std::function callback, + std::function status_callback, + std::function stop_callback) { + std::thread debug_thread([this, breakpoints, executable, path, callback, status_callback, stop_callback]() { auto target=debugger.CreateTarget(executable.string().c_str()); auto listener=lldb::SBListener("juCi++ lldb listener"); @@ -40,8 +42,6 @@ void Debug::start(std::shared_ptrGetStateFromEvent(event); + + //Update debug status + lldb::SBStream stream; + event.GetDescription(stream); + std::string event_desc=stream.GetData(); + event_desc.pop_back(); + auto pos=event_desc.rfind(" = "); + if(status_callback && pos!=std::string::npos) + status_callback(event_desc.substr(pos+3)); + bool expected=false; if(state==lldb::StateType::eStateStopped && stopped.compare_exchange_strong(expected, true)) { + auto line_entry=process->GetSelectedThread().GetSelectedFrame().GetLineEntry(); + if(stop_callback) { + lldb::SBStream stream; + line_entry.GetFileSpec().GetDescription(stream); + stop_callback(stream.GetData(), line_entry.GetLine()); + } + + /*lldb::SBStream stream; + process->GetSelectedThread().GetDescription(stream); + cout << stream.GetData() << endl;*/ for(uint32_t thread_index=0;thread_indexGetNumThreads();thread_index++) { auto thread=process->GetThreadAtIndex(thread_index); for(uint32_t frame_index=0;frame_indexGetDescription(stream); + cout << stream.GetData() << endl; + + stream.Clear(); + process->GetSelectedThread().GetSelectedFrame().GetLineEntry().GetDescription(stream); + cout << stream.GetData() << endl;*/ + /*lldb::SBStream stream; auto value=values.GetValueAtIndex(value_index); cout << value.GetFrame().GetSymbol().GetName() << endl; @@ -79,7 +106,7 @@ void Debug::start(std::shared_ptrGetExitStatus(); if(callback) callback(exit_status); + if(status_callback) + status_callback(""); + if(stop_callback) + stop_callback("", 0); process.reset(); stopped=false; return; @@ -97,6 +128,10 @@ void Debug::start(std::shared_ptrContinue(); +} + void Debug::stop() { - auto error=process->Kill(); + auto error=process->Stop(); if(error.Fail()) { cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead return; } } -void Debug::continue_debug() { - bool expected=true; - if(stopped.compare_exchange_strong(expected, false)) - process->Continue(); +void Debug::kill() { + auto error=process->Kill(); + if(error.Fail()) { + cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead + return; + } } std::string Debug::get_value(const std::string &variable) { if(stopped) { - for(uint32_t thread_index=0;thread_indexGetNumThreads();thread_index++) { - auto thread=process->GetThreadAtIndex(thread_index); - for(uint32_t frame_index=0;frame_indexGetSelectedThread().GetSelectedFrame(); + auto values=frame.GetVariables(false, true, false, false); + for(uint32_t value_index=0;value_index > > breakpoints, const boost::filesystem::path &executable, const boost::filesystem::path &path="", std::function callback=nullptr); - void stop(); + void start(std::shared_ptr > > breakpoints, + const boost::filesystem::path &executable, const boost::filesystem::path &path="", + std::function callback=nullptr, + std::function status_callback=nullptr, + std::function stop_callback=nullptr); void continue_debug(); //can't use continue as function name + void stop(); + void kill(); std::string get_value(const std::string &variable); diff --git a/src/files.h b/src/files.h index ef12530..8628b56 100644 --- a/src/files.h +++ b/src/files.h @@ -98,9 +98,9 @@ const std::string configjson = " \"run_command\": \"Return\",\n" " \"kill_last_running\": \"Escape\",\n" " \"force_kill_last_running\": \"Escape\",\n" -" \"debug_start\": \"y\",\n" -" \"debug_stop\": \"\",\n" -" \"debug_continue\": \"y\",\n" +" \"debug_start_continue\": \"y\",\n" +" \"debug_stop\": \"y\",\n" +" \"debug_kill\": \"k\",\n" " \"debug_toggle_breakpoint\": \"b\",\n" #ifdef __linux " \"next_tab\": \"Tab\",\n" diff --git a/src/menu.cc b/src/menu.cc index 21e19ac..1fccdeb 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -272,15 +272,20 @@ Menu::Menu() { " _Debug" "
" " " - " _Start" - " app.debug_start" - +accels["debug_start"]+ //For Ubuntu... + " _Start/_Continue" + " app.debug_start_continue" + +accels["debug_start_continue"]+ //For Ubuntu... " " " " " _Stop" " app.debug_stop" +accels["debug_stop"]+ //For Ubuntu... " " + " " + " _Kill" + " app.debug_kill" + +accels["debug_kill"]+ //For Ubuntu... + " " "
" "
" " " diff --git a/src/source.cc b/src/source.cc index 88e5d30..d8fa996 100644 --- a/src/source.cc +++ b/src/source.cc @@ -122,12 +122,17 @@ Source::View::View(const boost::filesystem::path &file_path, const boost::filesy auto tag=get_buffer()->create_tag("spellcheck_error"); tag->property_underline()=Pango::Underline::UNDERLINE_ERROR; - auto mark_attr=Gsv::MarkAttributes::create(); + auto mark_attr_debug_breakpoint=Gsv::MarkAttributes::create(); Gdk::RGBA rgba; rgba.set_red(1.0); rgba.set_alpha(0.1); - mark_attr->set_background(rgba); - set_mark_attributes("breakpoint", mark_attr, 100); + mark_attr_debug_breakpoint->set_background(rgba); + set_mark_attributes("debug_breakpoint", mark_attr_debug_breakpoint, 100); + auto mark_attr_debug_stop=Gsv::MarkAttributes::create(); + rgba.set_red(0.0); + rgba.set_blue(1.0); + mark_attr_debug_stop->set_background(rgba); + set_mark_attributes("debug_stop", mark_attr_debug_stop, 100); get_buffer()->signal_changed().connect([this](){ if(spellcheck_checker==NULL) diff --git a/src/window.cc b/src/window.cc index c4ac90d..64cfabc 100644 --- a/src/window.cc +++ b/src/window.cc @@ -47,6 +47,7 @@ Window::Window() : compiling(false), debugging(false) { terminal_vbox.pack_start(terminal_scrolled_window); info_and_status_hbox.pack_start(notebook.info, Gtk::PACK_SHRINK); + info_and_status_hbox.set_center_widget(debug_status); info_and_status_hbox.pack_end(notebook.status, Gtk::PACK_SHRINK); terminal_vbox.pack_end(info_and_status_hbox, Gtk::PACK_SHRINK); vpaned.pack2(terminal_vbox, true, true); @@ -616,9 +617,14 @@ void Window::set_menu_actions() { Terminal::get().kill_last_async_process(true); }); - menu.add_action("debug_start", [this](){ - if(debugging) + menu.add_action("debug_start_continue", [this](){ + if(debugging) { + //Continue + if(notebook.get_current_page()!=-1) { + Debug::get().continue_debug(); + } return; + } boost::filesystem::path cmake_path; if(notebook.get_current_page()!=-1) cmake_path=notebook.get_current_view()->file_path.parent_path(); @@ -651,21 +657,12 @@ void Window::set_menu_actions() { auto view=notebook.get_view(c); if(project_path==view->project_path) { auto iter=view->get_buffer()->begin(); - if(view->get_source_buffer()->get_source_marks_at_iter(iter, "breakpoint").size()>0) + if(view->get_source_buffer()->get_source_marks_at_iter(iter, "debug_breakpoint").size()>0) breakpoints->emplace_back(view->file_path.filename(), iter.get_line()+1); - while(view->get_source_buffer()->forward_iter_to_source_mark(iter, "breakpoint")) + while(view->get_source_buffer()->forward_iter_to_source_mark(iter, "debug_breakpoint")) breakpoints->emplace_back(view->file_path.filename(), iter.get_line()+1); } } - /*for(int c=0;cproject_path) { - for(int line_nr=0;line_nrget_buffer()->get_line_count();line_nr++) { - //if(view->get_source_buffer()->get_source_marks_at_line(line_nr, "breakpoint").size()>0) - // breakpoints->emplace_back(view->file_path.filename(), line_nr+1); - } - } - }*/ Terminal::get().print("Compiling and running "+executable_path.string()+"\n"); Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, breakpoints, executable_path, debug_build_path](int exit_status){ if(exit_status==EXIT_SUCCESS) { @@ -682,6 +679,33 @@ void Window::set_menu_actions() { Debug::get().start(breakpoints, executable_path_spaces_fixed, debug_build_path, [this, executable_path](int exit_status){ debugging=false; Terminal::get().async_print(executable_path.string()+" returned: "+std::to_string(exit_status)+'\n'); + }, [this](const std::string &status) { + //TODO: move to main thread + if(status.empty()) + debug_status.set_text(""); + else + debug_status.set_text("debug: "+status); + }, [this](const boost::filesystem::path &file, int line) { + //TODO: move to main thread + //Remove debug stop source mark + for(int c=0;cfile_path==debug_last_stop_line.first) { + auto start_iter=view->get_buffer()->get_iter_at_line(debug_last_stop_line.second-1); + auto end_iter=start_iter; + while(!end_iter.ends_line() && end_iter.forward_char()) {} + view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "debug_stop"); + break; + } + } + //Add debug stop source mark + for(int c=0;cfile_path==file) { + view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(line-1)); + debug_last_stop_line={file, line}; + } + } }); } }); @@ -697,9 +721,9 @@ void Window::set_menu_actions() { Debug::get().stop(); } }); - menu.add_action("debug_continue", [this]() { - if(notebook.get_current_page()!=-1 && debugging) { - Debug::get().continue_debug(); + menu.add_action("debug_kill", [this]() { + if(debugging) { + Debug::get().kill(); } }); menu.add_action("debug_toggle_breakpoint", [this](){ @@ -707,14 +731,14 @@ void Window::set_menu_actions() { auto view=notebook.get_current_view(); auto line_nr=view->get_buffer()->get_insert()->get_iter().get_line()+1; - if(view->get_source_buffer()->get_source_marks_at_line(line_nr-1, "breakpoint").size()>0) { + if(view->get_source_buffer()->get_source_marks_at_line(line_nr-1, "debug_breakpoint").size()>0) { auto start_iter=view->get_buffer()->get_iter_at_line(line_nr-1); auto end_iter=start_iter; while(!end_iter.ends_line() && end_iter.forward_char()) {} - view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "breakpoint"); + view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "debug_breakpoint"); } else - view->get_source_buffer()->create_source_mark("breakpoint", view->get_buffer()->get_insert()->get_iter()); + view->get_source_buffer()->create_source_mark("debug_breakpoint", view->get_buffer()->get_insert()->get_iter()); } }); diff --git a/src/window.h b/src/window.h index 45a592d..b8439c6 100644 --- a/src/window.h +++ b/src/window.h @@ -31,8 +31,11 @@ private: Gtk::HBox info_and_status_hbox; Gtk::AboutDialog about; EntryBox entry_box; + std::atomic compiling; std::atomic debugging; + Gtk::Label debug_status; + std::pair debug_last_stop_line; void configure(); void set_menu_actions(); From 9b5c5baa2d0496019190453f71b499244f6b942a Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 29 Dec 2015 12:52:10 +0100 Subject: [PATCH 06/90] Minor fixes to debug integration --- src/source.cc | 2 +- src/source_clang.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/source.cc b/src/source.cc index d8fa996..3d32726 100644 --- a/src/source.cc +++ b/src/source.cc @@ -132,7 +132,7 @@ Source::View::View(const boost::filesystem::path &file_path, const boost::filesy rgba.set_red(0.0); rgba.set_blue(1.0); mark_attr_debug_stop->set_background(rgba); - set_mark_attributes("debug_stop", mark_attr_debug_stop, 100); + set_mark_attributes("debug_stop", mark_attr_debug_stop, 101); get_buffer()->signal_changed().connect([this](){ if(spellcheck_checker==NULL) diff --git a/src/source_clang.cc b/src/source_clang.cc index 68dd90d..f1fb2d1 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -418,7 +418,7 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) debug_value.pop_back(); size_t pos=debug_value.find(" = "); if(pos!=std::string::npos) - tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\nDebug: "+debug_value.substr(pos+3), "def:note"); + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\nValue: "+debug_value.substr(pos+3), "def:note"); } return tooltip_buffer; From e941b563d9ac6d58125c9d77c580a713ae20141e Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 13:18:13 +0100 Subject: [PATCH 07/90] Added run debug command, and various fixes including more thread safe debug commands --- src/debug.cc | 259 ++++++++++++++++++++++++++------------------------ src/debug.h | 21 +++- src/files.h | 3 +- src/menu.cc | 6 +- src/window.cc | 39 ++++++-- src/window.h | 1 + 6 files changed, 188 insertions(+), 141 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index b3ed6e3..e1744e2 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -1,15 +1,16 @@ #include "debug.h" -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "lldb/API/SBTarget.h" -#include "lldb/API/SBProcess.h" -#include "lldb/API/SBListener.h" -#include "lldb/API/SBEvent.h" -#include "lldb/API/SBBreakpoint.h" -#include "lldb/API/SBThread.h" -#include "lldb/API/SBStream.h" -#include "lldb/API/SBDeclaration.h" +#include "terminal.h" #include //TODO: remove using namespace std; @@ -18,7 +19,7 @@ void log(const char *msg, void *) { cout << "debugger log: " << msg << endl; } -Debug::Debug(): stopped(false) { +Debug::Debug(): listener("juCi++ lldb listener"), state(lldb::StateType::eStateInvalid), buffer_size(131072) { lldb::SBDebugger::Initialize(); debugger=lldb::SBDebugger::Create(true, log, nullptr); @@ -27,157 +28,167 @@ Debug::Debug(): stopped(false) { void Debug::start(std::shared_ptr > > breakpoints, const boost::filesystem::path &executable, const boost::filesystem::path &path, std::function callback, std::function status_callback, - std::function stop_callback) { - std::thread debug_thread([this, breakpoints, executable, path, callback, status_callback, stop_callback]() { - auto target=debugger.CreateTarget(executable.string().c_str()); - auto listener=lldb::SBListener("juCi++ lldb listener"); - - if(!target.IsValid()) { - cerr << "Error: Could not create debug target to: " << executable << endl; //TODO: output to terminal instead - return; - } - - for(auto &breakpoint: *breakpoints) { - if(!(target.BreakpointCreateByLocation(breakpoint.first.string().c_str(), breakpoint.second)).IsValid()) { - cerr << "Error: Could not create breakpoint at: " << breakpoint.first << ":" << breakpoint.second << endl; //TODO: output to terminal instead - return; - } - } - - lldb::SBError error; - process = std::unique_ptr(new lldb::SBProcess(target.Launch(listener, nullptr, nullptr, nullptr, nullptr, nullptr, path.string().c_str(), lldb::eLaunchFlagNone, false, error))); - - if(error.Fail()) { - cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead + std::function stop_callback) { + auto target=debugger.CreateTarget(executable.string().c_str()); + + if(!target.IsValid()) { + Terminal::get().async_print("Error (debug): Could not create debug target to: "+executable.string()+'\n', true); + 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; } - + } + + lldb::SBError error; + process = std::unique_ptr(new lldb::SBProcess(target.Launch(listener, nullptr, nullptr, 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); + return; + } + + if(debug_thread.joinable()) + debug_thread.join(); + debug_thread=std::thread([this, breakpoints, executable, path, callback, status_callback, stop_callback]() { lldb::SBEvent event; while(true) { - if(listener.WaitForEvent(3, event)) { - auto state=process->GetStateFromEvent(event); - - //Update debug status - lldb::SBStream stream; - event.GetDescription(stream); - std::string event_desc=stream.GetData(); - event_desc.pop_back(); - auto pos=event_desc.rfind(" = "); - if(status_callback && pos!=std::string::npos) - status_callback(event_desc.substr(pos+3)); - - bool expected=false; - if(state==lldb::StateType::eStateStopped && stopped.compare_exchange_strong(expected, true)) { - auto line_entry=process->GetSelectedThread().GetSelectedFrame().GetLineEntry(); - if(stop_callback) { - lldb::SBStream stream; - line_entry.GetFileSpec().GetDescription(stream); - stop_callback(stream.GetData(), line_entry.GetLine()); - } + event_mutex.lock(); + if(listener.WaitForEvent(1, event)) { + if((event.GetType() & lldb::SBProcess::eBroadcastBitStateChanged)>0) { + auto state=process->GetStateFromEvent(event); + this->state=state; + + //Update debug status + lldb::SBStream stream; + event.GetDescription(stream); + std::string event_desc=stream.GetData(); + event_desc.pop_back(); + auto pos=event_desc.rfind(" = "); + if(status_callback && pos!=std::string::npos) + status_callback(event_desc.substr(pos+3)); - /*lldb::SBStream stream; - process->GetSelectedThread().GetDescription(stream); - cout << stream.GetData() << endl;*/ - for(uint32_t thread_index=0;thread_indexGetNumThreads();thread_index++) { - auto thread=process->GetThreadAtIndex(thread_index); - for(uint32_t frame_index=0;frame_indexGetDescription(stream); - cout << stream.GetData() << endl; - - stream.Clear(); - process->GetSelectedThread().GetSelectedFrame().GetLineEntry().GetDescription(stream); - cout << stream.GetData() << endl;*/ - /*lldb::SBStream stream; - auto value=values.GetValueAtIndex(value_index); - - cout << value.GetFrame().GetSymbol().GetName() << endl; - - auto declaration = value.GetDeclaration(); - if(declaration.IsValid()) - cout << declaration.GetFileSpec().GetFilename() << ":" << declaration.GetLine() << ":" << declaration.GetColumn() << endl; - - value.GetDescription(stream); - cout << " " << stream.GetData() << endl; - stream.Clear(); - - value.GetData().GetDescription(stream); - cout << " " << stream.GetData() << endl;*/ - } + if(state==lldb::StateType::eStateStopped) { + auto line_entry=process->GetSelectedThread().GetSelectedFrame().GetLineEntry(); + if(stop_callback) { + lldb::SBStream stream; + line_entry.GetFileSpec().GetDescription(stream); + stop_callback(stream.GetData(), line_entry.GetLine()); } } + + else if(state==lldb::StateType::eStateExited) { + auto exit_status=process->GetExitStatus(); + if(callback) + callback(exit_status); + if(status_callback) + status_callback(""); + if(stop_callback) + stop_callback("", 0); + process.reset(); + this->state=lldb::StateType::eStateInvalid; + event_mutex.unlock(); + return; + } + + else if(state==lldb::StateType::eStateCrashed) { + if(callback) + callback(-1); + if(status_callback) + status_callback(""); + if(stop_callback) + stop_callback("", 0); + process.reset(); + this->state=lldb::StateType::eStateInvalid; + event_mutex.unlock(); + return; + } } - - else if(state==lldb::StateType::eStateExited) { - auto exit_status=process->GetExitStatus(); - if(callback) - callback(exit_status); - if(status_callback) - status_callback(""); - if(stop_callback) - stop_callback("", 0); - process.reset(); - stopped=false; - return; + if((event.GetType() & lldb::SBProcess::eBroadcastBitSTDOUT)>0) { + char buffer[buffer_size]; + size_t n; + while((n=process->GetSTDOUT(buffer, buffer_size))!=0) + Terminal::get().async_print(std::string(buffer, n)); } - - else if(state==lldb::StateType::eStateCrashed) { - if(callback) - callback(-1); - if(status_callback) - status_callback(""); - if(stop_callback) - stop_callback("", 0); - process.reset(); - stopped=false; - return; + //TODO: for some reason stderr is redirected to stdout + if((event.GetType() & lldb::SBProcess::eBroadcastBitSTDERR)>0) { + char buffer[buffer_size]; + size_t n; + while((n=process->GetSTDERR(buffer, buffer_size))!=0) + Terminal::get().async_print(std::string(buffer, n), true); } } + event_mutex.unlock(); this_thread::sleep_for(std::chrono::milliseconds(200)); } }); - debug_thread.detach(); } void Debug::continue_debug() { - bool expected=true; - if(stopped.compare_exchange_strong(expected, false)) + event_mutex.lock(); + if(state==lldb::StateType::eStateStopped) process->Continue(); + event_mutex.unlock(); } void Debug::stop() { - auto error=process->Stop(); - if(error.Fail()) { - cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead - return; + event_mutex.lock(); + if(state==lldb::StateType::eStateRunning) { + auto error=process->Stop(); + if(error.Fail()) + Terminal::get().async_print(std::string("Error (debug): ")+error.GetCString()+'\n', true); } + event_mutex.unlock(); } void Debug::kill() { - auto error=process->Kill(); - if(error.Fail()) { - cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead - return; + event_mutex.lock(); + if(process) { + auto error=process->Kill(); + if(error.Fail()) + Terminal::get().async_print(std::string("Error (debug): ")+error.GetCString()+'\n', true); } + event_mutex.unlock(); +} + +std::pair Debug::run_command(const std::string &command) { + std::pair command_return; + event_mutex.lock(); + if(state==lldb::StateType::eStateStopped) { + lldb::SBCommandReturnObject command_return_object; + debugger.GetCommandInterpreter().HandleCommand(command.c_str(), command_return_object, true); + command_return.first=command_return_object.GetOutput(); + command_return.second=command_return_object.GetError(); + } + event_mutex.unlock(); + return command_return; +} + +void Debug::delete_debug() { + kill(); + if(debug_thread.joinable()) + debug_thread.join(); } std::string Debug::get_value(const std::string &variable) { - if(stopped) { + std::string variable_value; + event_mutex.lock(); + if(state==lldb::StateType::eStateStopped) { auto frame=process->GetSelectedThread().GetSelectedFrame(); - auto values=frame.GetVariables(false, true, false, false); + auto values=frame.GetVariables(true, true, true, true); for(uint32_t value_index=0;value_index #include -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBProcess.h" +#include +#include +#include +#include class Debug { private: @@ -19,17 +21,26 @@ public: const boost::filesystem::path &executable, const boost::filesystem::path &path="", std::function callback=nullptr, std::function status_callback=nullptr, - std::function stop_callback=nullptr); + std::function stop_callback=nullptr); void continue_debug(); //can't use continue as function name void stop(); void kill(); + std::pair run_command(const std::string &command); - std::string get_value(const std::string &variable); + void delete_debug(); //can't use delete as function name + std::string get_value(const std::string &variable); + private: lldb::SBDebugger debugger; + lldb::SBListener listener; std::unique_ptr process; - std::atomic stopped; + std::thread debug_thread; + + lldb::StateType state; + std::mutex event_mutex; + + size_t buffer_size; }; #endif diff --git a/src/files.h b/src/files.h index 8628b56..1cd0965 100644 --- a/src/files.h +++ b/src/files.h @@ -100,7 +100,8 @@ const std::string configjson = " \"force_kill_last_running\": \"Escape\",\n" " \"debug_start_continue\": \"y\",\n" " \"debug_stop\": \"y\",\n" -" \"debug_kill\": \"k\",\n" +" \"debug_kill\": \"k\",\n" +" \"debug_run_command\": \"Return\",\n" " \"debug_toggle_breakpoint\": \"b\",\n" #ifdef __linux " \"next_tab\": \"Tab\",\n" diff --git a/src/menu.cc b/src/menu.cc index 1fccdeb..b8900e8 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -289,9 +289,9 @@ Menu::Menu() { "
" "
" " " - " _Continue" - " app.debug_continue" - +accels["debug_continue"]+ //For Ubuntu... + " _Run Command" + " app.debug_run_command" + +accels["debug_run_command"]+ //For Ubuntu... " " "
" "
" diff --git a/src/window.cc b/src/window.cc index 64cfabc..37c729c 100644 --- a/src/window.cc +++ b/src/window.cc @@ -658,14 +658,16 @@ void Window::set_menu_actions() { if(project_path==view->project_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.filename(), iter.get_line()+1); + 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.filename(), iter.get_line()+1); + breakpoints->emplace_back(view->file_path, iter.get_line()+1); } } - Terminal::get().print("Compiling and running "+executable_path.string()+"\n"); + Terminal::get().print("Compiling and debugging "+executable_path.string()+"\n"); Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, breakpoints, executable_path, debug_build_path](int exit_status){ - if(exit_status==EXIT_SUCCESS) { + if(exit_status!=EXIT_SUCCESS) + debugging=false; + else { auto executable_path_spaces_fixed=executable_path.string(); char last_char=0; for(size_t c=0;cfile_path==file) { - view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(line-1)); - debug_last_stop_line={file, line}; + if(view->file_path==file_path) { + view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(line_nr-1)); + debug_last_stop_line={file_path, line_nr}; } } }); @@ -726,6 +728,26 @@ void Window::set_menu_actions() { Debug::get().kill(); } }); + 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); + } + last_run_debug_command=content; + } + entry_box.hide(); + }, 30); + auto entry_it=entry_box.entries.begin(); + entry_it->set_placeholder_text("Debug Command"); + entry_box.buttons.emplace_back("Run debug command", [this, entry_it](){ + entry_it->activate(); + }); + entry_box.show(); + }); menu.add_action("debug_toggle_breakpoint", [this](){ if(notebook.get_current_page()!=-1) { auto view=notebook.get_current_view(); @@ -824,6 +846,7 @@ bool Window::on_delete_event(GdkEventAny *event) { return true; } Terminal::get().kill_async_processes(); + Debug::get().delete_debug(); return false; } diff --git a/src/window.h b/src/window.h index b8439c6..fe9e71a 100644 --- a/src/window.h +++ b/src/window.h @@ -47,6 +47,7 @@ private: std::string last_search; std::string last_replace; std::string last_run_command; + std::string last_run_debug_command; bool case_sensitive_search=true; bool regex_search=false; bool search_entry_shown=false; From 8a9c8a3082d4f8017b83ca8e3e00ce3e139258bf Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 13:37:26 +0100 Subject: [PATCH 08/90] Now tries to find debug variable based on file_path and line number if possible --- src/debug.cc | 33 +++++++++++++++++++++++++++++---- src/debug.h | 2 +- src/source_clang.cc | 3 ++- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index e1744e2..7756e78 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -172,20 +172,45 @@ void Debug::delete_debug() { debug_thread.join(); } -std::string Debug::get_value(const std::string &variable) { +std::string Debug::get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr) { std::string variable_value; event_mutex.lock(); if(state==lldb::StateType::eStateStopped) { auto frame=process->GetSelectedThread().GetSelectedFrame(); + auto values=frame.GetVariables(true, true, true, true); + //First try to find variable based on name, file and line number for(uint32_t value_index=0;value_indexinsert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\n"+brief_comment, "def:note"); - auto debug_value=Debug::get().get_value(token.get_spelling()); + auto location=token.get_cursor().get_referenced().get_source_location(); + auto debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line); if(!debug_value.empty()) { debug_value.pop_back(); size_t pos=debug_value.find(" = "); From 0843bff56958aa8d99f9f7cb74dd57cee37f138d Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 14:50:42 +0100 Subject: [PATCH 09/90] Thread safe debug implementation, and can now go to debug stop --- src/debug.cc | 2 +- src/files.h | 1 + src/menu.cc | 7 +++++ src/window.cc | 84 ++++++++++++++++++++++++++++++++++++--------------- src/window.h | 10 +++++- 5 files changed, 77 insertions(+), 27 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 7756e78..d67fe25 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -56,7 +56,7 @@ void Debug::start(std::shared_ptr0) { auto state=process->GetStateFromEvent(event); this->state=state; diff --git a/src/files.h b/src/files.h index 1cd0965..2cf0867 100644 --- a/src/files.h +++ b/src/files.h @@ -101,6 +101,7 @@ const std::string configjson = " \"debug_start_continue\": \"y\",\n" " \"debug_stop\": \"y\",\n" " \"debug_kill\": \"k\",\n" +" \"debug_goto_stop\": \"l\",\n" " \"debug_run_command\": \"Return\",\n" " \"debug_toggle_breakpoint\": \"b\",\n" #ifdef __linux diff --git a/src/menu.cc b/src/menu.cc index b8900e8..e4367bd 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -301,6 +301,13 @@ Menu::Menu() { +accels["debug_toggle_breakpoint"]+ //For Ubuntu... " " "
" + "
" + " " + " _Go _to _Stop" + " app.debug_goto_stop" + +accels["debug_goto_stop"]+ //For Ubuntu... + " " + "
" " " "" " " diff --git a/src/window.cc b/src/window.cc index 37c729c..7bb9a49 100644 --- a/src/window.cc +++ b/src/window.cc @@ -47,7 +47,7 @@ Window::Window() : compiling(false), debugging(false) { terminal_vbox.pack_start(terminal_scrolled_window); info_and_status_hbox.pack_start(notebook.info, Gtk::PACK_SHRINK); - info_and_status_hbox.set_center_widget(debug_status); + info_and_status_hbox.set_center_widget(debug_status_label); info_and_status_hbox.pack_end(notebook.status, Gtk::PACK_SHRINK); terminal_vbox.pack_end(info_and_status_hbox, Gtk::PACK_SHRINK); vpaned.pack2(terminal_vbox, true, true); @@ -114,6 +114,37 @@ Window::Window() : compiling(false), debugging(false) { about.hide(); }); + debug_update_stop_line.connect([this](){ + debug_stop_line_mutex.lock(); + for(int c=0;cfile_path==debug_last_stop_line.first) { + auto start_iter=view->get_buffer()->get_iter_at_line(debug_last_stop_line.second-1); + auto end_iter=start_iter; + while(!end_iter.ends_line() && end_iter.forward_char()) {} + view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "debug_stop"); + break; + } + } + //Add debug stop source mark + for(int c=0;cfile_path==debug_stop_line.first) { + view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(debug_stop_line.second-1)); + debug_last_stop_line=debug_stop_line; + } + } + debug_stop_line_mutex.unlock(); + }); + debug_update_status.connect([this](){ + debug_status_mutex.lock(); + if(debug_status.empty()) + debug_status_label.set_text(""); + else + debug_status_label.set_text("debug: "+debug_status); + debug_status_mutex.unlock(); + }); + about.set_version(Config::get().window.version); about.set_authors({"(in order of appearance)", "Ted Johan Kristoffersen", @@ -682,32 +713,17 @@ void Window::set_menu_actions() { debugging=false; Terminal::get().async_print(executable_path.string()+" returned: "+std::to_string(exit_status)+'\n'); }, [this](const std::string &status) { - //TODO: move to main thread - if(status.empty()) - debug_status.set_text(""); - else - debug_status.set_text("debug: "+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) { - //TODO: move to main thread + debug_stop_line_mutex.lock(); + debug_stop_line.first=file_path; + debug_stop_line.second=line_nr; + debug_stop_line_mutex.unlock(); + debug_update_stop_line(); //Remove debug stop source mark - for(int c=0;cfile_path==debug_last_stop_line.first) { - auto start_iter=view->get_buffer()->get_iter_at_line(debug_last_stop_line.second-1); - auto end_iter=start_iter; - while(!end_iter.ends_line() && end_iter.forward_char()) {} - view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "debug_stop"); - break; - } - } - //Add debug stop source mark - for(int c=0;cfile_path==file_path) { - view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(line_nr-1)); - debug_last_stop_line={file_path, line_nr}; - } - } }); } }); @@ -763,6 +779,24 @@ void Window::set_menu_actions() { view->get_source_buffer()->create_source_mark("debug_breakpoint", view->get_buffer()->get_insert()->get_iter()); } }); + menu.add_action("debug_goto_stop", [this](){ + if(debugging) { + debug_stop_line_mutex.lock(); + auto debug_stop_line_copy=debug_stop_line; + debug_stop_line_mutex.unlock(); + notebook.open(debug_stop_line_copy.first); + if(notebook.get_current_page()!=-1) { + auto view=notebook.get_current_view(); + debug_update_stop_line(); + while(g_main_context_pending(NULL)) + g_main_context_iteration(NULL, false); + if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) { + view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line(debug_stop_line_copy.second-1)); + view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); + } + } + } + }); menu.add_action("next_tab", [this]() { if(notebook.get_current_page()!=-1) { diff --git a/src/window.h b/src/window.h index fe9e71a..973be5f 100644 --- a/src/window.h +++ b/src/window.h @@ -33,9 +33,17 @@ private: EntryBox entry_box; std::atomic compiling; + std::atomic debugging; - Gtk::Label debug_status; + Gtk::Label debug_status_label; std::pair debug_last_stop_line; + + std::pair debug_stop_line; + std::mutex debug_stop_line_mutex; + Glib::Dispatcher debug_update_stop_line; + std::string debug_status; + std::mutex debug_status_mutex; + Glib::Dispatcher debug_update_status; void configure(); void set_menu_actions(); From 256f01fd9d337488fbd569c6f565bbcf2e47ed29 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 14:57:01 +0100 Subject: [PATCH 10/90] Maybe a bit faster variable name search --- src/debug.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index d67fe25..9a0b863 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -202,15 +202,11 @@ std::string Debug::get_value(const std::string &variable, const boost::filesyste } if(variable_value.empty()) { //In case a variable is missing file and line number, only do check on name - for(uint32_t value_index=0;value_index Date: Wed, 30 Dec 2015 21:03:30 +0100 Subject: [PATCH 11/90] Added missing mutex --- src/debug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/debug.h b/src/debug.h index 1997717..5b96130 100644 --- a/src/debug.h +++ b/src/debug.h @@ -7,6 +7,7 @@ #include #include #include +#include class Debug { private: From 4cf9a4011bcd6b3eac4918299e739f32b369e612 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 21:33:20 +0100 Subject: [PATCH 12/90] Will now compile without debug support if liblldb is not found --- src/CMakeLists.txt | 20 +++++++++++++++++--- src/source_clang.cc | 5 +++++ src/window.cc | 4 ++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 25ea8dd..4697d60 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,8 +28,18 @@ endif() INCLUDE(FindPkgConfig) find_package(LibClang REQUIRED) -string(REPLACE libclang liblldb LLDB_LIBRARIES "${LIBCLANG_LIBRARIES}") - +string(REPLACE libclang liblldb LIBLLDB_LIBRARIES "${LIBCLANG_LIBRARIES}") +if(EXISTS "${LIBLLDB_LIBRARIES}") + set(LIBLLDB_FOUND TRUE) +elseif(EXISTS "${LIBLLDB_LIBRARIES}.1") + set(LIBLLDB_LIBRARIES "${LIBLLDB_LIBRARIES}.1") + set(LIBLLDB_FOUND TRUE) +endif() +if(LIBLLDB_FOUND) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DJUCI_ENABLE_DEBUG") +else() + set(LIBLLDB_LIBRARIES "") +endif() #find_package(PythonLibs 2.7) #find_package(Boost 1.55 COMPONENTS python thread log system filesystem REQUIRED) @@ -93,6 +103,10 @@ set(source_files juci.h ../tiny-process-library/process.cpp) +if(LIBLLDB_FOUND) + list(APPEND source_files debug.h debug.cc) +endif() + if(MSYS) list(APPEND source_files dialogs_unix.cc) #dialogs_win.cc does not work any more because of missing SHCreateItemFromParsingName list(APPEND source_files ../tiny-process-library/process_win.cpp) @@ -139,7 +153,7 @@ target_link_libraries(${project_name} ${GTKSVMM_LIBRARIES} ${Boost_LIBRARIES} ${ASPELL_LIBRARIES} - ${LLDB_LIBRARIES} + ${LIBLLDB_LIBRARIES} #${PYTHON_LIBRARIES} ) diff --git a/src/source_clang.cc b/src/source_clang.cc index 6ddf380..4f9ea04 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -2,7 +2,9 @@ #include "config.h" #include "terminal.h" #include "cmake.h" +#ifdef JUCI_ENABLE_DEBUG #include "debug.h" +#endif namespace sigc { #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE @@ -413,6 +415,8 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) auto brief_comment=token.get_cursor().get_brief_comments(); if(brief_comment!="") tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\n"+brief_comment, "def:note"); + +#ifdef JUCI_ENABLE_DEBUG auto location=token.get_cursor().get_referenced().get_source_location(); auto debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line); if(!debug_value.empty()) { @@ -421,6 +425,7 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) if(pos!=std::string::npos) tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\nValue: "+debug_value.substr(pos+3), "def:note"); } +#endif return tooltip_buffer; }; diff --git a/src/window.cc b/src/window.cc index 7bb9a49..34df94c 100644 --- a/src/window.cc +++ b/src/window.cc @@ -6,7 +6,9 @@ //#include "api.h" #include "dialogs.h" #include "filesystem.h" +#ifdef JUCI_ENABLE_DEBUG #include "debug.h" +#endif namespace sigc { #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE @@ -648,6 +650,7 @@ void Window::set_menu_actions() { Terminal::get().kill_last_async_process(true); }); +#ifdef JUCI_ENABLE_DEBUG menu.add_action("debug_start_continue", [this](){ if(debugging) { //Continue @@ -797,6 +800,7 @@ void Window::set_menu_actions() { } } }); +#endif menu.add_action("next_tab", [this]() { if(notebook.get_current_page()!=-1) { From 530a3561991f0427efc607bff5a014eea4de9f86 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 21:38:59 +0100 Subject: [PATCH 13/90] Added message when compiling without debugging support --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4697d60..f7e65bc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,6 +39,7 @@ if(LIBLLDB_FOUND) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DJUCI_ENABLE_DEBUG") else() set(LIBLLDB_LIBRARIES "") + message("Will compile juCi++ without debugging support") endif() #find_package(PythonLibs 2.7) From 42a416382d987e41e3d9d86452d8ff2a333097c8 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 21:40:50 +0100 Subject: [PATCH 14/90] Minor message fix when compiling without debugging support --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f7e65bc..56cc536 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,7 +39,7 @@ if(LIBLLDB_FOUND) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DJUCI_ENABLE_DEBUG") else() set(LIBLLDB_LIBRARIES "") - message("Will compile juCi++ without debugging support") + message("liblldb not found. Compiling juCi++ without debugging support") endif() #find_package(PythonLibs 2.7) From c45d4544ed6fa8349570c2da3f8c77400b5e1eb9 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 21:44:29 +0100 Subject: [PATCH 15/90] Minor compile fix --- src/window.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/window.cc b/src/window.cc index 34df94c..1767517 100644 --- a/src/window.cc +++ b/src/window.cc @@ -884,7 +884,9 @@ bool Window::on_delete_event(GdkEventAny *event) { return true; } Terminal::get().kill_async_processes(); +#ifdef JUCI_ENABLE_DEBUG Debug::get().delete_debug(); +#endif return false; } From 62d90273302f7ee1567e223f5ecc5e9b6ddc685c Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 21:51:27 +0100 Subject: [PATCH 16/90] Another minor compile fix --- src/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 56cc536..1c08d05 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -84,8 +84,6 @@ set(source_files juci.h cmake.h cmake.cc dialogs.cc - debug.h - debug.cc ../libclangmm/src/CodeCompleteResults.cc ../libclangmm/src/CompilationDatabase.cc From 3f8aeac476dac83dc8eba95d0e06f7315621aea1 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 21:55:46 +0100 Subject: [PATCH 17/90] Yet another minor compile fix --- src/notebook.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/notebook.cc b/src/notebook.cc index 744459b..2ba702b 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -6,7 +6,6 @@ #include #include "cmake.h" #include "filesystem.h" -#include "debug.h" #if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 17 #include "gtksourceview-3.0/gtksourceview/gtksourcemap.h" From ba7c44d7f80f1c16839ad42d90fe03a1fea2adf4 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 30 Dec 2015 23:17:52 +0100 Subject: [PATCH 18/90] Fixes to debugging --- src/debug.cc | 10 +++---- src/debug.h | 2 +- src/tooltips.cc | 3 +++ src/tooltips.h | 5 ++-- src/window.cc | 69 +++++++++++++++++++++++++++++-------------------- src/window.h | 8 +++--- 6 files changed, 57 insertions(+), 40 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 9a0b863..dbf7a8b 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -28,7 +28,7 @@ Debug::Debug(): listener("juCi++ lldb listener"), state(lldb::StateType::eStateI void Debug::start(std::shared_ptr > > breakpoints, const boost::filesystem::path &executable, const boost::filesystem::path &path, std::function callback, std::function status_callback, - std::function stop_callback) { + std::function stop_callback) { auto target=debugger.CreateTarget(executable.string().c_str()); if(!target.IsValid()) { @@ -75,7 +75,7 @@ void Debug::start(std::shared_ptrstate=lldb::StateType::eStateInvalid; event_mutex.unlock(); @@ -99,7 +99,7 @@ void Debug::start(std::shared_ptrstate=lldb::StateType::eStateInvalid; event_mutex.unlock(); @@ -178,7 +178,7 @@ std::string Debug::get_value(const std::string &variable, const boost::filesyste if(state==lldb::StateType::eStateStopped) { auto frame=process->GetSelectedThread().GetSelectedFrame(); - auto values=frame.GetVariables(true, true, true, true); + auto values=frame.GetVariables(true, true, true, false); //First try to find variable based on name, file and line number for(uint32_t value_index=0;value_index callback=nullptr, std::function status_callback=nullptr, - std::function stop_callback=nullptr); + std::function stop_callback=nullptr); void continue_debug(); //can't use continue as function name void stop(); void kill(); diff --git a/src/tooltips.cc b/src/tooltips.cc index 9874c6b..b177f62 100644 --- a/src/tooltips.cc +++ b/src/tooltips.cc @@ -143,6 +143,7 @@ void Tooltips::show(const Gdk::Rectangle& rectangle, bool disregard_drawn) { if(rectangle.intersects(tooltip.activation_rectangle)) { tooltip.adjust(disregard_drawn); tooltip.window->show_all(); + shown=true; } else if(tooltip.window) tooltip.window->hide(); @@ -154,6 +155,7 @@ void Tooltips::show(bool disregard_drawn) { tooltip.update(); tooltip.adjust(disregard_drawn); tooltip.window->show_all(); + shown=true; } } @@ -162,4 +164,5 @@ void Tooltips::hide() { if(tooltip.window) tooltip.window->hide(); } + shown=false; } diff --git a/src/tooltips.h b/src/tooltips.h index 4f21953..66d87a9 100644 --- a/src/tooltips.h +++ b/src/tooltips.h @@ -30,6 +30,7 @@ public: static void init() {drawn_tooltips_rectangle=Gdk::Rectangle();} void show(const Gdk::Rectangle& rectangle, bool disregard_drawn=false); void show(bool disregard_drawn=false); + bool shown=false; void hide(); void clear() {tooltip_list.clear();}; @@ -37,10 +38,10 @@ public: void emplace_back(Ts&&... params) { tooltip_list.emplace_back(std::forward(params)...); } - + static Gdk::Rectangle drawn_tooltips_rectangle; - private: +private: std::list tooltip_list; }; diff --git a/src/window.cc b/src/window.cc index 1767517..be1d648 100644 --- a/src/window.cc +++ b/src/window.cc @@ -116,12 +116,12 @@ Window::Window() : compiling(false), debugging(false) { about.hide(); }); - debug_update_stop_line.connect([this](){ - debug_stop_line_mutex.lock(); + debug_update_stop.connect([this](){ + debug_stop_mutex.lock(); for(int c=0;cfile_path==debug_last_stop_line.first) { - auto start_iter=view->get_buffer()->get_iter_at_line(debug_last_stop_line.second-1); + if(view->file_path==debug_last_stop.first) { + auto start_iter=view->get_buffer()->get_iter_at_line(debug_last_stop.second.first-1); auto end_iter=start_iter; while(!end_iter.ends_line() && end_iter.forward_char()) {} view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "debug_stop"); @@ -131,12 +131,14 @@ Window::Window() : compiling(false), debugging(false) { //Add debug stop source mark for(int c=0;cfile_path==debug_stop_line.first) { - view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(debug_stop_line.second-1)); - debug_last_stop_line=debug_stop_line; + if(view->file_path==debug_stop.first) { + view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(debug_stop.second.first-1)); + debug_last_stop=debug_stop; + view->get_buffer()->place_cursor(view->get_buffer()->get_insert()->get_iter()); + break; } } - debug_stop_line_mutex.unlock(); + debug_stop_mutex.unlock(); }); debug_update_status.connect([this](){ debug_status_mutex.lock(); @@ -440,10 +442,10 @@ void Window::set_menu_actions() { auto end_line_index=iter.get_line_index(); index=std::min(index, end_line_index); + view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(line, index)); while(g_main_context_pending(NULL)) g_main_context_iteration(NULL, false); if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) { - view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(line, index)); view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); view->delayed_tooltips_connection.disconnect(); } @@ -720,12 +722,13 @@ void Window::set_menu_actions() { debug_status=status; debug_status_mutex.unlock(); debug_update_status(); - }, [this](const boost::filesystem::path &file_path, int line_nr) { - debug_stop_line_mutex.lock(); - debug_stop_line.first=file_path; - debug_stop_line.second=line_nr; - debug_stop_line_mutex.unlock(); - debug_update_stop_line(); + }, [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 }); } @@ -784,18 +787,29 @@ void Window::set_menu_actions() { }); menu.add_action("debug_goto_stop", [this](){ if(debugging) { - debug_stop_line_mutex.lock(); - auto debug_stop_line_copy=debug_stop_line; - debug_stop_line_mutex.unlock(); - notebook.open(debug_stop_line_copy.first); + debug_stop_mutex.lock(); + auto debug_stop_copy=debug_stop; + debug_stop_mutex.unlock(); + notebook.open(debug_stop_copy.first); if(notebook.get_current_page()!=-1) { auto view=notebook.get_current_view(); - debug_update_stop_line(); - while(g_main_context_pending(NULL)) - g_main_context_iteration(NULL, false); - if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) { - view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line(debug_stop_line_copy.second-1)); - view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); + debug_update_stop(); + + int line_nr=debug_stop_copy.second.first-1; + int line_index= debug_stop_copy.second.second-1; + if(line_nrget_buffer()->get_line_count()) { + auto iter=view->get_buffer()->get_iter_at_line(line_nr); + auto end_line_iter=iter; + while(!iter.ends_line() && iter.forward_char()) {} + auto line=view->get_buffer()->get_text(iter, end_line_iter); + if(line_indexget_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(line_nr, line_index)); + + 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); + } } } } @@ -1050,12 +1064,11 @@ void Window::goto_line_entry() { if(line>0 && line<=view->get_buffer()->get_line_count()) { line--; + view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line(line)); while(g_main_context_pending(NULL)) g_main_context_iteration(NULL, false); - if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) { - view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line(line)); + 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); - } } } catch(const std::exception &e) {} diff --git a/src/window.h b/src/window.h index 973be5f..2c8b535 100644 --- a/src/window.h +++ b/src/window.h @@ -36,11 +36,11 @@ private: std::atomic debugging; Gtk::Label debug_status_label; - std::pair debug_last_stop_line; + std::pair > debug_last_stop; - std::pair debug_stop_line; - std::mutex debug_stop_line_mutex; - Glib::Dispatcher debug_update_stop_line; + std::pair > debug_stop; + std::mutex debug_stop_mutex; + Glib::Dispatcher debug_update_stop; std::string debug_status; std::mutex debug_status_mutex; Glib::Dispatcher debug_update_status; From ebec5de6b18559260a43e54605434f4eaeb53ef4 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 31 Dec 2015 00:18:34 +0100 Subject: [PATCH 19/90] Autocomplete now restarts after . symbols properly --- src/source_clang.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/source_clang.cc b/src/source_clang.cc index 4f9ea04..e3f8982 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -669,11 +669,10 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_state(Au else { if(autocomplete_state==AutocompleteState::STARTING || autocomplete_state==AutocompleteState::RESTARTING) autocomplete_state=AutocompleteState::CANCELED; - else { - auto iter=get_buffer()->get_insert()->get_iter(); - if(last_keyval=='.' || last_keyval==':' || (last_keyval=='>' && iter.backward_char() && iter.backward_char() && *iter=='-')) - autocomplete_check(); - } + auto iter=get_buffer()->get_insert()->get_iter(); + iter.backward_chars(2); + if(last_keyval=='.' || (last_keyval==':' && *iter==':') || (last_keyval=='>' && *iter=='-')) + autocomplete_check(); } } }); From 924ccfc30da585c047b756813826a14efd5bc43e Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 31 Dec 2015 10:20:39 +0100 Subject: [PATCH 20/90] Debugging fixes --- src/debug.cc | 27 +++++++++++++++++---------- src/files.h | 2 +- src/window.cc | 40 +++++++++++++++++++++------------------- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index dbf7a8b..5c4da51 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -19,16 +19,16 @@ void log(const char *msg, void *) { cout << "debugger log: " << msg << endl; } -Debug::Debug(): listener("juCi++ lldb listener"), state(lldb::StateType::eStateInvalid), buffer_size(131072) { - lldb::SBDebugger::Initialize(); - - debugger=lldb::SBDebugger::Create(true, log, nullptr); -} +Debug::Debug(): listener("juCi++ lldb listener"), state(lldb::StateType::eStateInvalid), buffer_size(131072) {} void Debug::start(std::shared_ptr > > breakpoints, const boost::filesystem::path &executable, const boost::filesystem::path &path, 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()); if(!target.IsValid()) { @@ -49,10 +49,9 @@ void Debug::start(std::shared_ptrGetSelectedThread().GetSelectedFrame().GetLineEntry(); if(stop_callback) { - lldb::SBStream stream; - line_entry.GetFileSpec().GetDescription(stream); - stop_callback(stream.GetData(), line_entry.GetLine(), line_entry.GetColumn()); + if(line_entry.IsValid()) { + lldb::SBStream stream; + line_entry.GetFileSpec().GetDescription(stream); + auto column=line_entry.GetColumn(); + if(column==0) + column=1; + stop_callback(stream.GetData(), line_entry.GetLine(), column); + } + else + stop_callback("", 0, 0); } } @@ -170,6 +176,7 @@ void Debug::delete_debug() { kill(); if(debug_thread.joinable()) debug_thread.join(); + lldb::SBDebugger::Terminate(); } std::string Debug::get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr) { diff --git a/src/files.h b/src/files.h index 2cf0867..34dca1f 100644 --- a/src/files.h +++ b/src/files.h @@ -2,7 +2,7 @@ #define JUCI_FILES_H_ #include -#define JUCI_VERSION "1.0.2" +#define JUCI_VERSION "1.1.0" const std::string configjson = "{\n" diff --git a/src/window.cc b/src/window.cc index be1d648..ffdc4f1 100644 --- a/src/window.cc +++ b/src/window.cc @@ -790,25 +790,27 @@ void Window::set_menu_actions() { debug_stop_mutex.lock(); auto debug_stop_copy=debug_stop; debug_stop_mutex.unlock(); - notebook.open(debug_stop_copy.first); - if(notebook.get_current_page()!=-1) { - auto view=notebook.get_current_view(); - debug_update_stop(); - - int line_nr=debug_stop_copy.second.first-1; - int line_index= debug_stop_copy.second.second-1; - if(line_nrget_buffer()->get_line_count()) { - auto iter=view->get_buffer()->get_iter_at_line(line_nr); - auto end_line_iter=iter; - while(!iter.ends_line() && iter.forward_char()) {} - auto line=view->get_buffer()->get_text(iter, end_line_iter); - if(line_indexget_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(line_nr, line_index)); - - 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); + if(!debug_stop_copy.first.empty()) { + notebook.open(debug_stop_copy.first); + if(notebook.get_current_page()!=-1) { + auto view=notebook.get_current_view(); + debug_update_stop(); + + int line_nr=debug_stop_copy.second.first-1; + int line_index=debug_stop_copy.second.second-1; + if(line_nrget_buffer()->get_line_count()) { + auto iter=view->get_buffer()->get_iter_at_line(line_nr); + auto end_line_iter=iter; + while(!iter.ends_line() && iter.forward_char()) {} + auto line=view->get_buffer()->get_text(iter, end_line_iter); + if(line_indexget_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(line_nr, line_index)); + + 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); + } } } } From ff7ec7ddc87e1a364c6b1ed05d4197327a068954 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 31 Dec 2015 11:23:49 +0100 Subject: [PATCH 21/90] Debug process now has correct environment variables, and handles stdin --- src/debug.cc | 26 ++++++++++++++++++++++---- src/debug.h | 3 +++ src/terminal.cc | 16 ++++++++++++++-- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 5c4da51..739ab21 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -1,4 +1,7 @@ #include "debug.h" +#include +#include +#include "terminal.h" #include #include @@ -10,10 +13,9 @@ #include #include -#include "terminal.h" +using namespace std; //TODO: remove -#include //TODO: remove -using namespace std; +extern const char **environ; void log(const char *msg, void *) { cout << "debugger log: " << msg << endl; @@ -44,7 +46,7 @@ void Debug::start(std::shared_ptr(new lldb::SBProcess(target.Launch(listener, nullptr, nullptr, nullptr, nullptr, nullptr, path.string().c_str(), lldb::eLaunchFlagNone, false, error))); + process = std::unique_ptr(new lldb::SBProcess(target.Launch(listener, nullptr, 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); return; @@ -220,3 +222,19 @@ std::string Debug::get_value(const std::string &variable, const boost::filesyste event_mutex.unlock(); return variable_value; } + +bool Debug::is_running() { + bool running; + event_mutex.lock(); + running=state==lldb::StateType::eStateRunning; + event_mutex.unlock(); + return running; +} + +void Debug::write(const std::string &buffer) { + event_mutex.lock(); + if(state==lldb::StateType::eStateRunning) { + process->PutSTDIN(buffer.c_str(), buffer.size()); + } + event_mutex.unlock(); +} diff --git a/src/debug.h b/src/debug.h index 07abe79..d91fc5e 100644 --- a/src/debug.h +++ b/src/debug.h @@ -31,6 +31,9 @@ public: void delete_debug(); //can't use delete as function name std::string get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr); + + bool is_running(); + void write(const std::string &buffer); private: lldb::SBDebugger debugger; diff --git a/src/terminal.cc b/src/terminal.cc index 546328c..130e098 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -2,6 +2,9 @@ #include #include "logging.h" #include "config.h" +#ifdef JUCI_ENABLE_DEBUG +#include "debug.h" +#endif Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) { waiting_print.connect([this](){ @@ -243,7 +246,11 @@ void Terminal::async_print(int line_nr, const std::string &message) { bool Terminal::on_key_press_event(GdkEventKey *event) { processes_mutex.lock(); - if(processes.size()>0) { + bool debug_is_running=false; +#ifdef JUCI_ENABLE_DEBUG + debug_is_running=Debug::get().is_running(); +#endif + if(processes.size()>0 || debug_is_running) { get_buffer()->place_cursor(get_buffer()->end()); auto unicode=gdk_keyval_to_unicode(event->keyval); char chr=(char)unicode; @@ -261,7 +268,12 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { } else if(event->keyval==GDK_KEY_Return) { stdin_buffer+='\n'; - processes.back()->write(stdin_buffer); + if(debug_is_running) +#ifdef JUCI_ENABLE_DEBUG + Debug::get().write(stdin_buffer); +#endif + else + processes.back()->write(stdin_buffer); get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); stdin_buffer.clear(); } From 4d64edde4616710ccaeb43dc390232b84796fb7e Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 31 Dec 2015 12:22:04 +0100 Subject: [PATCH 22/90] Can now add/remove breakpoints when debug process is in stop state --- src/debug.cc | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/debug.h | 6 ++++++ src/window.cc | 30 ++++++++++++++++++----------- 3 files changed, 78 insertions(+), 11 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 739ab21..0d8c36a 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -12,6 +12,7 @@ #include #include #include +#include using namespace std; //TODO: remove @@ -223,6 +224,22 @@ std::string Debug::get_value(const std::string &variable, const boost::filesyste return variable_value; } +bool Debug::is_invalid() { + bool invalid; + event_mutex.lock(); + invalid=state==lldb::StateType::eStateInvalid; + event_mutex.unlock(); + return invalid; +} + +bool Debug::is_stopped() { + bool stopped; + event_mutex.lock(); + stopped=state==lldb::StateType::eStateStopped; + event_mutex.unlock(); + return stopped; +} + bool Debug::is_running() { bool running; event_mutex.lock(); @@ -231,6 +248,42 @@ bool Debug::is_running() { return running; } +void Debug::add_breakpoint(const boost::filesystem::path &file_path, int line_nr) { + event_mutex.lock(); + if(state==lldb::eStateStopped) { + if(!(process->GetTarget().BreakpointCreateByLocation(file_path.string().c_str(), line_nr)).IsValid()) + Terminal::get().async_print("Error (debug): Could not create breakpoint at: "+file_path.string()+":"+std::to_string(line_nr)+'\n', true); + } + event_mutex.unlock(); +} + +void Debug::remove_breakpoint(const boost::filesystem::path &file_path, int line_nr, int line_count) { + event_mutex.lock(); + if(state==lldb::eStateStopped) { + auto target=process->GetTarget(); + for(int line_nr_try=line_nr;line_nr_tryget_buffer()->get_insert()->get_iter().get_line()+1; - - if(view->get_source_buffer()->get_source_marks_at_line(line_nr-1, "debug_breakpoint").size()>0) { - auto start_iter=view->get_buffer()->get_iter_at_line(line_nr-1); - auto end_iter=start_iter; - while(!end_iter.ends_line() && end_iter.forward_char()) {} - view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "debug_breakpoint"); + bool debug_is_stopped=Debug::get().is_stopped(); + if(Debug::get().is_invalid() || debug_is_stopped) { + if(notebook.get_current_page()!=-1) { + auto view=notebook.get_current_view(); + auto line_nr=view->get_buffer()->get_insert()->get_iter().get_line(); + + if(view->get_source_buffer()->get_source_marks_at_line(line_nr, "debug_breakpoint").size()>0) { + auto start_iter=view->get_buffer()->get_iter_at_line(line_nr); + auto end_iter=start_iter; + while(!end_iter.ends_line() && end_iter.forward_char()) {} + view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "debug_breakpoint"); + if(debug_is_stopped) + Debug::get().remove_breakpoint(view->file_path, line_nr+1, view->get_buffer()->get_line_count()+1); + } + else { + view->get_source_buffer()->create_source_mark("debug_breakpoint", view->get_buffer()->get_insert()->get_iter()); + if(debug_is_stopped) + Debug::get().add_breakpoint(view->file_path, line_nr+1); + } } - else - view->get_source_buffer()->create_source_mark("debug_breakpoint", view->get_buffer()->get_insert()->get_iter()); } }); menu.add_action("debug_goto_stop", [this](){ From 091324e0ba3b7b6330d62b99c9f810c5d58d707b Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 31 Dec 2015 12:47:29 +0100 Subject: [PATCH 23/90] Minor fixes to debugging --- src/window.cc | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/window.cc b/src/window.cc index ff66bff..a48b883 100644 --- a/src/window.cc +++ b/src/window.cc @@ -121,10 +121,7 @@ Window::Window() : compiling(false), debugging(false) { for(int c=0;cfile_path==debug_last_stop.first) { - auto start_iter=view->get_buffer()->get_iter_at_line(debug_last_stop.second.first-1); - auto end_iter=start_iter; - while(!end_iter.ends_line() && end_iter.forward_char()) {} - view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "debug_stop"); + view->get_source_buffer()->remove_source_marks(view->get_buffer()->begin(), view->get_buffer()->end(), "debug_stop"); break; } } @@ -132,8 +129,10 @@ Window::Window() : compiling(false), debugging(false) { for(int c=0;cfile_path==debug_stop.first) { - view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(debug_stop.second.first-1)); - debug_last_stop=debug_stop; + if(debug_stop.second.first-1get_buffer()->get_line_count()) { + view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(debug_stop.second.first-1)); + debug_last_stop=debug_stop; + } view->get_buffer()->place_cursor(view->get_buffer()->get_insert()->get_iter()); break; } @@ -811,14 +810,14 @@ void Window::set_menu_actions() { auto end_line_iter=iter; while(!iter.ends_line() && iter.forward_char()) {} auto line=view->get_buffer()->get_text(iter, end_line_iter); - if(line_indexget_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(line_nr, line_index)); - - 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); - } + if(line_index>=line.bytes()) + line_index=0; + view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(line_nr, line_index)); + + 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); } } } From dc8dcae1ff7b0319a65ade2ef97f626698ab8cde Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 31 Dec 2015 12:59:32 +0100 Subject: [PATCH 24/90] Can now add/remove breakpoints when debug is in running state, also removes stop line mark when debug is in running state --- src/debug.cc | 9 +++++---- src/window.cc | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 0d8c36a..0a18dbb 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -87,7 +87,9 @@ void Debug::start(std::shared_ptrGetExitStatus(); if(callback) @@ -101,7 +103,6 @@ void Debug::start(std::shared_ptrGetTarget().BreakpointCreateByLocation(file_path.string().c_str(), line_nr)).IsValid()) Terminal::get().async_print("Error (debug): Could not create breakpoint at: "+file_path.string()+":"+std::to_string(line_nr)+'\n', true); } @@ -259,7 +260,7 @@ void Debug::add_breakpoint(const boost::filesystem::path &file_path, int line_nr void Debug::remove_breakpoint(const boost::filesystem::path &file_path, int line_nr, int line_count) { event_mutex.lock(); - if(state==lldb::eStateStopped) { + if(state==lldb::eStateStopped || state==lldb::eStateRunning) { auto target=process->GetTarget(); for(int line_nr_try=line_nr;line_nr_tryget_buffer()->get_insert()->get_iter().get_line(); @@ -781,12 +781,12 @@ void Window::set_menu_actions() { auto end_iter=start_iter; while(!end_iter.ends_line() && end_iter.forward_char()) {} view->get_source_buffer()->remove_source_marks(start_iter, end_iter, "debug_breakpoint"); - if(debug_is_stopped) + if(debug_is_stopped_or_running) Debug::get().remove_breakpoint(view->file_path, line_nr+1, view->get_buffer()->get_line_count()+1); } else { view->get_source_buffer()->create_source_mark("debug_breakpoint", view->get_buffer()->get_insert()->get_iter()); - if(debug_is_stopped) + if(debug_is_stopped_or_running) Debug::get().add_breakpoint(view->file_path, line_nr+1); } } From ad4fed49e8bbde6c1e32948c23660aa54fae3262 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 31 Dec 2015 13:21:45 +0100 Subject: [PATCH 25/90] Added lldb to README, install.md and fixed some minor compilation issues --- README.md | 2 ++ docs/install.md | 11 ++++++++--- src/debug.cc | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ef2e0f8..d1edf64 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ towards libclang with speed and ease of use in mind. ## Features * Platform independent +* Debug integration through lldb * Fast and responsive (written in C++) * Syntax highlighting for more than 100 different file types * C++ warnings and errors on the fly @@ -44,6 +45,7 @@ See [enhancements](https://github.com/cppit/jucipp/labels/enhancement) for plann * gtksourceviewmm-3.0 * aspell * libclang +* lldb * [libclangmm](http://github.com/cppit/libclangmm/) (downloaded directly with git --recursive, no need to install) * [tiny-process-library](http://github.com/eidheim/tiny-process-library/) (downloaded directly with git --recursive, no need to install) diff --git a/docs/install.md b/docs/install.md index 672e5f3..4263fbf 100644 --- a/docs/install.md +++ b/docs/install.md @@ -10,9 +10,11 @@ - [MSYS 2](#windows-with-msys2-httpsmsys2githubio) ## Debian/Ubuntu 15 +Note that if you use a different libclang version, be sure to install the same version of lldb (dev package). + Install dependencies: ```sh -sudo apt-get install git cmake make g++ libclang-dev pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev +sudo apt-get install git cmake make g++ libclang-dev liblldb-3.5-dev pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev sudo apt-get install clang-format-3.6 || sudo apt-get install clang-format-3.5 ``` @@ -66,9 +68,10 @@ make install ``` ## OS X with Homebrew (http://brew.sh/) -Install dependencies (installing llvm may take some time): +Install dependencies (installing llvm may take some time, and you need to follow the lldb code signing instructions): ```sh -brew install cmake --with-clang llvm pkg-config boost homebrew/x11/gtksourceviewmm3 aspell clang-format +brew install --with-clang --with-lldb llvm +brew install cmake pkg-config boost homebrew/x11/gtksourceviewmm3 aspell clang-format ``` Get juCi++ source, compile and install: @@ -82,6 +85,8 @@ make install ``` ##Windows with MSYS2 (https://msys2.github.io/) +Note that MSYS2 does not yet support lldb, but you can still compile juCi++ without debug support. + Install dependencies (replace `x86_64` with `i686` for 32-bit MSYS2 installs): ```sh pacman -S git mingw-w64-x86_64-cmake make mingw-w64-x86_64-toolchain mingw-w64-x86_64-clang mingw-w64-x86_64-gtkmm3 mingw-w64-x86_64-gtksourceviewmm3 mingw-w64-x86_64-boost mingw-w64-x86_64-aspell mingw-w64-x86_64-aspell-en diff --git a/src/debug.cc b/src/debug.cc index 0a18dbb..a7c453b 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -16,7 +16,7 @@ using namespace std; //TODO: remove -extern const char **environ; +extern char **environ; void log(const char *msg, void *) { cout << "debugger log: " << msg << endl; @@ -47,7 +47,7 @@ void Debug::start(std::shared_ptr(new lldb::SBProcess(target.Launch(listener, nullptr, environ, nullptr, nullptr, nullptr, path.string().c_str(), lldb::eLaunchFlagNone, false, error))); + process = std::unique_ptr(new lldb::SBProcess(target.Launch(listener, nullptr, (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); return; @@ -267,7 +267,7 @@ void Debug::remove_breakpoint(const boost::filesystem::path &file_path, int line auto breakpoint=target.GetBreakpointAtIndex(b_index); for(uint32_t l_index=0;l_index(line_nr_try)) { auto file_spec=line_entry.GetFileSpec(); boost::filesystem::path breakpoint_path=file_spec.GetDirectory(); breakpoint_path/=file_spec.GetFilename(); From 3fd1670363a8bbcb3bcd6e3a66f7324db283c66d Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 31 Dec 2015 13:35:55 +0100 Subject: [PATCH 26/90] installation instructions improved, and got rid of a compilation warning --- docs/install.md | 9 ++++++--- src/window.cc | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/install.md b/docs/install.md index 4263fbf..a06f88e 100644 --- a/docs/install.md +++ b/docs/install.md @@ -10,11 +10,12 @@ - [MSYS 2](#windows-with-msys2-httpsmsys2githubio) ## Debian/Ubuntu 15 -Note that if you use a different libclang version, be sure to install the same version of lldb (dev package). +**Currently, if using another libclang version, the same version of lldb is needed.** Install dependencies: ```sh -sudo apt-get install git cmake make g++ libclang-dev liblldb-3.5-dev pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev +sudo apt-get install git cmake make g++ pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev +sudo apt-get install libclang-3.6-dev liblldb-3.6-dev || sudo apt-get install libclang-3.5-dev liblldb-3.5-dev sudo apt-get install clang-format-3.6 || sudo apt-get install clang-format-3.5 ``` @@ -45,6 +46,8 @@ sudo make install ``` ##Arch Linux +**lldb install instructions needed** + Package available in the Arch User Repository: https://aur.archlinux.org/packages/jucipp-git/ @@ -85,7 +88,7 @@ make install ``` ##Windows with MSYS2 (https://msys2.github.io/) -Note that MSYS2 does not yet support lldb, but you can still compile juCi++ without debug support. +**MSYS2 does not yet support lldb, but you can still compile juCi++ without debug support.** Install dependencies (replace `x86_64` with `i686` for 32-bit MSYS2 installs): ```sh diff --git a/src/window.cc b/src/window.cc index 58f53a1..388cb07 100644 --- a/src/window.cc +++ b/src/window.cc @@ -810,7 +810,7 @@ void Window::set_menu_actions() { auto end_line_iter=iter; while(!iter.ends_line() && iter.forward_char()) {} auto line=view->get_buffer()->get_text(iter, end_line_iter); - if(line_index>=line.bytes()) + if(static_cast(line_index)>=line.bytes()) line_index=0; view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(line_nr, line_index)); From 9af098b31018d07e671bd5b116fa4ccb31798a57 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 31 Dec 2015 13:50:30 +0100 Subject: [PATCH 27/90] Added Ubuntu 14 lldb instructions --- docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index a06f88e..8fb9935 100644 --- a/docs/install.md +++ b/docs/install.md @@ -32,7 +32,7 @@ sudo make install ## Ubuntu 14/Linux Mint 17 Install dependencies: ```sh -sudo apt-get install git cmake make g++ libclang-3.6-dev clang-format-3.6 pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev +sudo apt-get install git cmake make g++ libclang-3.6-dev liblldb-3.6-dev clang-format-3.6 pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev ``` Get juCi++ source, compile and install: From 5c8e71d758b51a62becbc8635cc1a71c2e36859f Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 31 Dec 2015 13:58:42 +0100 Subject: [PATCH 28/90] Fixed compilation on MSYS2 --- src/terminal.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/terminal.cc b/src/terminal.cc index 130e098..87c5068 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -268,10 +268,11 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { } else if(event->keyval==GDK_KEY_Return) { stdin_buffer+='\n'; - if(debug_is_running) + if(debug_is_running) { #ifdef JUCI_ENABLE_DEBUG Debug::get().write(stdin_buffer); #endif + } else processes.back()->write(stdin_buffer); get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); From 293d8bb35f3b28197db163197b71b78219a97df1 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 1 Jan 2016 10:52:48 +0100 Subject: [PATCH 29/90] Should now compile on Ubuntu 14 --- src/window.cc | 9 +++++++-- src/window.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/window.cc b/src/window.cc index 388cb07..8284e4e 100644 --- a/src/window.cc +++ b/src/window.cc @@ -49,7 +49,12 @@ Window::Window() : compiling(false), debugging(false) { terminal_vbox.pack_start(terminal_scrolled_window); info_and_status_hbox.pack_start(notebook.info, Gtk::PACK_SHRINK); +#if GTK_VERSION_GE(3, 12) info_and_status_hbox.set_center_widget(debug_status_label); +#else + debug_status_label.set_halign(Gtk::Align::ALIGN_CENTER); + info_and_status_hbox.pack_start(debug_status_label); +#endif info_and_status_hbox.pack_end(notebook.status, Gtk::PACK_SHRINK); terminal_vbox.pack_end(info_and_status_hbox, Gtk::PACK_SHRINK); vpaned.pack2(terminal_vbox, true, true); @@ -120,7 +125,7 @@ Window::Window() : compiling(false), debugging(false) { debug_stop_mutex.lock(); for(int c=0;cfile_path==debug_last_stop.first) { + if(view->file_path==debug_last_stop_file_path) { view->get_source_buffer()->remove_source_marks(view->get_buffer()->begin(), view->get_buffer()->end(), "debug_stop"); break; } @@ -131,7 +136,7 @@ Window::Window() : compiling(false), debugging(false) { if(view->file_path==debug_stop.first) { if(debug_stop.second.first-1get_buffer()->get_line_count()) { view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(debug_stop.second.first-1)); - debug_last_stop=debug_stop; + debug_last_stop_file_path=debug_stop.first; } view->get_buffer()->place_cursor(view->get_buffer()->get_insert()->get_iter()); break; diff --git a/src/window.h b/src/window.h index 2c8b535..d210c76 100644 --- a/src/window.h +++ b/src/window.h @@ -36,9 +36,9 @@ private: std::atomic debugging; Gtk::Label debug_status_label; - std::pair > debug_last_stop; std::pair > debug_stop; + boost::filesystem::path debug_last_stop_file_path; std::mutex debug_stop_mutex; Glib::Dispatcher debug_update_stop; std::string debug_status; From 019e72a444a0d8eb9d1dc579c01d3eb4509e3fb2 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 1 Jan 2016 11:35:14 +0100 Subject: [PATCH 30/90] Added step-over, step-in and step-out functions to debugging menu --- src/files.h | 7 +++++-- src/menu.cc | 17 +++++++++++++++++ src/window.cc | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/files.h b/src/files.h index 34dca1f..ff84cfc 100644 --- a/src/files.h +++ b/src/files.h @@ -2,7 +2,7 @@ #define JUCI_FILES_H_ #include -#define JUCI_VERSION "1.1.0" +#define JUCI_VERSION "1.1.0-1" const std::string configjson = "{\n" @@ -101,9 +101,12 @@ const std::string configjson = " \"debug_start_continue\": \"y\",\n" " \"debug_stop\": \"y\",\n" " \"debug_kill\": \"k\",\n" -" \"debug_goto_stop\": \"l\",\n" +" \"debug_step_over\": \"n\",\n" +" \"debug_step_into\": \"t\",\n" +" \"debug_step_out\": \"t\",\n" " \"debug_run_command\": \"Return\",\n" " \"debug_toggle_breakpoint\": \"b\",\n" +" \"debug_goto_stop\": \"l\",\n" #ifdef __linux " \"next_tab\": \"Tab\",\n" " \"previous_tab\": \"Tab\",\n" diff --git a/src/menu.cc b/src/menu.cc index e4367bd..c1c76a7 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -289,6 +289,23 @@ Menu::Menu() { "
" "
" " " + " _Step _Over" + " app.debug_step_over" + +accels["debug_step_over"]+ //For Ubuntu... + " " + " " + " _Step _Into" + " app.debug_step_into" + +accels["debug_step_into"]+ //For Ubuntu... + " " + " " + " _Step _Out" + " app.debug_step_out" + +accels["debug_step_out"]+ //For Ubuntu... + " " + "
" + "
" + " " " _Run Command" " app.debug_run_command" +accels["debug_run_command"]+ //For Ubuntu... diff --git a/src/window.cc b/src/window.cc index 8284e4e..d23a4be 100644 --- a/src/window.cc +++ b/src/window.cc @@ -754,6 +754,27 @@ void Window::set_menu_actions() { Debug::get().kill(); } }); + menu.add_action("debug_step_over", [this]() { + if(debugging) { + auto command_return=Debug::get().run_command("thread step-over"); + Terminal::get().async_print(command_return.first); + Terminal::get().async_print(command_return.second, true); + } + }); + menu.add_action("debug_step_into", [this]() { + if(debugging) { + auto command_return=Debug::get().run_command("thread step-in"); + Terminal::get().async_print(command_return.first); + Terminal::get().async_print(command_return.second, true); + } + }); + menu.add_action("debug_step_out", [this]() { + if(debugging) { + auto command_return=Debug::get().run_command("thread step-out"); + Terminal::get().async_print(command_return.first); + Terminal::get().async_print(command_return.second, true); + } + }); menu.add_action("debug_run_command", [this]() { entry_box.clear(); entry_box.entries.emplace_back(last_run_debug_command, [this](const std::string& content){ From 3d74cbba50f030e96bbc04c582dac53ba8935f6e Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 1 Jan 2016 16:29:20 +0100 Subject: [PATCH 31/90] Added Project Set Run Arguments --- src/files.h | 4 +- src/menu.cc | 10 ++ src/window.cc | 291 ++++++++++++++++++++++++++++++-------------------- src/window.h | 5 + 4 files changed, 192 insertions(+), 118 deletions(-) diff --git a/src/files.h b/src/files.h index ff84cfc..127816e 100644 --- a/src/files.h +++ b/src/files.h @@ -2,7 +2,7 @@ #define JUCI_FILES_H_ #include -#define JUCI_VERSION "1.1.0-1" +#define JUCI_VERSION "1.1.0-2" const std::string configjson = "{\n" @@ -92,12 +92,14 @@ const std::string configjson = " \"source_rename\": \"r\",\n" " \"source_goto_next_diagnostic\": \"e\",\n" " \"source_apply_fix_its\": \"space\",\n" +" \"project_set_run_arguments\": \"\",\n" " \"compile_and_run\": \"Return\",\n" " \"compile\": \"Return\",\n" " \"compile_and_run\": \"Return\",\n" " \"run_command\": \"Return\",\n" " \"kill_last_running\": \"Escape\",\n" " \"force_kill_last_running\": \"Escape\",\n" +" \"debug_set_run_arguments\": \"\",\n" " \"debug_start_continue\": \"y\",\n" " \"debug_stop\": \"y\",\n" " \"debug_kill\": \"k\",\n" diff --git a/src/menu.cc b/src/menu.cc index c1c76a7..a7adb2d 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -239,6 +239,11 @@ Menu::Menu() { " _Project" "
" " " + " _Set _Run _Arguments" + " app.project_set_run_arguments" + +accels["project_set_run_arguments"]+ //For Ubuntu... + " " + " " " _Compile _and _Run" " app.compile_and_run" +accels["compile_and_run"]+ //For Ubuntu... @@ -272,6 +277,11 @@ Menu::Menu() { " _Debug" "
" " " + " _Set _Run _Arguments" + " app.debug_set_run_arguments" + +accels["debug_set_run_arguments"]+ //For Ubuntu... + " " + " " " _Start/_Continue" " app.debug_start_continue" +accels["debug_start_continue"]+ //For Ubuntu... diff --git a/src/window.cc b/src/window.cc index d23a4be..876f1e8 100644 --- a/src/window.cc +++ b/src/window.cc @@ -167,6 +167,17 @@ 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; + return std::unique_ptr(new CMake(path)); +} + void Window::configure() { Config::get().load(); auto style_context = Gtk::StyleContext::create(); @@ -546,57 +557,111 @@ void Window::set_menu_actions() { } }); + menu.add_action("project_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=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()) { + 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_path=cmake.get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:""); + + if(executable_path!="") { + auto project_path=cmake.project_path; + auto default_build_path=CMake::get_default_build_path(project_path); + if(!default_build_path.empty()) { + auto executable_path_string=executable_path.string(); + size_t pos=executable_path_string.find(project_path.string()); + if(pos!=std::string::npos) { + executable_path_string.replace(pos, project_path.string().size(), default_build_path.string()); + executable_path=executable_path_string; + } + } + run_arguments=executable_path.string(); + } + } + + 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("testing"); + }; + 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.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("compile_and_run", [this]() { if(compiling) return; - 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()) + + auto cmake=get_cmake(); + if(!cmake) return; - CMake cmake(cmake_path); - if(cmake.project_path.empty()) + auto project_path=cmake->project_path; + if(project_path.empty()) return; - auto executable_path=cmake.get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:""); - if(executable_path!="") { - auto project_path=cmake.project_path; - auto default_build_path=CMake::get_default_build_path(project_path); - if(default_build_path.empty()) - return; - compiling=true; - auto executable_path_string=executable_path.string(); - size_t pos=executable_path_string.find(project_path.string()); - if(pos!=std::string::npos) { - executable_path_string.replace(pos, project_path.string().size(), default_build_path.string()); - executable_path=executable_path_string; - } - Terminal::get().print("Compiling and running "+executable_path.string()+"\n"); - Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this, executable_path, default_build_path](int exit_status){ - compiling=false; - if(exit_status==EXIT_SUCCESS) { - auto executable_path_spaces_fixed=executable_path.string(); - char last_char=0; - for(size_t c=0;csecond; + + std::string command; + if(!run_arguments.empty()) { + command=run_arguments; } else { - Terminal::get().print("Could not find add_executable in the following paths:\n"); - for(auto &path: cmake.paths) - Terminal::get().print(" "+path.string()+"\n"); + 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"); + 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()); } + + 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'); + }); + } + }); }); menu.add_action("compile", [this]() { if(compiling) @@ -659,90 +724,82 @@ void Window::set_menu_actions() { #ifdef JUCI_ENABLE_DEBUG menu.add_action("debug_start_continue", [this](){ if(debugging) { - //Continue - if(notebook.get_current_page()!=-1) { - Debug::get().continue_debug(); - } + Debug::get().continue_debug(); return; } - 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()) + + auto cmake=get_cmake(); + if(!cmake) return; - CMake cmake(cmake_path); - if(cmake.project_path.empty()) + auto project_path=cmake->project_path; + if(project_path.empty()) + return; + + 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 executable_path=cmake.get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:""); - if(executable_path!="") { - 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)) + /*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"); return; - debugging=true; - auto executable_path_string=executable_path.string(); - size_t pos=executable_path_string.find(project_path.string()); - if(pos!=std::string::npos) { - executable_path_string.replace(pos, project_path.string().size(), debug_build_path.string()); - executable_path=executable_path_string; } - - 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); - } + size_t pos=command.find(project_path.string()); + if(pos!=std::string::npos) + command.replace(pos, project_path.string().size(), debug_build_path.string()); + //} + + 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); } - Terminal::get().print("Compiling and debugging "+executable_path.string()+"\n"); - Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, breakpoints, executable_path, debug_build_path](int exit_status){ - if(exit_status!=EXIT_SUCCESS) - debugging=false; - else { - auto executable_path_spaces_fixed=executable_path.string(); - char last_char=0; - for(size_t c=0;c class Window : public Gtk::ApplicationWindow { @@ -45,6 +46,10 @@ private: std::mutex debug_status_mutex; Glib::Dispatcher debug_update_status; + std::unique_ptr get_cmake(); + std::unordered_map project_run_arguments; + std::unordered_map debug_run_arguments; + void configure(); void set_menu_actions(); void activate_menu_items(bool activate=true); From d131c7936f7e1d0bf23691226928b3212a53be12 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 1 Jan 2016 17:20:25 +0100 Subject: [PATCH 32/90] Added escaping of executables and cmake paths --- src/cmake.cc | 8 ++++---- src/window.cc | 35 +++++++++++++++++++++++++---------- src/window.h | 1 + 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index 21d6960..8e79f4f 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -115,8 +115,8 @@ bool CMake::create_compile_commands(const boost::filesystem::path &project_path) return false; 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+" "+ - project_path.string()+" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path); + auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" \""+ + project_path.string()+"\" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path); message.hide(); if(exit_status==EXIT_SUCCESS) { #ifdef _WIN32 //Temporary fix to MSYS2's libclang @@ -145,8 +145,8 @@ bool CMake::create_debug_build(const boost::filesystem::path &project_path) { std::unique_ptr message; 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+" "+ - project_path.string()+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path); + auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" \""+ + project_path.string()+"\" -DCMAKE_BUILD_TYPE=Debug", debug_build_path); if(message) message->hide(); if(exit_status==EXIT_SUCCESS) diff --git a/src/window.cc b/src/window.cc index 876f1e8..e1a95a4 100644 --- a/src/window.cc +++ b/src/window.cc @@ -178,6 +178,21 @@ std::unique_ptr Window::get_cmake() { return std::unique_ptr(new CMake(path)); } +void Window::escape_executable(std::string &executable) { + bool backslash=false; + for(auto it=executable.begin();it!=executable.end();) { + if(*it=='\\' && !backslash) + backslash=true; + else if(backslash) + backslash=false; + else if(*it==' ') { + it=executable.insert(it, '\\'); + it++; + } + it++; + } +} + void Window::configure() { Config::get().load(); auto style_context = Gtk::StyleContext::create(); @@ -580,20 +595,18 @@ void Window::set_menu_actions() { CMake cmake(cmake_path); if(cmake.project_path.empty()) return; - auto executable_path=cmake.get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:""); + auto executable=cmake.get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:"").string(); - if(executable_path!="") { + 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 executable_path_string=executable_path.string(); - size_t pos=executable_path_string.find(project_path.string()); - if(pos!=std::string::npos) { - executable_path_string.replace(pos, project_path.string().size(), default_build_path.string()); - executable_path=executable_path_string; - } + size_t pos=executable.find(project_path.string()); + if(pos!=std::string::npos) + executable.replace(pos, project_path.string().size(), default_build_path.string()); + escape_executable(executable); } - run_arguments=executable_path.string(); + run_arguments=executable; } } @@ -601,7 +614,7 @@ void Window::set_menu_actions() { 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("testing"); + 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){ @@ -650,6 +663,7 @@ void Window::set_menu_actions() { size_t pos=command.find(project_path.string()); if(pos!=std::string::npos) command.replace(pos, project_path.string().size(), default_build_path.string()); + escape_executable(command); } compiling=true; @@ -761,6 +775,7 @@ void Window::set_menu_actions() { size_t pos=command.find(project_path.string()); if(pos!=std::string::npos) command.replace(pos, project_path.string().size(), debug_build_path.string()); + escape_executable(command); //} auto breakpoints=std::make_shared > >(); diff --git a/src/window.h b/src/window.h index 0174918..342b40a 100644 --- a/src/window.h +++ b/src/window.h @@ -47,6 +47,7 @@ private: Glib::Dispatcher debug_update_status; std::unique_ptr get_cmake(); + void escape_executable(std::string &executable); std::unordered_map project_run_arguments; std::unordered_map debug_run_arguments; From d19fbd9cc77d1f86d30c5f9f6dff71fee7012dd6 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 1 Jan 2016 22:53:57 +0100 Subject: [PATCH 33/90] Executable path escaping improvement --- src/cmake.cc | 8 ++++---- src/filesystem.cc | 20 ++++++++++++++++++++ src/filesystem.h | 3 +++ src/window.cc | 26 ++++++-------------------- src/window.h | 1 - 5 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index 8e79f4f..c8bcff6 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -115,8 +115,8 @@ bool CMake::create_compile_commands(const boost::filesystem::path &project_path) return false; 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+" \""+ - project_path.string()+"\" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path); + auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" "+ + filesystem::escape(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 @@ -145,8 +145,8 @@ bool CMake::create_debug_build(const boost::filesystem::path &project_path) { std::unique_ptr message; 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+" \""+ - project_path.string()+"\" -DCMAKE_BUILD_TYPE=Debug", debug_build_path); + auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" "+ + filesystem::escape(project_path)+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path); if(message) message->hide(); if(exit_status==EXIT_SUCCESS) diff --git a/src/filesystem.cc b/src/filesystem.cc index 02d05fd..e2a62ef 100644 --- a/src/filesystem.cc +++ b/src/filesystem.cc @@ -135,3 +135,23 @@ bool filesystem::write(const std::string &path, Glib::RefPtr bu } return false; } + +std::string filesystem::escape(const std::string &path) { + auto escaped=path; + size_t pos=0; + while((pos=escaped.find(' ', pos))!=std::string::npos) { + escaped.replace(pos, 1, "\\ "); + pos+=2; + } + return escaped; +} + +std::string filesystem::unescape(const std::string &path) { + auto escaped=path; + size_t pos=0; + while((pos=escaped.find("\\ ", pos))!=std::string::npos) { + escaped.replace(pos, 2, " "); + pos+=1; + } + return escaped; +} diff --git a/src/filesystem.h b/src/filesystem.h index 10d51bb..f4a0e6d 100644 --- a/src/filesystem.h +++ b/src/filesystem.h @@ -25,5 +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); }; #endif // JUCI_FILESYSTEM_H_ diff --git a/src/window.cc b/src/window.cc index e1a95a4..a88bc79 100644 --- a/src/window.cc +++ b/src/window.cc @@ -178,21 +178,6 @@ std::unique_ptr Window::get_cmake() { return std::unique_ptr(new CMake(path)); } -void Window::escape_executable(std::string &executable) { - bool backslash=false; - for(auto it=executable.begin();it!=executable.end();) { - if(*it=='\\' && !backslash) - backslash=true; - else if(backslash) - backslash=false; - else if(*it==' ') { - it=executable.insert(it, '\\'); - it++; - } - it++; - } -} - void Window::configure() { Config::get().load(); auto style_context = Gtk::StyleContext::create(); @@ -604,10 +589,11 @@ void Window::set_menu_actions() { size_t pos=executable.find(project_path.string()); if(pos!=std::string::npos) executable.replace(pos, project_path.string().size(), default_build_path.string()); - escape_executable(executable); } - run_arguments=executable; + run_arguments=filesystem::escape(executable); } + else + run_arguments=cmake.project_path.string(); } entry_box.clear(); @@ -663,7 +649,7 @@ void Window::set_menu_actions() { size_t pos=command.find(project_path.string()); if(pos!=std::string::npos) command.replace(pos, project_path.string().size(), default_build_path.string()); - escape_executable(command); + command=filesystem::escape(command); } compiling=true; @@ -775,7 +761,7 @@ void Window::set_menu_actions() { size_t pos=command.find(project_path.string()); if(pos!=std::string::npos) command.replace(pos, project_path.string().size(), debug_build_path.string()); - escape_executable(command); + command=filesystem::escape(command); //} auto breakpoints=std::make_shared > >(); @@ -796,7 +782,7 @@ void Window::set_menu_actions() { if(exit_status!=EXIT_SUCCESS) debugging=false; else { - Debug::get().start(breakpoints, command, debug_build_path, [this, command](int exit_status){ + Debug::get().start(breakpoints, filesystem::unescape(command), debug_build_path, [this, command](int exit_status){ debugging=false; Terminal::get().async_print(command+" returned: "+std::to_string(exit_status)+'\n'); }, [this](const std::string &status) { diff --git a/src/window.h b/src/window.h index 342b40a..0174918 100644 --- a/src/window.h +++ b/src/window.h @@ -47,7 +47,6 @@ private: Glib::Dispatcher debug_update_status; std::unique_ptr get_cmake(); - void escape_executable(std::string &executable); std::unordered_map project_run_arguments; std::unordered_map debug_run_arguments; From 8bf2b21e9629495fbf2ee1a46b25f86be5de13f2 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 1 Jan 2016 23:02:49 +0100 Subject: [PATCH 34/90] Now sets LLDB_DEBUGSERVER_PATH in debug.cc on OS X --- src/debug.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/debug.cc b/src/debug.cc index a7c453b..51bbd59 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -1,5 +1,6 @@ #include "debug.h" #include +#include #include #include "terminal.h" @@ -22,7 +23,11 @@ void log(const char *msg, void *) { cout << "debugger log: " << msg << endl; } -Debug::Debug(): listener("juCi++ lldb listener"), state(lldb::StateType::eStateInvalid), buffer_size(131072) {} +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); +#endif +} void Debug::start(std::shared_ptr > > breakpoints, const boost::filesystem::path &executable, const boost::filesystem::path &path, std::function callback, From 56eb3ddae167ae7c4ad484f1aced572b156d6708 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 2 Jan 2016 10:47:47 +0100 Subject: [PATCH 35/90] 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 Date: Sat, 2 Jan 2016 11:07:42 +0100 Subject: [PATCH 36/90] Now uses lldb API for stepping --- src/debug.cc | 24 ++++++++++++++++++++++++ src/debug.h | 3 +++ src/window.cc | 21 ++++++--------------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 88217f4..ec6b9b8 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -217,6 +217,30 @@ void Debug::kill() { event_mutex.unlock(); } +void Debug::step_over() { + event_mutex.lock(); + if(state==lldb::StateType::eStateStopped) { + process->GetSelectedThread().StepOver(); + } + event_mutex.unlock(); +} + +void Debug::step_into() { + event_mutex.lock(); + if(state==lldb::StateType::eStateStopped) { + process->GetSelectedThread().StepInto(); + } + event_mutex.unlock(); +} + +void Debug::step_out() { + event_mutex.lock(); + if(state==lldb::StateType::eStateStopped) { + process->GetSelectedThread().StepOut(); + } + event_mutex.unlock(); +} + std::pair Debug::run_command(const std::string &command) { std::pair command_return; event_mutex.lock(); diff --git a/src/debug.h b/src/debug.h index 0174167..44d8e1a 100644 --- a/src/debug.h +++ b/src/debug.h @@ -26,6 +26,9 @@ public: void continue_debug(); //can't use continue as function name void stop(); void kill(); + void step_over(); + void step_into(); + void step_out(); std::pair run_command(const std::string &command); void delete_debug(); //can't use delete as function name diff --git a/src/window.cc b/src/window.cc index 9a56018..582decc 100644 --- a/src/window.cc +++ b/src/window.cc @@ -872,25 +872,16 @@ void Window::set_menu_actions() { } }); menu.add_action("debug_step_over", [this]() { - if(debugging) { - auto command_return=Debug::get().run_command("thread step-over"); - Terminal::get().async_print(command_return.first); - Terminal::get().async_print(command_return.second, true); - } + if(debugging) + Debug::get().step_over(); }); menu.add_action("debug_step_into", [this]() { - if(debugging) { - auto command_return=Debug::get().run_command("thread step-in"); - Terminal::get().async_print(command_return.first); - Terminal::get().async_print(command_return.second, true); - } + if(debugging) + Debug::get().step_into(); }); menu.add_action("debug_step_out", [this]() { - if(debugging) { - auto command_return=Debug::get().run_command("thread step-out"); - Terminal::get().async_print(command_return.first); - Terminal::get().async_print(command_return.second, true); - } + if(debugging) + Debug::get().step_out(); }); menu.add_action("debug_run_command", [this]() { entry_box.clear(); From 12d7d07cb43263c581c086d9b12fd739a0bca41d Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 2 Jan 2016 11:20:03 +0100 Subject: [PATCH 37/90] Now activates/deactivates debug menu items --- src/window.cc | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/window.cc b/src/window.cc index 582decc..0ad51fe 100644 --- a/src/window.cc +++ b/src/window.cc @@ -144,12 +144,39 @@ Window::Window() : compiling(false), debugging(false) { } debug_stop_mutex.unlock(); }); + + auto &menu=Menu::get(); + menu.actions["debug_stop"]->set_enabled(false); + menu.actions["debug_kill"]->set_enabled(false); + menu.actions["debug_step_over"]->set_enabled(false); + menu.actions["debug_step_into"]->set_enabled(false); + menu.actions["debug_step_out"]->set_enabled(false); + menu.actions["debug_run_command"]->set_enabled(false); + menu.actions["debug_goto_stop"]->set_enabled(false); debug_update_status.connect([this](){ debug_status_mutex.lock(); - if(debug_status.empty()) + if(debug_status.empty()) { debug_status_label.set_text(""); - else + auto &menu=Menu::get(); + menu.actions["debug_stop"]->set_enabled(false); + menu.actions["debug_kill"]->set_enabled(false); + menu.actions["debug_step_over"]->set_enabled(false); + menu.actions["debug_step_into"]->set_enabled(false); + menu.actions["debug_step_out"]->set_enabled(false); + menu.actions["debug_run_command"]->set_enabled(false); + menu.actions["debug_goto_stop"]->set_enabled(false); + } + else { debug_status_label.set_text("debug: "+debug_status); + auto &menu=Menu::get(); + menu.actions["debug_stop"]->set_enabled(); + menu.actions["debug_kill"]->set_enabled(); + menu.actions["debug_step_over"]->set_enabled(); + menu.actions["debug_step_into"]->set_enabled(); + menu.actions["debug_step_out"]->set_enabled(); + menu.actions["debug_run_command"]->set_enabled(); + menu.actions["debug_goto_stop"]->set_enabled(); + } debug_status_mutex.unlock(); }); From 3cd564d89c45fbfc30849d2f713ed32b12d6384a Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 2 Jan 2016 11:44:37 +0100 Subject: [PATCH 38/90] Fixed freeze when using Go to Stop in menu --- src/window.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.cc b/src/window.cc index 0ad51fe..483aa59 100644 --- a/src/window.cc +++ b/src/window.cc @@ -962,7 +962,6 @@ void Window::set_menu_actions() { notebook.open(debug_stop_copy.first); if(notebook.get_current_page()!=-1) { auto view=notebook.get_current_view(); - debug_update_stop(); int line_nr=debug_stop_copy.second.first-1; int line_index=debug_stop_copy.second.second-1; @@ -980,6 +979,7 @@ void Window::set_menu_actions() { 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); } + debug_update_stop(); } } } From 19734953c2659bb6b28ac447e5260bf4fc576c6b Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 2 Jan 2016 11:59:49 +0100 Subject: [PATCH 39/90] Fixed crash when quitting juci in the middle of starting debug --- src/debug.cc | 1 - src/window.cc | 8 ++++++-- src/window.h | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index ec6b9b8..bf463bc 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -258,7 +258,6 @@ void Debug::delete_debug() { kill(); if(debug_thread.joinable()) debug_thread.join(); - lldb::SBDebugger::Terminate(); } std::string Debug::get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr) { diff --git a/src/window.cc b/src/window.cc index 483aa59..8354b6d 100644 --- a/src/window.cc +++ b/src/window.cc @@ -627,7 +627,7 @@ void Window::set_menu_actions() { 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->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){ @@ -793,7 +793,7 @@ void Window::set_menu_actions() { 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->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){ @@ -868,6 +868,7 @@ void Window::set_menu_actions() { 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'); @@ -885,6 +886,7 @@ void Window::set_menu_actions() { debug_update_stop(); //Remove debug stop source mark }); + debug_start_mutex.unlock(); } }); }); @@ -1069,7 +1071,9 @@ 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(); #endif return false; } diff --git a/src/window.h b/src/window.h index 0174918..51f5215 100644 --- a/src/window.h +++ b/src/window.h @@ -38,6 +38,7 @@ private: 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; From a655b61ea800d62dfaa1835c7ffd4a25db9bc412 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 2 Jan 2016 13:27:05 +0100 Subject: [PATCH 40/90] Added debug stack backtrace --- src/debug.cc | 27 +++++++++++++++++++++ src/debug.h | 9 +++++++ src/files.h | 3 ++- src/menu.cc | 7 ++++++ src/window.cc | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/debug.cc b/src/debug.cc index bf463bc..f35bac3 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -254,6 +254,33 @@ std::pair Debug::run_command(const std::string &comman return command_return; } +std::vector Debug::get_backtrace() { + std::vector backtrace; + event_mutex.lock(); + if(state==lldb::StateType::eStateStopped) { + auto thread=process->GetSelectedThread(); + for(uint32_t c_f=0;c_f class Debug { +public: + class Frame { + public: + std::string file_path; + std::string function_name; + int line_nr; + int line_index; + }; private: Debug(); public: @@ -30,6 +38,7 @@ public: void step_into(); void step_out(); std::pair run_command(const std::string &command); + std::vector get_backtrace(); void delete_debug(); //can't use delete as function name diff --git a/src/files.h b/src/files.h index 127816e..8f4af52 100644 --- a/src/files.h +++ b/src/files.h @@ -2,7 +2,7 @@ #define JUCI_FILES_H_ #include -#define JUCI_VERSION "1.1.0-2" +#define JUCI_VERSION "1.1.0-3" const std::string configjson = "{\n" @@ -106,6 +106,7 @@ const std::string configjson = " \"debug_step_over\": \"n\",\n" " \"debug_step_into\": \"t\",\n" " \"debug_step_out\": \"t\",\n" +" \"debug_backtrace\": \"n\",\n" " \"debug_run_command\": \"Return\",\n" " \"debug_toggle_breakpoint\": \"b\",\n" " \"debug_goto_stop\": \"l\",\n" diff --git a/src/menu.cc b/src/menu.cc index a7adb2d..3612c6c 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -316,6 +316,13 @@ Menu::Menu() { "
" "
" " " + " _Backtrace" + " app.debug_backtrace" + +accels["debug_backtrace"]+ //For Ubuntu... + " " + "
" + "
" + " " " _Run Command" " app.debug_run_command" +accels["debug_run_command"]+ //For Ubuntu... diff --git a/src/window.cc b/src/window.cc index 8354b6d..96488e5 100644 --- a/src/window.cc +++ b/src/window.cc @@ -151,6 +151,7 @@ Window::Window() : compiling(false), debugging(false) { menu.actions["debug_step_over"]->set_enabled(false); menu.actions["debug_step_into"]->set_enabled(false); menu.actions["debug_step_out"]->set_enabled(false); + menu.actions["debug_backtrace"]->set_enabled(false); menu.actions["debug_run_command"]->set_enabled(false); menu.actions["debug_goto_stop"]->set_enabled(false); debug_update_status.connect([this](){ @@ -163,6 +164,7 @@ Window::Window() : compiling(false), debugging(false) { menu.actions["debug_step_over"]->set_enabled(false); menu.actions["debug_step_into"]->set_enabled(false); menu.actions["debug_step_out"]->set_enabled(false); + menu.actions["debug_backtrace"]->set_enabled(false); menu.actions["debug_run_command"]->set_enabled(false); menu.actions["debug_goto_stop"]->set_enabled(false); } @@ -174,6 +176,7 @@ Window::Window() : compiling(false), debugging(false) { menu.actions["debug_step_over"]->set_enabled(); menu.actions["debug_step_into"]->set_enabled(); menu.actions["debug_step_out"]->set_enabled(); + menu.actions["debug_backtrace"]->set_enabled(); menu.actions["debug_run_command"]->set_enabled(); menu.actions["debug_goto_stop"]->set_enabled(); } @@ -912,6 +915,68 @@ void Window::set_menu_actions() { if(debugging) Debug::get().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 buffer=view->get_buffer(); + auto iter=buffer->get_insert()->get_iter(); + Gdk::Rectangle visible_rect; + view->get_visible_rect(visible_rect); + Gdk::Rectangle iter_rect; + view->get_iter_location(iter, iter_rect); + iter_rect.set_width(1); + if(!visible_rect.intersects(iter_rect)) { + view->get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3); + } + view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, buffer->create_mark(iter), true, true)); + auto rows=std::make_shared >(); + if(backtrace.size()==0) + return; + + std::string project_path; + auto cmake=get_cmake(); + if(cmake) + project_path=cmake->project_path.string(); + + for(auto &frame: backtrace) { + std::string row; + if(frame.file_path.empty()) + row=frame.function_name; + else { + auto file_path=frame.file_path; + if(!project_path.empty()) { + auto pos=file_path.find(project_path); + if(pos==0) + file_path.erase(0, project_path.size()+1); + } + + 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(); + + 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(); + } + }); menu.add_action("debug_run_command", [this]() { entry_box.clear(); entry_box.entries.emplace_back(last_run_debug_command, [this](const std::string& content){ From 1448fd742cba6be9c68dcaa34710df433b5a7442 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Sat, 2 Jan 2016 14:08:05 +0100 Subject: [PATCH 41/90] Fixed crash when debug support is not enabled --- src/window.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/window.cc b/src/window.cc index 96488e5..cae36fd 100644 --- a/src/window.cc +++ b/src/window.cc @@ -145,6 +145,7 @@ Window::Window() : compiling(false), debugging(false) { debug_stop_mutex.unlock(); }); +#ifdef JUCI_ENABLE_DEBUG auto &menu=Menu::get(); menu.actions["debug_stop"]->set_enabled(false); menu.actions["debug_kill"]->set_enabled(false); @@ -154,6 +155,7 @@ Window::Window() : compiling(false), debugging(false) { menu.actions["debug_backtrace"]->set_enabled(false); menu.actions["debug_run_command"]->set_enabled(false); menu.actions["debug_goto_stop"]->set_enabled(false); +#endif debug_update_status.connect([this](){ debug_status_mutex.lock(); if(debug_status.empty()) { From c56ac6f888dc270710b1420bf6e19ead512bdedf Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sat, 2 Jan 2016 14:48:18 +0100 Subject: [PATCH 42/90] Fixed crash on earlier liblldb versions, and changed a couple debug key bindings from n (used for new file and directory) to h --- src/debug.cc | 3 ++- src/files.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index f35bac3..a617295 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -262,7 +262,8 @@ std::vector Debug::get_backtrace() { for(uint32_t c_f=0;c_fy\",\n" " \"debug_stop\": \"y\",\n" " \"debug_kill\": \"k\",\n" -" \"debug_step_over\": \"n\",\n" +" \"debug_step_over\": \"h\",\n" " \"debug_step_into\": \"t\",\n" " \"debug_step_out\": \"t\",\n" -" \"debug_backtrace\": \"n\",\n" +" \"debug_backtrace\": \"h\",\n" " \"debug_run_command\": \"Return\",\n" " \"debug_toggle_breakpoint\": \"b\",\n" " \"debug_goto_stop\": \"l\",\n" From 23eaf5159a8329bb3f6c6df1e41a3cf717251813 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 2 Jan 2016 15:24:04 +0100 Subject: [PATCH 43/90] Fixed backtrace and a couple debug keybindings --- src/debug.cc | 5 +++-- src/files.h | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index a617295..463be8d 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -262,8 +262,9 @@ std::vector Debug::get_backtrace() { for(uint32_t c_f=0;c_fy\",\n" " \"debug_stop\": \"y\",\n" " \"debug_kill\": \"k\",\n" -" \"debug_step_over\": \"h\",\n" +" \"debug_step_over\": \"j\",\n" " \"debug_step_into\": \"t\",\n" " \"debug_step_out\": \"t\",\n" -" \"debug_backtrace\": \"h\",\n" +" \"debug_backtrace\": \"j\",\n" " \"debug_run_command\": \"Return\",\n" " \"debug_toggle_breakpoint\": \"b\",\n" " \"debug_goto_stop\": \"l\",\n" From 463b12ed54854f616526dd2ab5fd12971283c096 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 3 Jan 2016 08:18:16 +0100 Subject: [PATCH 44/90] Tooltips now always update after debug stop --- src/window.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/window.cc b/src/window.cc index cae36fd..e1590fa 100644 --- a/src/window.cc +++ b/src/window.cc @@ -138,10 +138,11 @@ Window::Window() : compiling(false), debugging(false) { view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(debug_stop.second.first-1)); debug_last_stop_file_path=debug_stop.first; } - view->get_buffer()->place_cursor(view->get_buffer()->get_insert()->get_iter()); break; } } + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->get_buffer()->place_cursor(notebook.get_current_view()->get_buffer()->get_insert()->get_iter()); debug_stop_mutex.unlock(); }); From 5ca9b4bfe65874bd7fbb7805d1ddfcd9ee52ed17 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 3 Jan 2016 08:45:18 +0100 Subject: [PATCH 45/90] Added stop reason to debug status --- src/debug.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 463be8d..858850f 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -123,8 +123,15 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat std::string event_desc=stream.GetData(); event_desc.pop_back(); auto pos=event_desc.rfind(" = "); - if(status_callback && pos!=std::string::npos) - status_callback(event_desc.substr(pos+3)); + if(status_callback && pos!=std::string::npos) { + auto status=event_desc.substr(pos+3); + if(state==lldb::StateType::eStateStopped) { + char buffer[100]; + auto n=process->GetSelectedThread().GetStopDescription(buffer, 100); + status+=" ("+std::string(buffer, n)+")"; + } + status_callback(status); + } if(state==lldb::StateType::eStateStopped) { auto line_entry=process->GetSelectedThread().GetSelectedFrame().GetLineEntry(); From 23255cdaf664f59c50083bef33a02499e2151767 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 3 Jan 2016 09:31:45 +0100 Subject: [PATCH 46/90] Slightly better breakpoint and stop colors in dark style --- src/source.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index 3d32726..66b748f 100644 --- a/src/source.cc +++ b/src/source.cc @@ -125,7 +125,7 @@ Source::View::View(const boost::filesystem::path &file_path, const boost::filesy auto mark_attr_debug_breakpoint=Gsv::MarkAttributes::create(); Gdk::RGBA rgba; rgba.set_red(1.0); - rgba.set_alpha(0.1); + rgba.set_alpha(0.15); mark_attr_debug_breakpoint->set_background(rgba); set_mark_attributes("debug_breakpoint", mark_attr_debug_breakpoint, 100); auto mark_attr_debug_stop=Gsv::MarkAttributes::create(); From 42dbeb2d0ef71c6558eb99bcf61dd58acfc232c6 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sun, 3 Jan 2016 09:43:14 +0100 Subject: [PATCH 47/90] Slight cleanup of installation document --- docs/install.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/install.md b/docs/install.md index 8fb9935..2f7e2c0 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,21 +1,23 @@ # juCi++ Installation Guide -- Linux - - [Debian/Ubuntu 15](#debianubuntu-15) - - [Ubuntu 14/Linux Mint 17](#ubuntu-14linux-mint-17) - - [Arch Linux](#arch-linux) -- OS X - - [Homebrew](#os-x-with-homebrew-httpbrewsh) -- Windows - - [MSYS 2](#windows-with-msys2-httpsmsys2githubio) +- Installation + - Linux + - [Debian/Ubuntu 15](#debianubuntu-15) + - [Ubuntu 14/Linux Mint 17](#ubuntu-14linux-mint-17) + - [Arch Linux](#arch-linux) + - OS X + - [Homebrew](#os-x-with-homebrew-httpbrewsh) + - Windows + - [MSYS 2](#windows-with-msys2-httpsmsys2githubio) +- [Run](#run) ## Debian/Ubuntu 15 **Currently, if using another libclang version, the same version of lldb is needed.** Install dependencies: ```sh -sudo apt-get install git cmake make g++ pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev sudo apt-get install libclang-3.6-dev liblldb-3.6-dev || sudo apt-get install libclang-3.5-dev liblldb-3.5-dev +sudo apt-get install git cmake make g++ pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev sudo apt-get install clang-format-3.6 || sudo apt-get install clang-format-3.5 ``` @@ -30,6 +32,8 @@ sudo make install ``` ## Ubuntu 14/Linux Mint 17 +**Currently, if using another libclang version, the same version of lldb is needed.** + Install dependencies: ```sh sudo apt-get install git cmake make g++ libclang-3.6-dev liblldb-3.6-dev clang-format-3.6 pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev @@ -71,7 +75,9 @@ make install ``` ## OS X with Homebrew (http://brew.sh/) -Install dependencies (installing llvm may take some time, and you need to follow the lldb code signing instructions): +**installing llvm may take some time, and you need to follow the lldb code signing instructions** + +Install dependencies: ```sh brew install --with-clang --with-lldb llvm brew install cmake pkg-config boost homebrew/x11/gtksourceviewmm3 aspell clang-format From ac616cd88ca8544e671d2dd40a4dd18d1bb0a18e Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sun, 3 Jan 2016 09:44:10 +0100 Subject: [PATCH 48/90] Minor fixes to installation document --- docs/install.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install.md b/docs/install.md index 2f7e2c0..643f4b3 100644 --- a/docs/install.md +++ b/docs/install.md @@ -50,7 +50,7 @@ sudo make install ``` ##Arch Linux -**lldb install instructions needed** +**lldb install instructions needed.** Package available in the Arch User Repository: https://aur.archlinux.org/packages/jucipp-git/ @@ -75,7 +75,7 @@ make install ``` ## OS X with Homebrew (http://brew.sh/) -**installing llvm may take some time, and you need to follow the lldb code signing instructions** +**Installing llvm may take some time, and you need to follow the lldb code signing instructions.** Install dependencies: ```sh From 0cf5978f1ced1af0915a80cd0c411e4bcfab9b62 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 3 Jan 2016 10:07:51 +0100 Subject: [PATCH 49/90] Found debug that looks ok in both light and dark styles --- src/source.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/source.cc b/src/source.cc index 66b748f..4706a6c 100644 --- a/src/source.cc +++ b/src/source.cc @@ -125,11 +125,14 @@ Source::View::View(const boost::filesystem::path &file_path, const boost::filesy auto mark_attr_debug_breakpoint=Gsv::MarkAttributes::create(); Gdk::RGBA rgba; rgba.set_red(1.0); - rgba.set_alpha(0.15); + rgba.set_green(0.5); + rgba.set_blue(0.5); + rgba.set_alpha(0.3); mark_attr_debug_breakpoint->set_background(rgba); set_mark_attributes("debug_breakpoint", mark_attr_debug_breakpoint, 100); auto mark_attr_debug_stop=Gsv::MarkAttributes::create(); - rgba.set_red(0.0); + rgba.set_red(0.5); + rgba.set_green(0.5); rgba.set_blue(1.0); mark_attr_debug_stop->set_background(rgba); set_mark_attributes("debug_stop", mark_attr_debug_stop, 101); From 4104d9e1aa25af8fbcf20e192691d4bba77b218e Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 3 Jan 2016 11:19:38 +0100 Subject: [PATCH 50/90] Now selects the thread in which a debug process stops --- src/debug.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/debug.cc b/src/debug.cc index 858850f..f706e32 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -117,6 +117,16 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat auto state=process->GetStateFromEvent(event); this->state=state; + if(state==lldb::StateType::eStateStopped) { + for(uint32_t c=0;cGetNumThreads();c++) { + auto thread=process->GetThreadAtIndex(c); + if(thread.GetStopReason()>=2) { + process->SetSelectedThreadByIndexID(thread.GetIndexID()); + break; + } + } + } + //Update debug status lldb::SBStream stream; event.GetDescription(stream); @@ -128,7 +138,8 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat if(state==lldb::StateType::eStateStopped) { char buffer[100]; auto n=process->GetSelectedThread().GetStopDescription(buffer, 100); - status+=" ("+std::string(buffer, n)+")"; + if(n>0) + status+=" ("+std::string(buffer, n<=100?n:100)+")"; } status_callback(status); } From 1be61a7f1b82e88d3a8d418a57a1280ce4c52510 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 3 Jan 2016 17:12:23 +0100 Subject: [PATCH 51/90] Added filename (if available) to debug status if state is stopped --- src/debug.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index f706e32..50b4b5a 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -2,8 +2,8 @@ #include #ifdef __APPLE__ #include -#include #endif +#include #include #include "terminal.h" #include "filesystem.h" @@ -137,16 +137,23 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat auto status=event_desc.substr(pos+3); if(state==lldb::StateType::eStateStopped) { char buffer[100]; - auto n=process->GetSelectedThread().GetStopDescription(buffer, 100); + auto thread=process->GetSelectedThread(); + auto n=thread.GetStopDescription(buffer, 100); if(n>0) status+=" ("+std::string(buffer, n<=100?n:100)+")"; + auto line_entry=thread.GetSelectedFrame().GetLineEntry(); + if(line_entry.IsValid()) { + lldb::SBStream stream; + line_entry.GetFileSpec().GetDescription(stream); + status +=" - "+boost::filesystem::path(stream.GetData()).filename().string()+":"+std::to_string(line_entry.GetLine()); + } } status_callback(status); } if(state==lldb::StateType::eStateStopped) { - auto line_entry=process->GetSelectedThread().GetSelectedFrame().GetLineEntry(); if(stop_callback) { + auto line_entry=process->GetSelectedThread().GetSelectedFrame().GetLineEntry(); if(line_entry.IsValid()) { lldb::SBStream stream; line_entry.GetFileSpec().GetDescription(stream); From 76493b708177096eb1e37846470137a29effb630 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 3 Jan 2016 17:27:44 +0100 Subject: [PATCH 52/90] Now only shows filename in backtrace dialog --- src/window.cc | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/window.cc b/src/window.cc index e1590fa..6a4a0cd 100644 --- a/src/window.cc +++ b/src/window.cc @@ -938,23 +938,12 @@ void Window::set_menu_actions() { if(backtrace.size()==0) return; - std::string project_path; - auto cmake=get_cmake(); - if(cmake) - project_path=cmake->project_path.string(); - for(auto &frame: backtrace) { std::string row; if(frame.file_path.empty()) row=frame.function_name; else { - auto file_path=frame.file_path; - if(!project_path.empty()) { - auto pos=file_path.find(project_path); - if(pos==0) - file_path.erase(0, project_path.size()+1); - } - + 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; From a9e294218ee47dd3a4b9ad4266e8957117182020 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 4 Jan 2016 09:19:51 +0100 Subject: [PATCH 53/90] Cleanup of cmake build system, and no longer runs cmake in debug build every time debug is started --- src/cmake.cc | 41 +++++++++++++++++++------- src/cmake.h | 4 ++- src/notebook.cc | 7 ++--- src/window.cc | 76 ++++++++++++++++--------------------------------- 4 files changed, 61 insertions(+), 67 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index 8a5ee2e..c28a46b 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -5,6 +5,8 @@ #include "terminal.h" #include +std::unordered_set CMake::debug_build_needed; + CMake::CMake(const boost::filesystem::path &path) { const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) { for(auto &line: filesystem::read_lines(cmake_path)) { @@ -31,12 +33,6 @@ CMake::CMake(const boost::filesystem::path &path) { break; search_path=search_path.parent_path(); } - - if(!project_path.empty()) { - auto default_build_path=get_default_build_path(project_path); - if(!default_build_path.empty() && !boost::filesystem::exists(default_build_path/"compile_commands.json")) - create_compile_commands(project_path); - } } boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::path &project_path) { @@ -109,12 +105,24 @@ boost::filesystem::path CMake::get_debug_build_path(const boost::filesystem::pat return debug_build_path; } -bool CMake::create_compile_commands(const boost::filesystem::path &project_path) { +bool CMake::create_default_build(const boost::filesystem::path &project_path, bool force) { + if(project_path.empty()) + return false; + + if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) + return false; + auto default_build_path=get_default_build_path(project_path); if(default_build_path.empty()) return false; + + if(!force && boost::filesystem::exists(default_build_path/"compile_commands.json")) + return true; + + debug_build_needed.emplace(project_path.string()); + auto compile_commands_path=default_build_path/"compile_commands.json"; - Dialog::Message message("Creating "+compile_commands_path.string()); + Dialog::Message message("Creating/updating default build"); auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" "+ filesystem::escape_argument(project_path)+" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path); message.hide(); @@ -139,12 +147,25 @@ bool CMake::create_compile_commands(const boost::filesystem::path &project_path) } bool CMake::create_debug_build(const boost::filesystem::path &project_path) { + if(project_path.empty()) + return false; + + if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) + return false; + auto debug_build_path=get_debug_build_path(project_path); if(debug_build_path.empty()) return false; + + if(boost::filesystem::exists(debug_build_path/"CMakeCache.txt")) { + auto it=debug_build_needed.find(project_path.string()); + if(it==debug_build_needed.end()) + return true; + debug_build_needed.erase(it); + } + std::unique_ptr message; - if(!boost::filesystem::exists(debug_build_path/"CMakeCache.txt")) - message=std::unique_ptr(new Dialog::Message("Creating debug build")); + message=std::unique_ptr(new Dialog::Message("Creating/updating debug build")); auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" "+ filesystem::escape_argument(project_path)+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path); if(message) diff --git a/src/cmake.h b/src/cmake.h index e26c4cc..bfa463b 100644 --- a/src/cmake.h +++ b/src/cmake.h @@ -3,6 +3,7 @@ #include #include #include +#include class CMake { public: @@ -12,7 +13,7 @@ public: static boost::filesystem::path get_default_build_path(const boost::filesystem::path &project_path); static boost::filesystem::path get_debug_build_path(const boost::filesystem::path &project_path); - static bool create_compile_commands(const boost::filesystem::path &project_path); + static bool create_default_build(const boost::filesystem::path &project_path, bool force=false); static bool create_debug_build(const boost::filesystem::path &project_path); boost::filesystem::path get_executable(const boost::filesystem::path &file_path); @@ -30,5 +31,6 @@ private: void parse(); std::vector get_function_parameters(std::string &data); bool parsed=false; + static std::unordered_set debug_build_needed; }; #endif //JUCI_CMAKE_H_ diff --git a/src/notebook.cc b/src/notebook.cc index 2ba702b..eec39b3 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -110,8 +110,7 @@ void Notebook::open(const boost::filesystem::path &file_path) { } } if(language && (language->get_id()=="chdr" || language->get_id()=="cpphdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) { - if(boost::filesystem::exists(project_path.string()+"/CMakeLists.txt") && !boost::filesystem::exists(CMake::get_default_build_path(project_path)/"compile_commands.json")) - CMake::create_compile_commands(project_path); + CMake::create_default_build(project_path); source_views.emplace_back(new Source::ClangView(file_path, project_path, language)); } else @@ -249,12 +248,12 @@ bool Notebook::save(int page) { if(view->file_path.filename()=="CMakeLists.txt") { auto &directories=Directories::get(); if(directories.cmake && directories.cmake->project_path!="" && view->file_path.generic_string().substr(0, directories.cmake->project_path.generic_string().size()+1)==directories.cmake->project_path.generic_string()+'/') { - if(CMake::create_compile_commands(directories.cmake->project_path)) + if(CMake::create_default_build(directories.cmake->project_path, true)) project_path=directories.cmake->project_path; } else { CMake cmake(view->file_path.parent_path()); - if(cmake.project_path!="" && CMake::create_compile_commands(cmake.project_path)) + if(CMake::create_default_build(cmake.project_path, true)) project_path=cmake.project_path; } if(project_path!="") { diff --git a/src/window.cc b/src/window.cc index 6a4a0cd..584c3aa 100644 --- a/src/window.cc +++ b/src/window.cc @@ -208,7 +208,11 @@ std::unique_ptr Window::get_cmake() { path=Directories::get().current_path; if(path.empty()) return nullptr; - return std::unique_ptr(new CMake(path)); + auto cmake=std::unique_ptr(new CMake(path)); + if(cmake->project_path.empty()) + return nullptr; + CMake::create_default_build(cmake->project_path); + return cmake; } void Window::configure() { @@ -594,29 +598,18 @@ void Window::set_menu_actions() { 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=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()) { - 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(); + 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 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()); @@ -626,7 +619,7 @@ void Window::set_menu_actions() { run_arguments=filesystem::escape_argument(executable); } else - run_arguments=filesystem::escape_argument(CMake::get_default_build_path(cmake.project_path)); + run_arguments=filesystem::escape_argument(CMake::get_default_build_path(cmake->project_path)); } entry_box.clear(); @@ -655,8 +648,6 @@ void Window::set_menu_actions() { if(!cmake) return; auto project_path=cmake->project_path; - if(project_path.empty()) - return; auto default_build_path=CMake::get_default_build_path(project_path); if(default_build_path.empty()) @@ -700,24 +691,18 @@ void Window::set_menu_actions() { menu.add_action("compile", [this]() { if(compiling) return; - 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()) + auto cmake=get_cmake(); + if(!cmake) return; - CMake cmake(cmake_path); - if(cmake.project_path!="") { - 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; - }); - } + + 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; + }); }); menu.add_action("run_command", [this]() { @@ -760,29 +745,18 @@ void Window::set_menu_actions() { 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(); + 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 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()); @@ -792,7 +766,7 @@ void Window::set_menu_actions() { run_arguments=filesystem::escape_argument(executable); } else - run_arguments=filesystem::escape_argument(CMake::get_debug_build_path(cmake.project_path)); + run_arguments=filesystem::escape_argument(CMake::get_debug_build_path(cmake->project_path)); } entry_box.clear(); @@ -823,8 +797,6 @@ void Window::set_menu_actions() { if(!cmake) return; auto project_path=cmake->project_path; - if(project_path.empty()) - return; auto debug_build_path=CMake::get_debug_build_path(project_path); if(debug_build_path.empty()) From 591555e6ee53b348a377ddea28493021db024c6a Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 4 Jan 2016 09:36:44 +0100 Subject: [PATCH 54/90] Updated install docs --- docs/install.md | 47 ++++++++--------------------------------------- 1 file changed, 8 insertions(+), 39 deletions(-) diff --git a/docs/install.md b/docs/install.md index 643f4b3..981e885 100644 --- a/docs/install.md +++ b/docs/install.md @@ -2,8 +2,8 @@ - Installation - Linux - - [Debian/Ubuntu 15](#debianubuntu-15) - - [Ubuntu 14/Linux Mint 17](#ubuntu-14linux-mint-17) + - [Debian testing/Linux Mint/Ubuntu](#debian-testinglinux-mintubuntu) + - [Debian stable](#debian-stable) - [Arch Linux](#arch-linux) - OS X - [Homebrew](#os-x-with-homebrew-httpbrewsh) @@ -11,14 +11,12 @@ - [MSYS 2](#windows-with-msys2-httpsmsys2githubio) - [Run](#run) -## Debian/Ubuntu 15 +## Debian testing/Linux Mint/Ubuntu **Currently, if using another libclang version, the same version of lldb is needed.** Install dependencies: ```sh -sudo apt-get install libclang-3.6-dev liblldb-3.6-dev || sudo apt-get install libclang-3.5-dev liblldb-3.5-dev -sudo apt-get install git cmake make g++ pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev -sudo apt-get install clang-format-3.6 || sudo apt-get install clang-format-3.5 +sudo apt-get install git cmake make g++ libclang-3.6-dev liblldb-3.6-dev clang-format-3.6 pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev ``` Get juCi++ source, compile and install: @@ -31,12 +29,12 @@ make sudo make install ``` -## Ubuntu 14/Linux Mint 17 +## Debian stable **Currently, if using another libclang version, the same version of lldb is needed.** Install dependencies: ```sh -sudo apt-get install git cmake make g++ libclang-3.6-dev liblldb-3.6-dev clang-format-3.6 pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev +sudo apt-get install git cmake make g++ libclang-3.5-dev liblldb-3.5-dev clang-format-3.5 pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev ``` Get juCi++ source, compile and install: @@ -59,8 +57,7 @@ Alternatively, follow the instructions below. Install dependencies: ```sh -#as root -pacman -S git cmake make clang gtksourceviewmm boost aspell aspell-en +sudo pacman -S git cmake make clang gtksourceviewmm boost aspell aspell-en ``` Get juCi++ source, compile and install: @@ -70,8 +67,7 @@ mkdir jucipp/build cd jucipp/build cmake .. make -# as root -make install +sudo make install ``` ## OS X with Homebrew (http://brew.sh/) @@ -111,34 +107,7 @@ make make install ``` - - ## Run ```sh juci ``` - - From 8b5d8a92847709e2ca96d6b8567e8b0deafbe0ed Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 4 Jan 2016 09:41:28 +0100 Subject: [PATCH 55/90] Added lldb as Arch Linux dependency --- docs/install.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/install.md b/docs/install.md index 981e885..3e844f5 100644 --- a/docs/install.md +++ b/docs/install.md @@ -48,8 +48,6 @@ sudo make install ``` ##Arch Linux -**lldb install instructions needed.** - Package available in the Arch User Repository: https://aur.archlinux.org/packages/jucipp-git/ @@ -57,7 +55,7 @@ Alternatively, follow the instructions below. Install dependencies: ```sh -sudo pacman -S git cmake make clang gtksourceviewmm boost aspell aspell-en +sudo pacman -S git cmake make clang lldb gtksourceviewmm boost aspell aspell-en ``` Get juCi++ source, compile and install: From 38f49d4d7fcdc174ba612db58b1154ae42e2baf0 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Mon, 4 Jan 2016 09:57:31 +0100 Subject: [PATCH 56/90] Updated Run section --- docs/install.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/install.md b/docs/install.md index 3e844f5..86587c4 100644 --- a/docs/install.md +++ b/docs/install.md @@ -109,3 +109,7 @@ make install ```sh juci ``` +Alternatively, you can also include directories and files: +```sh +juci [directory] [file1 file2 ...] +``` From 25da8e59f1ceb48259b69c7cb025db88e4795a26 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 4 Jan 2016 10:48:37 +0100 Subject: [PATCH 57/90] Fixes to cmake builds --- src/cmake.cc | 7 +++++-- src/directories.cc | 1 + src/window.cc | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index c28a46b..7d7c2a5 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -161,7 +161,6 @@ bool CMake::create_debug_build(const boost::filesystem::path &project_path) { auto it=debug_build_needed.find(project_path.string()); if(it==debug_build_needed.end()) return true; - debug_build_needed.erase(it); } std::unique_ptr message; @@ -170,8 +169,12 @@ bool CMake::create_debug_build(const boost::filesystem::path &project_path) { filesystem::escape_argument(project_path)+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path); if(message) message->hide(); - if(exit_status==EXIT_SUCCESS) + if(exit_status==EXIT_SUCCESS) { + auto it=debug_build_needed.find(project_path.string()); + if(it!=debug_build_needed.end()) + debug_build_needed.erase(it); return true; + } return false; } diff --git a/src/directories.cc b/src/directories.cc index ab027a9..0265cf5 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -130,6 +130,7 @@ void Directories::open(const boost::filesystem::path& dir_path) { update_mutex.unlock(); cmake=std::unique_ptr(new CMake(dir_path)); + CMake::create_default_build(cmake->project_path); auto project=cmake->get_functions_parameters("project"); if(project.size()>0 && project[0].second.size()>0) get_column(0)->set_title(project[0].second[0]); diff --git a/src/window.cc b/src/window.cc index 584c3aa..9d2e6b5 100644 --- a/src/window.cc +++ b/src/window.cc @@ -211,7 +211,8 @@ std::unique_ptr Window::get_cmake() { auto cmake=std::unique_ptr(new CMake(path)); if(cmake->project_path.empty()) return nullptr; - CMake::create_default_build(cmake->project_path); + if(!CMake::create_default_build(cmake->project_path)) + return nullptr; return cmake; } From 9ee3255f5fc543cbb66f3b1b05943ba61f974f10 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 6 Jan 2016 09:21:49 +0100 Subject: [PATCH 58/90] Improved debug menu activation/deactivation, and now does no debug initialization before debug is run --- src/debug.cc | 15 ++++++++------- src/debug.h | 4 ++-- src/window.cc | 19 +++++++++++++++---- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 50b4b5a..d26d31c 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -27,7 +27,7 @@ void log(const char *msg, void *) { cout << "debugger log: " << msg << endl; } -Debug::Debug(): listener("juCi++ lldb listener"), state(lldb::StateType::eStateInvalid), buffer_size(131072) { +Debug::Debug(): state(lldb::StateType::eStateInvalid), buffer_size(131072) { #ifdef __APPLE__ auto debugserver_path=boost::filesystem::path("/usr/local/opt/llvm/bin/debugserver"); if(boost::filesystem::exists(debugserver_path)) @@ -40,9 +40,10 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat std::function callback, std::function status_callback, std::function stop_callback) { - if(!debugger.IsValid()) { + if(!debugger) { lldb::SBDebugger::Initialize(); - debugger=lldb::SBDebugger::Create(true, log, nullptr); + debugger=std::unique_ptr(new lldb::SBDebugger(lldb::SBDebugger::Create(true, log, nullptr))); + listener=std::unique_ptr(new lldb::SBListener("juCi++ lldb listener")); } //Create executable string and argument array @@ -78,7 +79,7 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat argv[c]=arguments[c].c_str(); argv[arguments.size()]=NULL; - auto target=debugger.CreateTarget(executable.c_str()); + auto target=debugger->CreateTarget(executable.c_str()); if(!target.IsValid()) { Terminal::get().async_print("Error (debug): Could not create debug target to: "+executable+'\n', true); if(callback) @@ -99,7 +100,7 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat } lldb::SBError 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))); + 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) @@ -112,7 +113,7 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat lldb::SBEvent event; while(true) { event_mutex.lock(); - if(listener.GetNextEvent(event)) { + if(listener->GetNextEvent(event)) { if((event.GetType() & lldb::SBProcess::eBroadcastBitStateChanged)>0) { auto state=process->GetStateFromEvent(event); this->state=state; @@ -271,7 +272,7 @@ std::pair Debug::run_command(const std::string &comman event_mutex.lock(); if(state==lldb::StateType::eStateStopped) { lldb::SBCommandReturnObject command_return_object; - debugger.GetCommandInterpreter().HandleCommand(command.c_str(), command_return_object, true); + debugger->GetCommandInterpreter().HandleCommand(command.c_str(), command_return_object, true); command_return.first=command_return_object.GetOutput(); command_return.second=command_return_object.GetError(); } diff --git a/src/debug.h b/src/debug.h index bd6c541..9ae597c 100644 --- a/src/debug.h +++ b/src/debug.h @@ -54,8 +54,8 @@ public: void write(const std::string &buffer); private: - lldb::SBDebugger debugger; - lldb::SBListener listener; + std::unique_ptr debugger; + std::unique_ptr listener; std::unique_ptr process; std::thread debug_thread; diff --git a/src/window.cc b/src/window.cc index 9d2e6b5..bfb80ea 100644 --- a/src/window.cc +++ b/src/window.cc @@ -963,10 +963,10 @@ void Window::set_menu_actions() { entry_box.show(); }); menu.add_action("debug_toggle_breakpoint", [this](){ - bool debug_is_stopped_or_running=Debug::get().is_stopped() || Debug::get().is_running(); - if(Debug::get().is_invalid() || debug_is_stopped_or_running) { - if(notebook.get_current_page()!=-1) { - auto view=notebook.get_current_view(); + if(notebook.get_current_page()!=-1) { + auto view=notebook.get_current_view(); + bool debug_is_stopped_or_running=Debug::get().is_stopped() || Debug::get().is_running(); + if(Debug::get().is_invalid() || debug_is_stopped_or_running) { auto line_nr=view->get_buffer()->get_insert()->get_iter().get_line(); if(view->get_source_buffer()->get_source_marks_at_line(line_nr, "debug_breakpoint").size()>0) { @@ -1057,6 +1057,17 @@ void Window::activate_menu_items(bool activate) { menu.actions["source_rename"]->set_enabled(activate ? static_cast(notebook.get_current_view()->rename_similar_tokens) : false); menu.actions["source_goto_next_diagnostic"]->set_enabled(activate ? static_cast(notebook.get_current_view()->goto_next_diagnostic) : false); menu.actions["source_apply_fix_its"]->set_enabled(activate ? static_cast(notebook.get_current_view()->apply_fix_its) : false); +#ifdef JUCI_ENABLE_DEBUG + if(notebook.get_current_page()!=-1) { + auto view=notebook.get_current_view(); + if(view->language->get_id()=="c" || view->language->get_id()=="cpp" || view->language->get_id()=="objc" || view->language->get_id()=="chdr" || view->language->get_id()=="cpphdr") + menu.actions["debug_toggle_breakpoint"]->set_enabled(true); + else + menu.actions["debug_toggle_breakpoint"]->set_enabled(false); + } + else + menu.actions["debug_toggle_breakpoint"]->set_enabled(false); +#endif } bool Window::on_key_press_event(GdkEventKey *event) { From b358917c78f76cb775a8ba030bc250419f21773c Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 7 Jan 2016 16:45:32 +0100 Subject: [PATCH 59/90] Fixed crash when opening unknown files --- src/window.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.cc b/src/window.cc index bfb80ea..e785404 100644 --- a/src/window.cc +++ b/src/window.cc @@ -1060,7 +1060,7 @@ void Window::activate_menu_items(bool activate) { #ifdef JUCI_ENABLE_DEBUG if(notebook.get_current_page()!=-1) { auto view=notebook.get_current_view(); - if(view->language->get_id()=="c" || view->language->get_id()=="cpp" || view->language->get_id()=="objc" || view->language->get_id()=="chdr" || view->language->get_id()=="cpphdr") + if(view->language && (view->language->get_id()=="c" || view->language->get_id()=="cpp" || view->language->get_id()=="objc" || view->language->get_id()=="chdr" || view->language->get_id()=="cpphdr")) menu.actions["debug_toggle_breakpoint"]->set_enabled(true); else menu.actions["debug_toggle_breakpoint"]->set_enabled(false); From 5a0420113128342f605a6cbf82ccada9b69cccee Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 9 Jan 2016 08:47:48 +0100 Subject: [PATCH 60/90] Added module filename in backtrace --- src/debug.cc | 6 ++++++ src/debug.h | 1 + src/window.cc | 6 +++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index d26d31c..af354d5 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -291,6 +291,12 @@ std::vector Debug::get_backtrace() { auto function_name=frame.GetFunctionName(); if(function_name!=NULL) backtrace_frame.function_name=function_name; + + auto module_filename=frame.GetModule().GetFileSpec().GetFilename(); + if(module_filename!=NULL) { + backtrace_frame.module_filename=module_filename; + } + auto line_entry=frame.GetLineEntry(); if(line_entry.IsValid()) { lldb::SBStream stream; diff --git a/src/debug.h b/src/debug.h index 9ae597c..e79b2fe 100644 --- a/src/debug.h +++ b/src/debug.h @@ -13,6 +13,7 @@ class Debug { public: class Frame { public: + std::string module_filename; std::string file_path; std::string function_name; int line_nr; diff --git a/src/window.cc b/src/window.cc index e785404..84290ca 100644 --- a/src/window.cc +++ b/src/window.cc @@ -912,12 +912,12 @@ void Window::set_menu_actions() { return; for(auto &frame: backtrace) { - std::string row; + std::string row=""+frame.module_filename+""; if(frame.file_path.empty()) - row=frame.function_name; + row+=" - "+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); + 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); From fe219a6e257ce4e30f4304a2fa0a7719ab763f5e Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 9 Jan 2016 09:32:58 +0100 Subject: [PATCH 61/90] Making frame variable smaller if it is too long when using backtrace, and dialogs are now moved to the start of line if activated on iter columns>=80 --- src/source_clang.cc | 2 ++ src/window.cc | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/source_clang.cc b/src/source_clang.cc index e3f8982..c1a7210 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -1195,6 +1195,8 @@ Source::ClangViewAutocomplete(file_path, project_path, language) { goto_method=[this](){ if(parsed) { auto iter=get_buffer()->get_insert()->get_iter(); + if(iter.get_line_offset()>=80) + iter=get_buffer()->get_iter_at_line(iter.get_line()); Gdk::Rectangle visible_rect; get_visible_rect(visible_rect); Gdk::Rectangle iter_rect; diff --git a/src/window.cc b/src/window.cc index 84290ca..7f675bd 100644 --- a/src/window.cc +++ b/src/window.cc @@ -514,6 +514,8 @@ void Window::set_menu_actions() { auto token=current_view->get_token(); if(token) { auto iter=current_view->get_buffer()->get_insert()->get_iter(); + if(iter.get_line_offset()>=80) + iter=current_view->get_buffer()->get_iter_at_line(iter.get_line()); Gdk::Rectangle visible_rect; current_view->get_visible_rect(visible_rect); Gdk::Rectangle iter_rect; @@ -898,6 +900,8 @@ void Window::set_menu_actions() { auto view=notebook.get_current_view(); auto buffer=view->get_buffer(); auto iter=buffer->get_insert()->get_iter(); + if(iter.get_line_offset()>=80) + iter=buffer->get_iter_at_line(iter.get_line()); Gdk::Rectangle visible_rect; view->get_visible_rect(visible_rect); Gdk::Rectangle iter_rect; @@ -913,11 +917,16 @@ void Window::set_menu_actions() { 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+=" - "+frame.function_name; + 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); + 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); From 1e20e6cdd73b2584d84a4872ec825bdefc7ae69d Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 9 Jan 2016 10:03:15 +0100 Subject: [PATCH 62/90] Now selects the frame when backtrace row is activated --- src/debug.cc | 12 ++++++++++++ src/debug.h | 2 ++ src/window.cc | 2 ++ 3 files changed, 16 insertions(+) diff --git a/src/debug.cc b/src/debug.cc index af354d5..68e3516 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -288,6 +288,9 @@ std::vector Debug::get_backtrace() { for(uint32_t c_f=0;c_f Debug::get_backtrace() { return backtrace; } +void Debug::select_frame(uint32_t index) { + event_mutex.lock(); + if(state==lldb::StateType::eStateStopped) { + auto thread=process->GetSelectedThread(); + thread.SetSelectedFrame(index); + } + event_mutex.unlock(); +} + void Debug::delete_debug() { kill(); if(debug_thread.joinable()) diff --git a/src/debug.h b/src/debug.h index e79b2fe..c8af1dc 100644 --- a/src/debug.h +++ b/src/debug.h @@ -13,6 +13,7 @@ class Debug { public: class Frame { public: + uint32_t index; std::string module_filename; std::string file_path; std::string function_name; @@ -40,6 +41,7 @@ public: void step_out(); std::pair run_command(const std::string &command); std::vector get_backtrace(); + void select_frame(uint32_t index); void delete_debug(); //can't use delete as function name diff --git a/src/window.cc b/src/window.cc index 7f675bd..9dbd011 100644 --- a/src/window.cc +++ b/src/window.cc @@ -939,6 +939,8 @@ void Window::set_menu_actions() { 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)) From 4221f1eebbc38b4515dba50144c589ec053d9f29 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 9 Jan 2016 10:17:09 +0100 Subject: [PATCH 63/90] Fixed error message when trying to open a file within a non-existing folder --- src/juci.cc | 6 +++++- src/juci.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/juci.cc b/src/juci.cc index 250afab..3c52331 100644 --- a/src/juci.cc +++ b/src/juci.cc @@ -32,7 +32,7 @@ int Application::on_command_line(const Glib::RefPtr files.emplace_back(new_p); } else - Terminal::get().print("Error: folder path "+parent_p.string()+" does not exist.\n", true); + errors.emplace_back("Error: folder path "+parent_p.string()+" does not exist.\n"); } } } @@ -66,8 +66,12 @@ void Application::on_activate() { another_juci_app.detach(); } } + for(auto &file: files) Window::get().notebook.open(file); + + for(auto &error: errors) + Terminal::get().print(error, true); } void Application::on_startup() { diff --git a/src/juci.h b/src/juci.h index a957b87..81682f2 100644 --- a/src/juci.h +++ b/src/juci.h @@ -13,6 +13,7 @@ public: private: std::vector directories; std::vector files; + std::vector errors; }; #endif // JUCI_JUCI_H_ From fa0fa7551ced3489f4589ca7eaaef5438dda2604 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 9 Jan 2016 13:50:00 +0100 Subject: [PATCH 64/90] Can now run debug commands while debug is running --- src/debug.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.cc b/src/debug.cc index 68e3516..161f8a2 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -270,7 +270,7 @@ void Debug::step_out() { std::pair Debug::run_command(const std::string &command) { std::pair command_return; event_mutex.lock(); - if(state==lldb::StateType::eStateStopped) { + if(state==lldb::StateType::eStateStopped || state==lldb::StateType::eStateRunning) { lldb::SBCommandReturnObject command_return_object; debugger->GetCommandInterpreter().HandleCommand(command.c_str(), command_return_object, true); command_return.first=command_return_object.GetOutput(); From 246955d2926df5b214cd17c5affc2e47887104ee Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 10 Jan 2016 12:04:53 +0100 Subject: [PATCH 65/90] Minor change --- src/window.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.cc b/src/window.cc index 9dbd011..cb31622 100644 --- a/src/window.cc +++ b/src/window.cc @@ -926,7 +926,7 @@ void Window::set_menu_actions() { 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); + 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); From 376a306964436bd4a8bf1bfdf7de4a4b53e94c93 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 10 Jan 2016 21:07:41 +0100 Subject: [PATCH 66/90] Non-utf8 chars from lldb values are now shown as '?' --- src/source_clang.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/source_clang.cc b/src/source_clang.cc index c1a7210..e08a927 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -418,12 +418,18 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) #ifdef JUCI_ENABLE_DEBUG auto location=token.get_cursor().get_referenced().get_source_location(); - auto debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line); + Glib::ustring debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line); if(!debug_value.empty()) { - debug_value.pop_back(); size_t pos=debug_value.find(" = "); - if(pos!=std::string::npos) - tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\nValue: "+debug_value.substr(pos+3), "def:note"); + if(pos!=Glib::ustring::npos) { + Glib::ustring::iterator iter; + while(!debug_value.validate(iter)) { + auto next_char_iter=iter; + next_char_iter++; + debug_value.replace(iter, next_char_iter, "?"); + } + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\nValue: "+debug_value.substr(pos+3, debug_value.size()-4), "def:note"); + } } #endif From bd68b222a0d2fbb729b2ad69744a7e1422b6e0d3 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 10 Jan 2016 21:25:33 +0100 Subject: [PATCH 67/90] Fixed debug value substring --- src/source_clang.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source_clang.cc b/src/source_clang.cc index e08a927..d3c6268 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -428,7 +428,7 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) next_char_iter++; debug_value.replace(iter, next_char_iter, "?"); } - tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\nValue: "+debug_value.substr(pos+3, debug_value.size()-4), "def:note"); + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\nValue: "+debug_value.substr(pos+3, debug_value.size()-(pos+3)-1), "def:note"); } } #endif From 6d6d2f31da96e95a0fccd5373cdb575a2a7a3684 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 10 Jan 2016 22:41:43 +0100 Subject: [PATCH 68/90] Added return value (lldb supports this when doing step out) --- src/debug.cc | 23 +++++++++++++++++++++++ src/debug.h | 1 + src/source_clang.cc | 30 +++++++++++++++++++----------- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 161f8a2..6e83e68 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -375,6 +375,29 @@ std::string Debug::get_value(const std::string &variable, const boost::filesyste return variable_value; } +std::string Debug::get_return_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index) { + std::string return_value; + event_mutex.lock(); + if(state==lldb::StateType::eStateStopped) { + auto thread=process->GetSelectedThread(); + auto thread_return_value=thread.GetStopReturnValue(); + if(thread_return_value.IsValid()) { + auto line_entry=thread.GetSelectedFrame().GetLineEntry(); + if(line_entry.IsValid()) { + lldb::SBStream stream; + line_entry.GetFileSpec().GetDescription(stream); + if(boost::filesystem::path(stream.GetData())==file_path && line_entry.GetLine()==line_nr && line_entry.GetColumn()==line_index) { + lldb::SBStream stream; + thread_return_value.GetDescription(stream); + return_value=stream.GetData(); + } + } + } + } + event_mutex.unlock(); + return return_value; +} + bool Debug::is_invalid() { bool invalid; event_mutex.lock(); diff --git a/src/debug.h b/src/debug.h index c8af1dc..45b9a0e 100644 --- a/src/debug.h +++ b/src/debug.h @@ -46,6 +46,7 @@ public: void delete_debug(); //can't use delete as function name std::string get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr); + std::string get_return_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index); bool is_invalid(); bool is_stopped(); diff --git a/src/source_clang.cc b/src/source_clang.cc index d3c6268..142d563 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -417,18 +417,26 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\n"+brief_comment, "def:note"); #ifdef JUCI_ENABLE_DEBUG - auto location=token.get_cursor().get_referenced().get_source_location(); - Glib::ustring debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line); - if(!debug_value.empty()) { - size_t pos=debug_value.find(" = "); - if(pos!=Glib::ustring::npos) { - Glib::ustring::iterator iter; - while(!debug_value.validate(iter)) { - auto next_char_iter=iter; - next_char_iter++; - debug_value.replace(iter, next_char_iter, "?"); + if(Debug::get().is_stopped()) { + auto location=token.get_cursor().get_referenced().get_source_location(); + Glib::ustring value_type="Value"; + Glib::ustring debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line); + if(debug_value.empty()) { + value_type="Return value"; + auto location=token.get_cursor().get_source_location(); + debug_value=Debug::get().get_return_value(token.get_spelling(), location.get_path(), location.get_offset().line, location.get_offset().index); + } + if(!debug_value.empty()) { + size_t pos=debug_value.find(" = "); + if(pos!=Glib::ustring::npos) { + Glib::ustring::iterator iter; + while(!debug_value.validate(iter)) { + auto next_char_iter=iter; + next_char_iter++; + debug_value.replace(iter, next_char_iter, "?"); + } + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\n"+value_type+": "+debug_value.substr(pos+3, debug_value.size()-(pos+3)-1), "def:note"); } - tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "\n\nValue: "+debug_value.substr(pos+3, debug_value.size()-(pos+3)-1), "def:note"); } } #endif From d2427b727b652e19a8808892451a65bf1292c10f Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sun, 10 Jan 2016 23:01:19 +0100 Subject: [PATCH 69/90] Debug::get_return_value cleanup, and now works on older lldb versions --- src/debug.cc | 5 +++-- src/debug.h | 2 +- src/source_clang.cc | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 6e83e68..29703c0 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -375,7 +375,7 @@ std::string Debug::get_value(const std::string &variable, const boost::filesyste return variable_value; } -std::string Debug::get_return_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index) { +std::string Debug::get_return_value(const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index) { std::string return_value; event_mutex.lock(); if(state==lldb::StateType::eStateStopped) { @@ -386,7 +386,8 @@ std::string Debug::get_return_value(const std::string &variable, const boost::fi if(line_entry.IsValid()) { lldb::SBStream stream; line_entry.GetFileSpec().GetDescription(stream); - if(boost::filesystem::path(stream.GetData())==file_path && line_entry.GetLine()==line_nr && line_entry.GetColumn()==line_index) { + if(boost::filesystem::path(stream.GetData())==file_path && line_entry.GetLine()==line_nr && + (line_entry.GetColumn()==0 || line_entry.GetColumn()==line_index)) { lldb::SBStream stream; thread_return_value.GetDescription(stream); return_value=stream.GetData(); diff --git a/src/debug.h b/src/debug.h index 45b9a0e..6f4a2c2 100644 --- a/src/debug.h +++ b/src/debug.h @@ -46,7 +46,7 @@ public: void delete_debug(); //can't use delete as function name std::string get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr); - std::string get_return_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index); + std::string get_return_value(const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index); bool is_invalid(); bool is_stopped(); diff --git a/src/source_clang.cc b/src/source_clang.cc index 142d563..a36a318 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -424,7 +424,7 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) if(debug_value.empty()) { value_type="Return value"; auto location=token.get_cursor().get_source_location(); - debug_value=Debug::get().get_return_value(token.get_spelling(), location.get_path(), location.get_offset().line, location.get_offset().index); + debug_value=Debug::get().get_return_value(location.get_path(), location.get_offset().line, location.get_offset().index); } if(!debug_value.empty()) { size_t pos=debug_value.find(" = "); From 534a2454530bc41cbc78bbe7975920300e9df6db Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 11 Jan 2016 22:37:35 +0100 Subject: [PATCH 70/90] Debug return value now found based on previous frame function name --- src/debug.cc | 13 ++++++++++--- src/debug.h | 5 ++++- src/source_clang.cc | 3 +-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 29703c0..25003ab 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -126,6 +126,13 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat break; } } + + last_function_name=current_function_name; + auto function_name_cstr=process->GetSelectedThread().GetSelectedFrame().GetFunctionName(); + if(function_name_cstr!=NULL) + current_function_name=function_name_cstr; + else + current_function_name.clear(); } //Update debug status @@ -375,7 +382,7 @@ std::string Debug::get_value(const std::string &variable, const boost::filesyste return variable_value; } -std::string Debug::get_return_value(const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index) { +std::string Debug::get_return_value(const std::string &function_name, const boost::filesystem::path &file_path) { std::string return_value; event_mutex.lock(); if(state==lldb::StateType::eStateStopped) { @@ -386,8 +393,8 @@ std::string Debug::get_return_value(const boost::filesystem::path &file_path, un if(line_entry.IsValid()) { lldb::SBStream stream; line_entry.GetFileSpec().GetDescription(stream); - if(boost::filesystem::path(stream.GetData())==file_path && line_entry.GetLine()==line_nr && - (line_entry.GetColumn()==0 || line_entry.GetColumn()==line_index)) { + auto pos=last_function_name.find('('); + if(pos!=std::string::npos && last_function_name.substr(0, pos)==function_name && boost::filesystem::path(stream.GetData())==file_path) { lldb::SBStream stream; thread_return_value.GetDescription(stream); return_value=stream.GetData(); diff --git a/src/debug.h b/src/debug.h index 6f4a2c2..9d4f1a9 100644 --- a/src/debug.h +++ b/src/debug.h @@ -46,7 +46,7 @@ public: void delete_debug(); //can't use delete as function name std::string get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr); - std::string get_return_value(const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index); + std::string get_return_value(const std::string &function_name, const boost::filesystem::path &file_path); bool is_invalid(); bool is_stopped(); @@ -67,6 +67,9 @@ private: std::mutex event_mutex; size_t buffer_size; + + std::string last_function_name; + std::string current_function_name; }; #endif diff --git a/src/source_clang.cc b/src/source_clang.cc index a36a318..e8892b5 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -423,8 +423,7 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) Glib::ustring debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line); if(debug_value.empty()) { value_type="Return value"; - auto location=token.get_cursor().get_source_location(); - debug_value=Debug::get().get_return_value(location.get_path(), location.get_offset().line, location.get_offset().index); + debug_value=Debug::get().get_return_value(token.get_spelling(), token.get_cursor().get_source_location().get_path()); } if(!debug_value.empty()) { size_t pos=debug_value.find(" = "); From a087f1408ddba2581823cca05b3c851591f13fb0 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Mon, 11 Jan 2016 22:50:37 +0100 Subject: [PATCH 71/90] Corrected debug return value --- src/debug.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/debug.cc b/src/debug.cc index 25003ab..40edcf3 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -393,7 +393,9 @@ std::string Debug::get_return_value(const std::string &function_name, const boos if(line_entry.IsValid()) { lldb::SBStream stream; line_entry.GetFileSpec().GetDescription(stream); - auto pos=last_function_name.find('('); + auto pos=last_function_name.find('['); + if(pos==std::string::npos) + pos=last_function_name.find('('); if(pos!=std::string::npos && last_function_name.substr(0, pos)==function_name && boost::filesystem::path(stream.GetData())==file_path) { lldb::SBStream stream; thread_return_value.GetDescription(stream); From f613369f61daeaee51b04af90dedc5d70f87176c Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 11 Jan 2016 22:59:17 +0100 Subject: [PATCH 72/90] Revert "Corrected debug return value" This reverts commit a087f1408ddba2581823cca05b3c851591f13fb0. --- src/debug.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 40edcf3..25003ab 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -393,9 +393,7 @@ std::string Debug::get_return_value(const std::string &function_name, const boos if(line_entry.IsValid()) { lldb::SBStream stream; line_entry.GetFileSpec().GetDescription(stream); - auto pos=last_function_name.find('['); - if(pos==std::string::npos) - pos=last_function_name.find('('); + auto pos=last_function_name.find('('); if(pos!=std::string::npos && last_function_name.substr(0, pos)==function_name && boost::filesystem::path(stream.GetData())==file_path) { lldb::SBStream stream; thread_return_value.GetDescription(stream); From 30f7411ccf158dff6b2428642b08af83dbea71c8 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 11 Jan 2016 22:59:28 +0100 Subject: [PATCH 73/90] Revert "Debug return value now found based on previous frame function name" This reverts commit 534a2454530bc41cbc78bbe7975920300e9df6db. --- src/debug.cc | 13 +++---------- src/debug.h | 5 +---- src/source_clang.cc | 3 ++- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 25003ab..29703c0 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -126,13 +126,6 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat break; } } - - last_function_name=current_function_name; - auto function_name_cstr=process->GetSelectedThread().GetSelectedFrame().GetFunctionName(); - if(function_name_cstr!=NULL) - current_function_name=function_name_cstr; - else - current_function_name.clear(); } //Update debug status @@ -382,7 +375,7 @@ std::string Debug::get_value(const std::string &variable, const boost::filesyste return variable_value; } -std::string Debug::get_return_value(const std::string &function_name, const boost::filesystem::path &file_path) { +std::string Debug::get_return_value(const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index) { std::string return_value; event_mutex.lock(); if(state==lldb::StateType::eStateStopped) { @@ -393,8 +386,8 @@ std::string Debug::get_return_value(const std::string &function_name, const boos if(line_entry.IsValid()) { lldb::SBStream stream; line_entry.GetFileSpec().GetDescription(stream); - auto pos=last_function_name.find('('); - if(pos!=std::string::npos && last_function_name.substr(0, pos)==function_name && boost::filesystem::path(stream.GetData())==file_path) { + if(boost::filesystem::path(stream.GetData())==file_path && line_entry.GetLine()==line_nr && + (line_entry.GetColumn()==0 || line_entry.GetColumn()==line_index)) { lldb::SBStream stream; thread_return_value.GetDescription(stream); return_value=stream.GetData(); diff --git a/src/debug.h b/src/debug.h index 9d4f1a9..6f4a2c2 100644 --- a/src/debug.h +++ b/src/debug.h @@ -46,7 +46,7 @@ public: void delete_debug(); //can't use delete as function name std::string get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr); - std::string get_return_value(const std::string &function_name, const boost::filesystem::path &file_path); + std::string get_return_value(const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index); bool is_invalid(); bool is_stopped(); @@ -67,9 +67,6 @@ private: std::mutex event_mutex; size_t buffer_size; - - std::string last_function_name; - std::string current_function_name; }; #endif diff --git a/src/source_clang.cc b/src/source_clang.cc index e8892b5..a36a318 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -423,7 +423,8 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) Glib::ustring debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line); if(debug_value.empty()) { value_type="Return value"; - debug_value=Debug::get().get_return_value(token.get_spelling(), token.get_cursor().get_source_location().get_path()); + auto location=token.get_cursor().get_source_location(); + debug_value=Debug::get().get_return_value(location.get_path(), location.get_offset().line, location.get_offset().index); } if(!debug_value.empty()) { size_t pos=debug_value.find(" = "); From bc7fcdf01d0b8ca177385c4aca1b4e6fc2f42d29 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Tue, 12 Jan 2016 16:30:14 +0100 Subject: [PATCH 74/90] Added Show Variables in Debug menu --- src/debug.cc | 42 ++++++++++++++++++++ src/debug.h | 10 +++++ src/files.h | 3 +- src/menu.cc | 5 +++ src/selectiondialog.cc | 14 ++++++- src/selectiondialog.h | 1 + src/window.cc | 89 ++++++++++++++++++++++++++++++++++++++++++ src/window.h | 3 ++ 8 files changed, 165 insertions(+), 2 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 29703c0..47c1e20 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -318,6 +318,48 @@ std::vector Debug::get_backtrace() { return backtrace; } +std::vector Debug::get_variables() { + vector variables; + event_mutex.lock(); + if(state==lldb::StateType::eStateStopped) { + for(uint32_t c_t=0;c_tGetNumThreads();c_t++) { + auto thread=process->GetThreadAtIndex(c_t); + for(uint32_t c_f=0;c_f run_command(const std::string &command); std::vector get_backtrace(); + std::vector get_variables(); void select_frame(uint32_t index); void delete_debug(); //can't use delete as function name diff --git a/src/files.h b/src/files.h index d50436e..0970ccf 100644 --- a/src/files.h +++ b/src/files.h @@ -2,7 +2,7 @@ #define JUCI_FILES_H_ #include -#define JUCI_VERSION "1.1.0-3" +#define JUCI_VERSION "1.1.0-4" const std::string configjson = "{\n" @@ -107,6 +107,7 @@ const std::string configjson = " \"debug_step_into\": \"t\",\n" " \"debug_step_out\": \"t\",\n" " \"debug_backtrace\": \"j\",\n" +" \"debug_show_variables\": \"b\",\n" " \"debug_run_command\": \"Return\",\n" " \"debug_toggle_breakpoint\": \"b\",\n" " \"debug_goto_stop\": \"l\",\n" diff --git a/src/menu.cc b/src/menu.cc index 3612c6c..3627947 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -320,6 +320,11 @@ Menu::Menu() { " app.debug_backtrace" +accels["debug_backtrace"]+ //For Ubuntu... " " + " " + " _Show _Variables" + " app.debug_show_variables" + +accels["debug_show_variables"]+ //For Ubuntu... + " " "
" "
" " " diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index 187a304..f4c82cc 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -72,6 +72,18 @@ list_view_text(use_markup), start_mark(start_mark), show_search_entry(show_searc }); } + list_view_text.signal_cursor_changed().connect([this]() { + if(!shown) + return; + auto it=list_view_text.get_selection()->get_selected(); + if(it) { + std::string row; + it->get_value(0, row); + if(on_changed) + on_changed(row); + } + }); + scrolled_window.add(list_view_text); if(!show_search_entry) window->add(scrolled_window); @@ -102,13 +114,13 @@ void SelectionDialogBase::show() { void SelectionDialogBase::hide() { if(!shown) return; + shown=false; window->hide(); if(tooltips) tooltips->hide(); if(on_hide) on_hide(); list_view_text.clear(); - shown=false; } void SelectionDialogBase::update_tooltips() { diff --git a/src/selectiondialog.h b/src/selectiondialog.h index 7c6d901..36f2747 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -35,6 +35,7 @@ public: virtual void move(); std::function on_hide; + std::function on_changed; std::function on_select; Glib::RefPtr start_mark; diff --git a/src/window.cc b/src/window.cc index cb31622..0e1ea3a 100644 --- a/src/window.cc +++ b/src/window.cc @@ -154,6 +154,7 @@ Window::Window() : compiling(false), debugging(false) { menu.actions["debug_step_into"]->set_enabled(false); menu.actions["debug_step_out"]->set_enabled(false); menu.actions["debug_backtrace"]->set_enabled(false); + menu.actions["debug_show_variables"]->set_enabled(false); menu.actions["debug_run_command"]->set_enabled(false); menu.actions["debug_goto_stop"]->set_enabled(false); #endif @@ -168,6 +169,7 @@ Window::Window() : compiling(false), debugging(false) { menu.actions["debug_step_into"]->set_enabled(false); menu.actions["debug_step_out"]->set_enabled(false); menu.actions["debug_backtrace"]->set_enabled(false); + menu.actions["debug_show_variables"]->set_enabled(false); menu.actions["debug_run_command"]->set_enabled(false); menu.actions["debug_goto_stop"]->set_enabled(false); } @@ -180,6 +182,7 @@ Window::Window() : compiling(false), debugging(false) { menu.actions["debug_step_into"]->set_enabled(); menu.actions["debug_step_out"]->set_enabled(); menu.actions["debug_backtrace"]->set_enabled(); + menu.actions["debug_show_variables"]->set_enabled(); menu.actions["debug_run_command"]->set_enabled(); menu.actions["debug_goto_stop"]->set_enabled(); } @@ -953,6 +956,92 @@ void Window::set_menu_actions() { view->selection_dialog->show(); } }); + 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 buffer=view->get_buffer(); + auto iter=buffer->get_insert()->get_iter(); + if(iter.get_line_offset()>=80) + iter=buffer->get_iter_at_line(iter.get_line()); + Gdk::Rectangle visible_rect; + view->get_visible_rect(visible_rect); + Gdk::Rectangle iter_rect; + view->get_iter_location(iter, iter_rect); + iter_rect.set_width(1); + if(!visible_rect.intersects(iter_rect)) { + view->get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3); + } + view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, buffer->create_mark(iter), true, true)); + auto rows=std::make_shared >(); + if(variables.size()==0) + return; + + for(auto &variable: variables) { + std::string row=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); + + 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]() { + if(debug_variable_tooltips) { + debug_variable_tooltips->hide(); + debug_variable_tooltips.reset(); + } + }; + + view->selection_dialog->on_changed=[this, rows, iter](const std::string &selected) { + if(notebook.get_current_page()!=-1) { + auto view=notebook.get_current_view(); + debug_variable_tooltips=std::unique_ptr(new Tooltips()); + 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(); + } + }); menu.add_action("debug_run_command", [this]() { entry_box.clear(); entry_box.entries.emplace_back(last_run_debug_command, [this](const std::string& content){ diff --git a/src/window.h b/src/window.h index 51f5215..6c55d87 100644 --- a/src/window.h +++ b/src/window.h @@ -5,6 +5,7 @@ #include "entrybox.h" #include "notebook.h" #include "cmake.h" +#include "tooltips.h" #include class Window : public Gtk::ApplicationWindow { @@ -46,6 +47,8 @@ private: std::string debug_status; std::mutex debug_status_mutex; Glib::Dispatcher debug_update_status; + + std::unique_ptr debug_variable_tooltips; std::unique_ptr get_cmake(); std::unordered_map project_run_arguments; From bd668eedfc47188ada80be86bb4598a939cc851d Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 12 Jan 2016 19:23:10 +0100 Subject: [PATCH 75/90] selectiondialog.* cleanup --- src/selectiondialog.cc | 144 ++++++++++++++++++++++------------------- src/selectiondialog.h | 30 +++++---- src/window.cc | 4 ++ 3 files changed, 99 insertions(+), 79 deletions(-) diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index f4c82cc..1cb27e2 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -59,31 +59,6 @@ list_view_text(use_markup), start_mark(start_mark), show_search_entry(show_searc resize(); }); - list_view_text.signal_event_after().connect([this](GdkEvent* event){ - if(event->type==GDK_KEY_PRESS || event->type==GDK_BUTTON_PRESS) { - update_tooltips(); - } - }); - if(show_search_entry) { - search_entry.signal_event_after().connect([this](GdkEvent* event){ - if(event->type==GDK_KEY_PRESS || event->type==GDK_BUTTON_PRESS) { - update_tooltips(); - } - }); - } - - list_view_text.signal_cursor_changed().connect([this]() { - if(!shown) - return; - auto it=list_view_text.get_selection()->get_selected(); - if(it) { - std::string row; - it->get_value(0, row); - if(on_changed) - on_changed(row); - } - }); - scrolled_window.add(list_view_text); if(!show_search_entry) window->add(scrolled_window); @@ -99,10 +74,8 @@ SelectionDialogBase::~SelectionDialogBase() { text_view.get_buffer()->delete_mark(start_mark); } -void SelectionDialogBase::add_row(const std::string& row, const std::string& tooltip) { +void SelectionDialogBase::add_row(const std::string& row) { list_view_text.append(row); - if(tooltip.size()>0) - tooltip_texts[row]=tooltip; } void SelectionDialogBase::show() { @@ -116,45 +89,11 @@ void SelectionDialogBase::hide() { return; shown=false; window->hide(); - if(tooltips) - tooltips->hide(); if(on_hide) on_hide(); list_view_text.clear(); } -void SelectionDialogBase::update_tooltips() { - auto it=list_view_text.get_selection()->get_selected(); - if(it) { - std::string row; - it->get_value(0, row); - if(row!=last_row || last_row.size()==0) { - if(tooltips) - tooltips->hide(); - auto it=tooltip_texts.find(row); - if(it!=tooltip_texts.end()) { - auto tooltip_text=it->second; - if(tooltip_text.size()>0) { - tooltips=std::unique_ptr(new Tooltips()); - auto get_tooltip_buffer=[this, tooltip_text]() { - auto tooltip_buffer=Gtk::TextBuffer::create(text_view.get_buffer()->get_tag_table()); - tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), tooltip_text, "def:note"); - return tooltip_buffer; - }; - tooltips->emplace_back(get_tooltip_buffer, text_view, text_view.get_buffer()->create_mark(start_mark->get_iter()), text_view.get_buffer()->create_mark(text_view.get_buffer()->get_insert()->get_iter())); - tooltips->show(true); - } - } - } - last_row=row; - } - else { - last_row=""; - if(tooltips) - tooltips->hide(); - } -} - void SelectionDialogBase::move() { Gdk::Rectangle rectangle; text_view.get_iter_location(start_mark->get_iter(), rectangle); @@ -190,7 +129,21 @@ void SelectionDialogBase::resize() { } } -SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup) : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) {} +SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup) : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) { + list_view_text.signal_cursor_changed().connect([this]() { + if(!shown) + return; + auto it=list_view_text.get_selection()->get_selected(); + std::string row; + if(it) + it->get_value(0, row); + if(last_row==row) + return; + if(on_changed) + on_changed(row); + last_row=row; + }); +} void SelectionDialog::show() { SelectionDialogBase::show(); @@ -284,10 +237,8 @@ void SelectionDialog::show() { return true; }); - if(list_view_text.get_model()->children().size()>0) { + if(list_view_text.get_model()->children().size()>0) list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); - update_tooltips(); - } } bool SelectionDialog::on_key_press(GdkEventKey* key) { @@ -331,7 +282,26 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { return false; } -CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark) : SelectionDialogBase(text_view, start_mark, false, false) {} +CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark) : SelectionDialogBase(text_view, start_mark, false, false) { + list_view_text.signal_event_after().connect([this](GdkEvent* event){ + if(event->type==GDK_KEY_PRESS || event->type==GDK_BUTTON_PRESS) { + update_tooltips(); + } + }); + if(show_search_entry) { + search_entry.signal_event_after().connect([this](GdkEvent* event){ + if(event->type==GDK_KEY_PRESS || event->type==GDK_BUTTON_PRESS) { + update_tooltips(); + } + }); + } +} + +void CompletionDialog::add_row(const std::string& row, const std::string& tooltip) { + SelectionDialogBase::add_row(row); + if(tooltip.size()>0) + tooltip_texts[row]=tooltip; +} void CompletionDialog::show() { SelectionDialogBase::show(); @@ -384,6 +354,14 @@ void CompletionDialog::show() { } } +void CompletionDialog::hide() { + if(!shown) + return; + SelectionDialogBase::hide(); + if(tooltips) + tooltips->hide(); +} + void CompletionDialog::select(bool hide_window) { row_in_entry=true; @@ -480,3 +458,35 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) { return true; return false; } + +void CompletionDialog::update_tooltips() { + auto it=list_view_text.get_selection()->get_selected(); + if(it) { + std::string row; + it->get_value(0, row); + if(row!=last_row || last_row.size()==0) { + if(tooltips) + tooltips->hide(); + auto it=tooltip_texts.find(row); + if(it!=tooltip_texts.end()) { + auto tooltip_text=it->second; + if(tooltip_text.size()>0) { + tooltips=std::unique_ptr(new Tooltips()); + auto get_tooltip_buffer=[this, tooltip_text]() { + auto tooltip_buffer=Gtk::TextBuffer::create(text_view.get_buffer()->get_tag_table()); + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), tooltip_text, "def:note"); + return tooltip_buffer; + }; + tooltips->emplace_back(get_tooltip_buffer, text_view, text_view.get_buffer()->create_mark(start_mark->get_iter()), text_view.get_buffer()->create_mark(text_view.get_buffer()->get_insert()->get_iter())); + tooltips->show(true); + } + } + } + last_row=row; + } + else { + last_row=""; + if(tooltips) + tooltips->hide(); + } +} diff --git a/src/selectiondialog.h b/src/selectiondialog.h index 36f2747..0c9b1e5 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -29,20 +29,18 @@ class SelectionDialogBase { public: SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup); ~SelectionDialogBase(); - virtual void add_row(const std::string& row, const std::string& tooltip=""); - virtual void show(); - virtual void hide(); - virtual void move(); + void add_row(const std::string& row); + void show(); + void hide(); + void move(); std::function on_hide; - std::function on_changed; std::function on_select; Glib::RefPtr start_mark; bool shown=false; protected: - virtual void resize(); - virtual void update_tooltips(); + void resize(); Gtk::TextView& text_view; std::unique_ptr window; @@ -50,22 +48,25 @@ protected: ListViewText list_view_text; Gtk::Entry search_entry; bool show_search_entry; - std::unique_ptr tooltips; - std::unordered_map tooltip_texts; - std::string last_row; }; class SelectionDialog : public SelectionDialogBase { public: SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry=true, bool use_markup=false); bool on_key_press(GdkEventKey* key); - void show() override; + void show(); + + std::function on_changed; +private: + std::string last_row; }; class CompletionDialog : public SelectionDialogBase { public: CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark); - void show() override; + void add_row(const std::string& row, const std::string& tooltip); + void show(); + void hide(); bool on_key_release(GdkEventKey* key); bool on_key_press(GdkEventKey* key); @@ -74,6 +75,11 @@ private: int show_offset; bool row_in_entry=false; + + void update_tooltips(); + std::unique_ptr tooltips; + std::unordered_map tooltip_texts; + std::string last_row; }; #endif // JUCI_SELECTIONDIALOG_H_ \ No newline at end of file diff --git a/src/window.cc b/src/window.cc index 0e1ea3a..15c5d40 100644 --- a/src/window.cc +++ b/src/window.cc @@ -1012,6 +1012,10 @@ void Window::set_menu_actions() { }; 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=std::unique_ptr(new Tooltips()); From 653d77776f2f2199c42a1c5cc08c18e62b75c2cb Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 12 Jan 2016 20:04:56 +0100 Subject: [PATCH 76/90] Debug show variables finished --- src/debug.cc | 11 ++++++----- src/debug.h | 3 ++- src/source_clang.cc | 2 +- src/window.cc | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 47c1e20..954bf27 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -24,7 +24,7 @@ using namespace std; //TODO: remove extern char **environ; void log(const char *msg, void *) { - cout << "debugger log: " << msg << endl; + std::cout << "debugger log: " << msg << std::endl; } Debug::Debug(): state(lldb::StateType::eStateInvalid), buffer_size(131072) { @@ -211,7 +211,7 @@ void Debug::start(const std::string &command, const boost::filesystem::path &pat } } event_mutex.unlock(); - this_thread::sleep_for(std::chrono::milliseconds(200)); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); } }); } @@ -319,7 +319,7 @@ std::vector Debug::get_backtrace() { } std::vector Debug::get_variables() { - vector variables; + std::vector variables; event_mutex.lock(); if(state==lldb::StateType::eStateStopped) { for(uint32_t c_t=0;c_tGetNumThreads();c_t++) { @@ -335,6 +335,7 @@ std::vector Debug::get_variables() { if(declaration.IsValid()) { Debug::Variable variable; + variable.thread_index_id=thread.GetIndexID(); variable.frame_index=c_f; variable.name=value.GetName(); @@ -375,7 +376,7 @@ void Debug::delete_debug() { debug_thread.join(); } -std::string Debug::get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr) { +std::string Debug::get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index) { std::string variable_value; event_mutex.lock(); if(state==lldb::StateType::eStateStopped) { @@ -390,7 +391,7 @@ std::string Debug::get_value(const std::string &variable, const boost::filesyste if(value.GetName()==variable) { auto declaration=value.GetDeclaration(); if(declaration.IsValid()) { - if(declaration.GetLine()==line_nr) { + if(declaration.GetLine()==line_nr && (declaration.GetColumn()==0 || declaration.GetColumn()==line_index)) { auto file_spec=declaration.GetFileSpec(); boost::filesystem::path value_decl_path=file_spec.GetDirectory(); value_decl_path/=file_spec.GetFilename(); diff --git a/src/debug.h b/src/debug.h index 91e4343..9900f9a 100644 --- a/src/debug.h +++ b/src/debug.h @@ -22,6 +22,7 @@ public: }; class Variable { public: + uint32_t thread_index_id; uint32_t frame_index; std::string name; std::string value; @@ -55,7 +56,7 @@ public: void delete_debug(); //can't use delete as function name - std::string get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr); + std::string get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index); std::string get_return_value(const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index); bool is_invalid(); diff --git a/src/source_clang.cc b/src/source_clang.cc index a36a318..67a5128 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -420,7 +420,7 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) if(Debug::get().is_stopped()) { auto location=token.get_cursor().get_referenced().get_source_location(); Glib::ustring value_type="Value"; - Glib::ustring debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line); + Glib::ustring debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line, location.get_offset().index); if(debug_value.empty()) { value_type="Return value"; auto location=token.get_cursor().get_source_location(); diff --git a/src/window.cc b/src/window.cc index 15c5d40..531cc3e 100644 --- a/src/window.cc +++ b/src/window.cc @@ -979,7 +979,7 @@ void Window::set_menu_actions() { return; for(auto &variable: variables) { - std::string row=variable.file_path.filename().string()+":"+std::to_string(variable.line_nr)+" - "+Glib::Markup::escape_text(variable.name)+""; + 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); From 18748aed2414ca664f137121e88302f0ee3aaf7e Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 12 Jan 2016 20:49:09 +0100 Subject: [PATCH 77/90] CMake build paths cleanup --- src/cmake.cc | 14 +++++++------- src/source_clang.cc | 6 +----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index 7d7c2a5..61bf185 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -36,6 +36,9 @@ CMake::CMake(const boost::filesystem::path &path) { } boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::path &project_path) { + if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) + return boost::filesystem::path(); + boost::filesystem::path default_build_path=Config::get().terminal.default_build_path; const std::string path_variable_project_directory_name=""; @@ -65,6 +68,9 @@ boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::p } boost::filesystem::path CMake::get_debug_build_path(const boost::filesystem::path &project_path) { + if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) + return boost::filesystem::path(); + boost::filesystem::path debug_build_path=Config::get().terminal.debug_build_path; const std::string path_variable_project_directory_name=""; @@ -109,9 +115,6 @@ bool CMake::create_default_build(const boost::filesystem::path &project_path, bo if(project_path.empty()) return false; - if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) - return false; - auto default_build_path=get_default_build_path(project_path); if(default_build_path.empty()) return false; @@ -149,10 +152,7 @@ bool CMake::create_default_build(const boost::filesystem::path &project_path, bo bool CMake::create_debug_build(const boost::filesystem::path &project_path) { if(project_path.empty()) return false; - - if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) - return false; - + auto debug_build_path=get_debug_build_path(project_path); if(debug_build_path.empty()) return false; diff --git a/src/source_clang.cc b/src/source_clang.cc index d041b29..67a5128 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -182,11 +182,7 @@ void Source::ClangViewParse::soft_reparse() { } std::vector Source::ClangViewParse::get_compilation_commands() { - boost::filesystem::path default_build_path; - if(boost::filesystem::exists(project_path/"CMakeLists.txt")) - default_build_path=CMake::get_default_build_path(project_path); - - clang::CompilationDatabase db(default_build_path.string()); + clang::CompilationDatabase db(CMake::get_default_build_path(project_path).string()); clang::CompileCommands commands(file_path.string(), db); std::vector cmds = commands.get_commands(); std::vector arguments; From 541fa039f5115e6110ab5406c87a4dfdb3d7dc21 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 12 Jan 2016 22:21:01 +0100 Subject: [PATCH 78/90] Cleanup of builds --- src/cmake.cc | 49 +++++++++++++++++++++++-------------------------- src/notebook.cc | 3 +++ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index 61bf185..f5d1260 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -36,9 +36,6 @@ CMake::CMake(const boost::filesystem::path &path) { } boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::path &project_path) { - if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) - return boost::filesystem::path(); - boost::filesystem::path default_build_path=Config::get().terminal.default_build_path; const std::string path_variable_project_directory_name=""; @@ -54,23 +51,11 @@ boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::p if(default_build_path.is_relative()) default_build_path=project_path/default_build_path; - - if(!boost::filesystem::exists(default_build_path)) { - boost::system::error_code ec; - boost::filesystem::create_directories(default_build_path, ec); - if(ec) { - Terminal::get().print("Error: could not create "+default_build_path.string()+": "+ec.message()+"\n", true); - return boost::filesystem::path(); - } - } return default_build_path; } boost::filesystem::path CMake::get_debug_build_path(const boost::filesystem::path &project_path) { - if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) - return boost::filesystem::path(); - boost::filesystem::path debug_build_path=Config::get().terminal.debug_build_path; const std::string path_variable_project_directory_name=""; @@ -95,18 +80,8 @@ boost::filesystem::path CMake::get_debug_build_path(const boost::filesystem::pat if(pos!=0) debug_build_path=debug_build_path_string; - if(debug_build_path.is_relative()) debug_build_path=project_path/debug_build_path; - - if(!boost::filesystem::exists(debug_build_path)) { - boost::system::error_code ec; - boost::filesystem::create_directories(debug_build_path, ec); - if(ec) { - Terminal::get().print("Error: could not create "+debug_build_path.string()+": "+ec.message()+"\n", true); - return boost::filesystem::path(); - } - } return debug_build_path; } @@ -115,9 +90,20 @@ bool CMake::create_default_build(const boost::filesystem::path &project_path, bo if(project_path.empty()) return false; + if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) + return false; + auto default_build_path=get_default_build_path(project_path); if(default_build_path.empty()) return false; + if(!boost::filesystem::exists(default_build_path)) { + boost::system::error_code ec; + boost::filesystem::create_directories(default_build_path, ec); + if(ec) { + Terminal::get().print("Error: could not create "+default_build_path.string()+": "+ec.message()+"\n", true); + return false; + } + } if(!force && boost::filesystem::exists(default_build_path/"compile_commands.json")) return true; @@ -152,10 +138,21 @@ bool CMake::create_default_build(const boost::filesystem::path &project_path, bo bool CMake::create_debug_build(const boost::filesystem::path &project_path) { if(project_path.empty()) return false; - + + if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) + return false; + auto debug_build_path=get_debug_build_path(project_path); if(debug_build_path.empty()) return false; + if(!boost::filesystem::exists(debug_build_path)) { + boost::system::error_code ec; + boost::filesystem::create_directories(debug_build_path, ec); + if(ec) { + Terminal::get().print("Error: could not create "+debug_build_path.string()+": "+ec.message()+"\n", true); + return false; + } + } if(boost::filesystem::exists(debug_build_path/"CMakeCache.txt")) { auto it=debug_build_needed.find(project_path.string()); diff --git a/src/notebook.cc b/src/notebook.cc index eec39b3..a0aa6f3 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -257,6 +257,9 @@ bool Notebook::save(int page) { project_path=cmake.project_path; } if(project_path!="") { + auto debug_project_path=CMake::get_debug_build_path(project_path); + if(!debug_project_path.empty() && boost::filesystem::exists(debug_project_path)) + CMake::create_debug_build(project_path); for(auto source_view: source_views) { if(auto source_clang_view=dynamic_cast(source_view)) { if(project_path==source_clang_view->project_path) From 7f123fe8f861097a2ba16646105200e65a8e6e59 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 13 Jan 2016 11:36:41 +0100 Subject: [PATCH 79/90] Fix to Debug get return value --- src/source_clang.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/source_clang.cc b/src/source_clang.cc index 67a5128..785248e 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -423,8 +423,9 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) Glib::ustring debug_value=Debug::get().get_value(token.get_spelling(), location.get_path(), location.get_offset().line, location.get_offset().index); if(debug_value.empty()) { value_type="Return value"; - auto location=token.get_cursor().get_source_location(); - debug_value=Debug::get().get_return_value(location.get_path(), location.get_offset().line, location.get_offset().index); + auto cursor=token.get_cursor(); + auto offsets=cursor.get_source_range().get_offsets(); + debug_value=Debug::get().get_return_value(cursor.get_source_location().get_path(), offsets.first.line, offsets.first.index); } if(!debug_value.empty()) { size_t pos=debug_value.find(" = "); From bd3c30fabae6431bb6187c6c9e9d94f04a345f63 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 13 Jan 2016 11:55:23 +0100 Subject: [PATCH 80/90] Get iter for dialog positioning cleanup --- src/source.cc | 15 +++++++++++++++ src/source.h | 1 + src/source_clang.cc | 12 +----------- src/window.cc | 42 +++++------------------------------------- 4 files changed, 22 insertions(+), 48 deletions(-) diff --git a/src/source.cc b/src/source.cc index 4706a6c..05381cd 100644 --- a/src/source.cc +++ b/src/source.cc @@ -682,6 +682,21 @@ void Source::View::paste() { } } +Gtk::TextIter Source::View::get_iter_for_dialog() { + auto iter=get_buffer()->get_insert()->get_iter(); + if(iter.get_line_offset()>=80) + iter=get_buffer()->get_iter_at_line(iter.get_line()); + Gdk::Rectangle visible_rect; + get_visible_rect(visible_rect); + Gdk::Rectangle iter_rect; + get_iter_location(iter, iter_rect); + iter_rect.set_width(1); + if(!visible_rect.intersects(iter_rect)) { + get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3); + } + return iter; +} + void Source::View::set_status(const std::string &status) { this->status=status; if(on_update_status) diff --git a/src/source.h b/src/source.h index 35d6c98..b060e8b 100644 --- a/src/source.h +++ b/src/source.h @@ -87,6 +87,7 @@ namespace Source { std::unique_ptr autocomplete_dialog; std::unique_ptr selection_dialog; + Gtk::TextIter get_iter_for_dialog(); sigc::connection delayed_tooltips_connection; std::function on_update_status; diff --git a/src/source_clang.cc b/src/source_clang.cc index 785248e..e698e38 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -1209,17 +1209,7 @@ Source::ClangViewAutocomplete(file_path, project_path, language) { goto_method=[this](){ if(parsed) { - auto iter=get_buffer()->get_insert()->get_iter(); - if(iter.get_line_offset()>=80) - iter=get_buffer()->get_iter_at_line(iter.get_line()); - Gdk::Rectangle visible_rect; - get_visible_rect(visible_rect); - Gdk::Rectangle iter_rect; - get_iter_location(iter, iter_rect); - iter_rect.set_width(1); - if(!visible_rect.intersects(iter_rect)) { - get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3); - } + auto iter=get_iter_for_dialog(); selection_dialog=std::unique_ptr(new SelectionDialog(*this, get_buffer()->create_mark(iter), true, true)); auto rows=std::make_shared >(); auto methods=clang_tokens->get_cxx_methods(); diff --git a/src/window.cc b/src/window.cc index 531cc3e..ba97259 100644 --- a/src/window.cc +++ b/src/window.cc @@ -516,17 +516,7 @@ void Window::set_menu_actions() { if(current_view->get_token && current_view->get_usages) { auto token=current_view->get_token(); if(token) { - auto iter=current_view->get_buffer()->get_insert()->get_iter(); - if(iter.get_line_offset()>=80) - iter=current_view->get_buffer()->get_iter_at_line(iter.get_line()); - Gdk::Rectangle visible_rect; - current_view->get_visible_rect(visible_rect); - Gdk::Rectangle iter_rect; - current_view->get_iter_location(iter, iter_rect); - iter_rect.set_width(1); - if(!visible_rect.intersects(iter_rect)) { - current_view->get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3); - } + auto iter=current_view->get_iter_for_dialog(); current_view->selection_dialog=std::unique_ptr(new SelectionDialog(*current_view, current_view->get_buffer()->create_mark(iter), true, true)); auto rows=std::make_shared >(); @@ -901,19 +891,8 @@ void Window::set_menu_actions() { auto backtrace=Debug::get().get_backtrace(); auto view=notebook.get_current_view(); - auto buffer=view->get_buffer(); - auto iter=buffer->get_insert()->get_iter(); - if(iter.get_line_offset()>=80) - iter=buffer->get_iter_at_line(iter.get_line()); - Gdk::Rectangle visible_rect; - view->get_visible_rect(visible_rect); - Gdk::Rectangle iter_rect; - view->get_iter_location(iter, iter_rect); - iter_rect.set_width(1); - if(!visible_rect.intersects(iter_rect)) { - view->get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3); - } - view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, buffer->create_mark(iter), true, true)); + 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; @@ -961,19 +940,8 @@ void Window::set_menu_actions() { auto variables=Debug::get().get_variables(); auto view=notebook.get_current_view(); - auto buffer=view->get_buffer(); - auto iter=buffer->get_insert()->get_iter(); - if(iter.get_line_offset()>=80) - iter=buffer->get_iter_at_line(iter.get_line()); - Gdk::Rectangle visible_rect; - view->get_visible_rect(visible_rect); - Gdk::Rectangle iter_rect; - view->get_iter_location(iter, iter_rect); - iter_rect.set_width(1); - if(!visible_rect.intersects(iter_rect)) { - view->get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3); - } - view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, buffer->create_mark(iter), true, true)); + 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; From a50adf87eeb9c1f8a39f495aa2a5275fca75f33b Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 13 Jan 2016 12:33:43 +0100 Subject: [PATCH 81/90] Cleanup of dialog tooltips --- src/selectiondialog.cc | 103 +++++++---------------------------------- src/selectiondialog.h | 14 ++---- src/source_clang.cc | 39 ++++++++++++++-- src/source_clang.h | 3 +- src/window.cc | 3 +- 5 files changed, 61 insertions(+), 101 deletions(-) diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index 1cb27e2..ff0f143 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -68,6 +68,20 @@ list_view_text(use_markup), start_mark(start_mark), show_search_entry(show_searc dialog->get_vbox()->pack_start(scrolled_window, true, true); dialog->set_transient_for((Gtk::Window&)(*text_view.get_toplevel())); } + + list_view_text.signal_cursor_changed().connect([this]() { + if(!shown) + return; + auto it=list_view_text.get_selection()->get_selected(); + std::string row; + if(it) + it->get_value(0, row); + if(last_row==row) + return; + if(on_changed) + on_changed(row); + last_row=row; + }); } SelectionDialogBase::~SelectionDialogBase() { @@ -129,21 +143,7 @@ void SelectionDialogBase::resize() { } } -SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup) : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) { - list_view_text.signal_cursor_changed().connect([this]() { - if(!shown) - return; - auto it=list_view_text.get_selection()->get_selected(); - std::string row; - if(it) - it->get_value(0, row); - if(last_row==row) - return; - if(on_changed) - on_changed(row); - last_row=row; - }); -} +SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup) : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) {} void SelectionDialog::show() { SelectionDialogBase::show(); @@ -282,26 +282,7 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { return false; } -CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark) : SelectionDialogBase(text_view, start_mark, false, false) { - list_view_text.signal_event_after().connect([this](GdkEvent* event){ - if(event->type==GDK_KEY_PRESS || event->type==GDK_BUTTON_PRESS) { - update_tooltips(); - } - }); - if(show_search_entry) { - search_entry.signal_event_after().connect([this](GdkEvent* event){ - if(event->type==GDK_KEY_PRESS || event->type==GDK_BUTTON_PRESS) { - update_tooltips(); - } - }); - } -} - -void CompletionDialog::add_row(const std::string& row, const std::string& tooltip) { - SelectionDialogBase::add_row(row); - if(tooltip.size()>0) - tooltip_texts[row]=tooltip; -} +CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark) : SelectionDialogBase(text_view, start_mark, false, false) {} void CompletionDialog::show() { SelectionDialogBase::show(); @@ -348,18 +329,8 @@ void CompletionDialog::show() { list_view_text.set_search_entry(search_entry); } - if(list_view_text.get_model()->children().size()>0) { + if(list_view_text.get_model()->children().size()>0) list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); - update_tooltips(); - } -} - -void CompletionDialog::hide() { - if(!shown) - return; - SelectionDialogBase::hide(); - if(tooltips) - tooltips->hide(); } void CompletionDialog::select(bool hide_window) { @@ -394,7 +365,6 @@ bool CompletionDialog::on_key_release(GdkEventKey* key) { list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); } } - update_tooltips(); } return false; } @@ -407,12 +377,9 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) { if(row_in_entry) { text_view.get_buffer()->erase(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); row_in_entry=false; - if(key->keyval==GDK_KEY_BackSpace) { - update_tooltips(); + if(key->keyval==GDK_KEY_BackSpace) return true; - } } - update_tooltips(); return false; } if(key->keyval==GDK_KEY_Shift_L || key->keyval==GDK_KEY_Shift_R || key->keyval==GDK_KEY_Alt_L || key->keyval==GDK_KEY_Alt_R || key->keyval==GDK_KEY_Control_L || key->keyval==GDK_KEY_Control_R || key->keyval==GDK_KEY_Meta_L || key->keyval==GDK_KEY_Meta_R) @@ -428,7 +395,6 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) { else list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); select(false); - update_tooltips(); return true; } if(key->keyval==GDK_KEY_Up && list_view_text.get_model()->children().size()>0) { @@ -446,7 +412,6 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) { list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); } select(false); - update_tooltips(); return true; } if(key->keyval==GDK_KEY_Return || key->keyval==GDK_KEY_ISO_Left_Tab || key->keyval==GDK_KEY_Tab) { @@ -458,35 +423,3 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) { return true; return false; } - -void CompletionDialog::update_tooltips() { - auto it=list_view_text.get_selection()->get_selected(); - if(it) { - std::string row; - it->get_value(0, row); - if(row!=last_row || last_row.size()==0) { - if(tooltips) - tooltips->hide(); - auto it=tooltip_texts.find(row); - if(it!=tooltip_texts.end()) { - auto tooltip_text=it->second; - if(tooltip_text.size()>0) { - tooltips=std::unique_ptr(new Tooltips()); - auto get_tooltip_buffer=[this, tooltip_text]() { - auto tooltip_buffer=Gtk::TextBuffer::create(text_view.get_buffer()->get_tag_table()); - tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), tooltip_text, "def:note"); - return tooltip_buffer; - }; - tooltips->emplace_back(get_tooltip_buffer, text_view, text_view.get_buffer()->create_mark(start_mark->get_iter()), text_view.get_buffer()->create_mark(text_view.get_buffer()->get_insert()->get_iter())); - tooltips->show(true); - } - } - } - last_row=row; - } - else { - last_row=""; - if(tooltips) - tooltips->hide(); - } -} diff --git a/src/selectiondialog.h b/src/selectiondialog.h index 0c9b1e5..b95d3c6 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -36,6 +36,7 @@ public: std::function on_hide; std::function on_select; + std::function on_changed; Glib::RefPtr start_mark; bool shown=false; @@ -48,6 +49,8 @@ protected: ListViewText list_view_text; Gtk::Entry search_entry; bool show_search_entry; + + std::string last_row; }; class SelectionDialog : public SelectionDialogBase { @@ -55,18 +58,12 @@ public: SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry=true, bool use_markup=false); bool on_key_press(GdkEventKey* key); void show(); - - std::function on_changed; -private: - std::string last_row; }; class CompletionDialog : public SelectionDialogBase { public: CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark); - void add_row(const std::string& row, const std::string& tooltip); void show(); - void hide(); bool on_key_release(GdkEventKey* key); bool on_key_press(GdkEventKey* key); @@ -75,11 +72,6 @@ private: int show_offset; bool row_in_entry=false; - - void update_tooltips(); - std::unique_ptr tooltips; - std::unordered_map tooltip_texts; - std::string last_row; }; #endif // JUCI_SELECTIONDIALOG_H_ \ No newline at end of file diff --git a/src/source_clang.cc b/src/source_clang.cc index e698e38..77a9c15 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -744,10 +744,11 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_state(Au if (!row.empty()) { if(!return_value.empty()) row+=" --> " + return_value; - autocomplete_dialog_rows[row] = row_insert_on_selection; - autocomplete_dialog->add_row(row, data.brief_comments); + autocomplete_dialog_rows[row] = std::pair(std::move(row_insert_on_selection), std::move(data.brief_comments)); + autocomplete_dialog->add_row(row); } } + autocomplete_data.clear(); set_status(""); autocomplete_state=AutocompleteState::IDLE; if (!autocomplete_dialog_rows.empty()) { @@ -797,11 +798,15 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() { autocomplete_dialog_rows.clear(); autocomplete_dialog->on_hide=[this](){ get_source_buffer()->end_user_action(); + if(autocomplete_tooltips) { + autocomplete_tooltips->hide(); + autocomplete_tooltips.reset(); + } parsed=false; soft_reparse(); }; autocomplete_dialog->on_select=[this](const std::string& selected, bool hide_window) { - auto row = autocomplete_dialog_rows.at(selected); + auto row = autocomplete_dialog_rows.at(selected).first; get_buffer()->erase(autocomplete_dialog->start_mark->get_iter(), get_buffer()->get_insert()->get_iter()); auto iter=get_buffer()->get_insert()->get_iter(); if(*iter=='<' || *iter=='(') { @@ -850,6 +855,34 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() { } } }; + + autocomplete_dialog->on_changed=[this](const std::string &selected) { + if(selected.empty()) { + if(autocomplete_tooltips) + autocomplete_tooltips->hide(); + return; + } + auto tooltip=std::make_shared(autocomplete_dialog_rows.at(selected).second); + if(tooltip->empty()) { + if(autocomplete_tooltips) + autocomplete_tooltips->hide(); + } + else { + autocomplete_tooltips=std::unique_ptr(new Tooltips()); + auto create_tooltip_buffer=[this, tooltip]() { + auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); + + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), *tooltip, "def:note"); + + return tooltip_buffer; + }; + + auto iter=autocomplete_dialog->start_mark->get_iter(); + autocomplete_tooltips->emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(iter), get_buffer()->create_mark(iter)); + + autocomplete_tooltips->show(true); + } + }; } void Source::ClangViewAutocomplete::autocomplete_check() { diff --git a/src/source_clang.h b/src/source_clang.h index f4d26d6..12e4ee4 100644 --- a/src/source_clang.h +++ b/src/source_clang.h @@ -101,8 +101,9 @@ namespace Source { void autocomplete_check(); void autocomplete(); std::vector autocomplete_data; - std::unordered_map autocomplete_dialog_rows; + std::unordered_map > autocomplete_dialog_rows; std::vector autocomplete_get_suggestions(const std::string &buffer, int line_number, int column); + std::unique_ptr autocomplete_tooltips; Glib::Dispatcher autocomplete_done; Glib::Dispatcher autocomplete_restart; Glib::Dispatcher autocomplete_error; diff --git a/src/window.cc b/src/window.cc index ba97259..2fd7f73 100644 --- a/src/window.cc +++ b/src/window.cc @@ -981,7 +981,8 @@ void Window::set_menu_actions() { view->selection_dialog->on_changed=[this, rows, iter](const std::string &selected) { if(selected.empty()) { - debug_variable_tooltips->hide(); + if(debug_variable_tooltips) + debug_variable_tooltips->hide(); return; } if(notebook.get_current_page()!=-1) { From 98a4f9c2511249f417c1407dc4b581eaed98b27d Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 13 Jan 2016 12:52:17 +0100 Subject: [PATCH 82/90] Slight memory optimization of autocompletion --- src/source_clang.cc | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/source_clang.cc b/src/source_clang.cc index 77a9c15..354d8e1 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -728,20 +728,17 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_state(Au autocomplete_dialog_setup(); for (auto &data : autocomplete_data) { - std::stringstream ss; + std::string row; std::string return_value; for (auto &chunk : data.chunks) { - switch (chunk.kind) { - case clang::CompletionChunk_ResultType: - return_value = chunk.chunk; - break; - case clang::CompletionChunk_Informative: break; - default: ss << chunk.chunk; break; - } + if(chunk.kind==clang::CompletionChunk_ResultType) + return_value=chunk.chunk; + else if(chunk.kind!=clang::CompletionChunk_Informative) + row+=chunk.chunk; } - auto row=ss.str(); - auto row_insert_on_selection=row; + data.chunks.clear(); if (!row.empty()) { + auto row_insert_on_selection=row; if(!return_value.empty()) row+=" --> " + return_value; autocomplete_dialog_rows[row] = std::pair(std::move(row_insert_on_selection), std::move(data.brief_comments)); From dafec140baaf5b880f868b09716bb91b8f793bcd Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Wed, 13 Jan 2016 15:55:50 +0100 Subject: [PATCH 83/90] Removed tooltips.h from selectiondialog.h --- src/selectiondialog.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/selectiondialog.h b/src/selectiondialog.h index b95d3c6..07a7dd9 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -3,7 +3,6 @@ #include "gtkmm.h" #include "logging.h" -#include "tooltips.h" #include class ListViewText : public Gtk::TreeView { From 6068cc7774dc08b209570b3b904e33953895be3e Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 13 Jan 2016 17:27:39 +0100 Subject: [PATCH 84/90] Now also selects thread when going to a variable --- src/debug.cc | 7 ++++--- src/debug.h | 2 +- src/window.cc | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/debug.cc b/src/debug.cc index 954bf27..2e72c52 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -361,11 +361,12 @@ std::vector Debug::get_variables() { return variables; } -void Debug::select_frame(uint32_t index) { +void Debug::select_frame(uint32_t frame_index, uint32_t thread_index_id) { event_mutex.lock(); if(state==lldb::StateType::eStateStopped) { - auto thread=process->GetSelectedThread(); - thread.SetSelectedFrame(index); + if(thread_index_id!=0) + process->SetSelectedThreadByIndexID(thread_index_id); + process->GetSelectedThread().SetSelectedFrame(frame_index);; } event_mutex.unlock(); } diff --git a/src/debug.h b/src/debug.h index 9900f9a..07fd4d2 100644 --- a/src/debug.h +++ b/src/debug.h @@ -52,7 +52,7 @@ public: std::pair run_command(const std::string &command); std::vector get_backtrace(); std::vector get_variables(); - void select_frame(uint32_t index); + void select_frame(uint32_t frame_index, uint32_t thread_index_id=0); void delete_debug(); //can't use delete as function name diff --git a/src/window.cc b/src/window.cc index 2fd7f73..a167113 100644 --- a/src/window.cc +++ b/src/window.cc @@ -960,7 +960,7 @@ void Window::set_menu_actions() { if(notebook.get_current_page()!=-1) { auto view=notebook.get_current_view(); - Debug::get().select_frame(variable.frame_index); + 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)); From 800a51b79f2f67f5cc2f0ebb7c62e55a3aa4b1a8 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 13 Jan 2016 18:11:56 +0100 Subject: [PATCH 85/90] Workaround for a gtk bug that removes cursor from a tree view when the search entry becomes empty --- src/selectiondialog.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index ff0f143..3b19342 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -179,6 +179,10 @@ void SelectionDialog::show() { *search_key=search_entry.get_text(); filter_model->refilter(); list_view_text.set_search_entry(search_entry); //TODO:Report the need of this to GTK's git (bug) + if(search_key->empty()) { + if(list_view_text.get_model()->children().size()>0) + list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); + } }); search_entry.signal_event().connect([this](GdkEvent* event) { From 97da5bd74b23d770b5bc45c0e12b3704ba2d3037 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 14 Jan 2016 11:47:38 +0100 Subject: [PATCH 86/90] Minor cleanup --- src/window.cc | 15 ++++++--------- src/window.h | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/window.cc b/src/window.cc index a167113..2c55f69 100644 --- a/src/window.cc +++ b/src/window.cc @@ -973,21 +973,18 @@ void Window::set_menu_actions() { }; view->selection_dialog->on_hide=[this]() { - if(debug_variable_tooltips) { - debug_variable_tooltips->hide(); - debug_variable_tooltips.reset(); - } + debug_variable_tooltips.hide(); + debug_variable_tooltips.clear(); }; view->selection_dialog->on_changed=[this, rows, iter](const std::string &selected) { if(selected.empty()) { - if(debug_variable_tooltips) - debug_variable_tooltips->hide(); + debug_variable_tooltips.hide(); return; } if(notebook.get_current_page()!=-1) { auto view=notebook.get_current_view(); - debug_variable_tooltips=std::unique_ptr(new Tooltips()); + 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()); @@ -1006,9 +1003,9 @@ void Window::set_menu_actions() { 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.emplace_back(create_tooltip_buffer, *view, view->get_buffer()->create_mark(iter), view->get_buffer()->create_mark(iter)); - debug_variable_tooltips->show(true); + debug_variable_tooltips.show(true); } }; diff --git a/src/window.h b/src/window.h index 6c55d87..a3485a2 100644 --- a/src/window.h +++ b/src/window.h @@ -48,7 +48,7 @@ private: std::mutex debug_status_mutex; Glib::Dispatcher debug_update_status; - std::unique_ptr debug_variable_tooltips; + Tooltips debug_variable_tooltips; std::unique_ptr get_cmake(); std::unordered_map project_run_arguments; From 2b4c8d0dc6cbd7116a108be2e892adde6eb24424 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 14 Jan 2016 12:11:41 +0100 Subject: [PATCH 87/90] Minor change --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d1edf64..afc7120 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ towards libclang with speed and ease of use in mind. ## Features * Platform independent -* Debug integration through lldb * Fast and responsive (written in C++) * Syntax highlighting for more than 100 different file types * C++ warnings and errors on the fly * C++ Fix-its +* Debug integration through lldb * Automated CMake processing * Fast C++ autocompletion * Keyword and buffer autocompletion for other file types From 6f47300607bd32a361971ab06c5d74965072ee47 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 15 Jan 2016 14:51:10 +0100 Subject: [PATCH 88/90] Tooltip and completiondialog cleanup --- .gitignore | 2 ++ src/selectiondialog.cc | 22 ++++++---------------- src/selectiondialog.h | 2 -- src/source_clang.cc | 18 +++++++----------- src/source_clang.h | 2 +- 5 files changed, 16 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index c30b100..ad5aad3 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ !CMakeLists.txt !config.json !*.py + +build \ No newline at end of file diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index 3b19342..b9d5e3b 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -96,6 +96,9 @@ void SelectionDialogBase::show() { shown=true; move(); window->show_all(); + + if(list_view_text.get_model()->children().size()>0) + list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); } void SelectionDialogBase::hide() { @@ -143,10 +146,7 @@ void SelectionDialogBase::resize() { } } -SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup) : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) {} - -void SelectionDialog::show() { - SelectionDialogBase::show(); +SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup) : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) { std::shared_ptr search_key(new std::string()); auto filter_model=Gtk::TreeModelFilter::create(list_view_text.get_model()); @@ -240,9 +240,6 @@ void SelectionDialog::show() { hide(); return true; }); - - if(list_view_text.get_model()->children().size()>0) - list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); } bool SelectionDialog::on_key_press(GdkEventKey* key) { @@ -286,13 +283,9 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { return false; } -CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark) : SelectionDialogBase(text_view, start_mark, false, false) {} - -void CompletionDialog::show() { - SelectionDialogBase::show(); - +CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark) : SelectionDialogBase(text_view, start_mark, false, false) { show_offset=text_view.get_buffer()->get_insert()->get_iter().get_offset(); - + std::shared_ptr search_key(new std::string()); auto filter_model=Gtk::TreeModelFilter::create(list_view_text.get_model()); if(show_offset==start_mark->get_iter().get_offset()) { @@ -332,9 +325,6 @@ void CompletionDialog::show() { search_entry.set_text(text); list_view_text.set_search_entry(search_entry); } - - if(list_view_text.get_model()->children().size()>0) - list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); } void CompletionDialog::select(bool hide_window) { diff --git a/src/selectiondialog.h b/src/selectiondialog.h index 07a7dd9..1b8c6cf 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -56,13 +56,11 @@ class SelectionDialog : public SelectionDialogBase { public: SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry=true, bool use_markup=false); bool on_key_press(GdkEventKey* key); - void show(); }; class CompletionDialog : public SelectionDialogBase { public: CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark); - void show(); bool on_key_release(GdkEventKey* key); bool on_key_press(GdkEventKey* key); diff --git a/src/source_clang.cc b/src/source_clang.cc index 354d8e1..b5a4bb8 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -795,10 +795,8 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() { autocomplete_dialog_rows.clear(); autocomplete_dialog->on_hide=[this](){ get_source_buffer()->end_user_action(); - if(autocomplete_tooltips) { - autocomplete_tooltips->hide(); - autocomplete_tooltips.reset(); - } + autocomplete_tooltips.hide(); + autocomplete_tooltips.clear(); parsed=false; soft_reparse(); }; @@ -855,17 +853,15 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() { autocomplete_dialog->on_changed=[this](const std::string &selected) { if(selected.empty()) { - if(autocomplete_tooltips) - autocomplete_tooltips->hide(); + autocomplete_tooltips.hide(); return; } auto tooltip=std::make_shared(autocomplete_dialog_rows.at(selected).second); if(tooltip->empty()) { - if(autocomplete_tooltips) - autocomplete_tooltips->hide(); + autocomplete_tooltips.hide(); } else { - autocomplete_tooltips=std::unique_ptr(new Tooltips()); + autocomplete_tooltips.clear(); auto create_tooltip_buffer=[this, tooltip]() { auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); @@ -875,9 +871,9 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() { }; auto iter=autocomplete_dialog->start_mark->get_iter(); - autocomplete_tooltips->emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(iter), get_buffer()->create_mark(iter)); + autocomplete_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(iter), get_buffer()->create_mark(iter)); - autocomplete_tooltips->show(true); + autocomplete_tooltips.show(true); } }; } diff --git a/src/source_clang.h b/src/source_clang.h index 12e4ee4..93b226d 100644 --- a/src/source_clang.h +++ b/src/source_clang.h @@ -103,7 +103,7 @@ namespace Source { std::vector autocomplete_data; std::unordered_map > autocomplete_dialog_rows; std::vector autocomplete_get_suggestions(const std::string &buffer, int line_number, int column); - std::unique_ptr autocomplete_tooltips; + Tooltips autocomplete_tooltips; Glib::Dispatcher autocomplete_done; Glib::Dispatcher autocomplete_restart; Glib::Dispatcher autocomplete_error; From 7380ecf54458471a6e38541f3787bff682c9e284 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 15 Jan 2016 15:09:11 +0100 Subject: [PATCH 89/90] Fixed a bug where tooltips got shown when no row were found --- src/selectiondialog.cc | 67 +++++++++++++++++++++++++++--------------- src/selectiondialog.h | 2 ++ 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index b9d5e3b..8acafd1 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -68,20 +68,20 @@ list_view_text(use_markup), start_mark(start_mark), show_search_entry(show_searc dialog->get_vbox()->pack_start(scrolled_window, true, true); dialog->set_transient_for((Gtk::Window&)(*text_view.get_toplevel())); } - - list_view_text.signal_cursor_changed().connect([this]() { - if(!shown) - return; - auto it=list_view_text.get_selection()->get_selected(); - std::string row; - if(it) - it->get_value(0, row); - if(last_row==row) - return; - if(on_changed) - on_changed(row); - last_row=row; - }); +} + +void SelectionDialogBase::cursor_changed() { + if(!shown) + return; + auto it=list_view_text.get_selection()->get_selected(); + std::string row; + if(it) + it->get_value(0, row); + if(last_row==row) + return; + if(on_changed) + on_changed(row); + last_row=row; } SelectionDialogBase::~SelectionDialogBase() { @@ -97,8 +97,10 @@ void SelectionDialogBase::show() { move(); window->show_all(); - if(list_view_text.get_model()->children().size()>0) + if(list_view_text.get_model()->children().size()>0) { list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); + cursor_changed(); + } } void SelectionDialogBase::hide() { @@ -183,6 +185,7 @@ SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtrchildren().size()>0) list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); } + cursor_changed(); }); search_entry.signal_event().connect([this](GdkEvent* event) { @@ -194,10 +197,13 @@ SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtrget_path(it)); + cursor_changed(); } } - else + else { list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); + cursor_changed(); + } return true; } if(key->keyval==GDK_KEY_Up && list_view_text.get_model()->children().size()>0) { @@ -206,13 +212,16 @@ SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtrget_path(it)); + cursor_changed(); } } else { auto last_it=list_view_text.get_model()->children().end(); last_it--; - if(last_it) + if(last_it) { list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); + cursor_changed(); + } } return true; } @@ -249,10 +258,13 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { it++; if(it) { list_view_text.set_cursor(list_view_text.get_model()->get_path(it)); + cursor_changed(); } } - else + else { list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); + cursor_changed(); + } return true; } if(key->keyval==GDK_KEY_Up && list_view_text.get_model()->children().size()>0) { @@ -261,13 +273,16 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { it--; if(it) { list_view_text.set_cursor(list_view_text.get_model()->get_path(it)); + cursor_changed(); } } else { auto last_it=list_view_text.get_model()->children().end(); last_it--; - if(last_it) + if(last_it) { list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); + cursor_changed(); + } } return true; } @@ -355,10 +370,10 @@ bool CompletionDialog::on_key_release(GdkEventKey* key) { search_entry.set_text(text); list_view_text.set_search_entry(search_entry); if(text=="") { - if(list_view_text.get_model()->children().size()>0) { + if(list_view_text.get_model()->children().size()>0) list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); - } } + cursor_changed(); } return false; } @@ -384,10 +399,13 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) { it++; if(it) { list_view_text.set_cursor(list_view_text.get_model()->get_path(it)); + cursor_changed(); } } - else + else { list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); + cursor_changed(); + } select(false); return true; } @@ -397,13 +415,16 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) { it--; if(it) { list_view_text.set_cursor(list_view_text.get_model()->get_path(it)); + cursor_changed(); } } else { auto last_it=list_view_text.get_model()->children().end(); last_it--; - if(last_it) + if(last_it) { list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); + cursor_changed(); + } } select(false); return true; diff --git a/src/selectiondialog.h b/src/selectiondialog.h index 1b8c6cf..732652f 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -40,6 +40,8 @@ public: bool shown=false; protected: + void cursor_changed(); + void resize(); Gtk::TextView& text_view; From fa46c00e22120fe050ff0ad55ce440db73785334 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 15 Jan 2016 17:31:07 +0100 Subject: [PATCH 90/90] Completiondialog cleanup, and now updates tooltip when a row is selected with mouse --- src/selectiondialog.cc | 64 ++++++++++-------------------------------- 1 file changed, 15 insertions(+), 49 deletions(-) diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index 8acafd1..8ef0754 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -59,6 +59,17 @@ list_view_text(use_markup), start_mark(start_mark), show_search_entry(show_searc resize(); }); + list_view_text.signal_event_after().connect([this](GdkEvent* event){ + if(event->type==GDK_KEY_PRESS || event->type==GDK_BUTTON_PRESS) + cursor_changed(); + }); + if(show_search_entry) { + search_entry.signal_event_after().connect([this](GdkEvent* event){ + if(event->type==GDK_KEY_PRESS || event->type==GDK_BUTTON_PRESS) + cursor_changed(); + }); + } + scrolled_window.add(list_view_text); if(!show_search_entry) window->add(scrolled_window); @@ -185,7 +196,6 @@ SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtrchildren().size()>0) list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); } - cursor_changed(); }); search_entry.signal_event().connect([this](GdkEvent* event) { @@ -195,14 +205,8 @@ SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtrget_selected(); if(it) { it++; - if(it) { + if(it) list_view_text.set_cursor(list_view_text.get_model()->get_path(it)); - cursor_changed(); - } - } - else { - list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); - cursor_changed(); } return true; } @@ -210,18 +214,8 @@ SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtrget_selected(); if(it) { it--; - if(it) { + if(it) list_view_text.set_cursor(list_view_text.get_model()->get_path(it)); - cursor_changed(); - } - } - else { - auto last_it=list_view_text.get_model()->children().end(); - last_it--; - if(last_it) { - list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); - cursor_changed(); - } } return true; } @@ -256,14 +250,8 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { auto it=list_view_text.get_selection()->get_selected(); if(it) { it++; - if(it) { + if(it) list_view_text.set_cursor(list_view_text.get_model()->get_path(it)); - cursor_changed(); - } - } - else { - list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); - cursor_changed(); } return true; } @@ -271,18 +259,8 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { auto it=list_view_text.get_selection()->get_selected(); if(it) { it--; - if(it) { + if(it) list_view_text.set_cursor(list_view_text.get_model()->get_path(it)); - cursor_changed(); - } - } - else { - auto last_it=list_view_text.get_model()->children().end(); - last_it--; - if(last_it) { - list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); - cursor_changed(); - } } return true; } @@ -402,10 +380,6 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) { cursor_changed(); } } - else { - list_view_text.set_cursor(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin())); - cursor_changed(); - } select(false); return true; } @@ -418,14 +392,6 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) { cursor_changed(); } } - else { - auto last_it=list_view_text.get_model()->children().end(); - last_it--; - if(last_it) { - list_view_text.set_cursor(list_view_text.get_model()->get_path(last_it)); - cursor_changed(); - } - } select(false); return true; }