mirror of https://gitlab.com/cppit/jucipp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1088 lines
42 KiB
1088 lines
42 KiB
|
6 years ago
|
#include "project.hpp"
|
||
|
|
#include "config.hpp"
|
||
|
|
#include "directories.hpp"
|
||
|
|
#include "filesystem.hpp"
|
||
|
|
#include "menu.hpp"
|
||
|
|
#include "mutex.hpp"
|
||
|
|
#include "notebook.hpp"
|
||
|
|
#include "selection_dialog.hpp"
|
||
|
|
#include "terminal.hpp"
|
||
|
8 years ago
|
#include <fstream>
|
||
|
10 years ago
|
#ifdef JUCI_ENABLE_DEBUG
|
||
|
6 years ago
|
#include "debug_lldb.hpp"
|
||
|
10 years ago
|
#endif
|
||
|
6 years ago
|
#include "ctags.hpp"
|
||
|
|
#include "info.hpp"
|
||
|
|
#include "snippets.hpp"
|
||
|
|
#include "source_clang.hpp"
|
||
|
|
#include "source_language_protocol.hpp"
|
||
|
|
#include "usages_clang.hpp"
|
||
|
8 years ago
|
#include <future>
|
||
|
10 years ago
|
|
||
|
10 years ago
|
boost::filesystem::path Project::debug_last_stop_file_path;
|
||
|
10 years ago
|
std::unordered_map<std::string, std::string> Project::run_arguments;
|
||
|
8 years ago
|
std::unordered_map<std::string, Project::DebugRunArguments> Project::debug_run_arguments;
|
||
|
10 years ago
|
std::atomic<bool> Project::compiling(false);
|
||
|
|
std::atomic<bool> Project::debugging(false);
|
||
|
8 years ago
|
std::pair<boost::filesystem::path, std::pair<int, int>> Project::debug_stop;
|
||
|
9 years ago
|
std::string Project::debug_status;
|
||
|
8 years ago
|
std::shared_ptr<Project::Base> Project::current;
|
||
|
8 years ago
|
std::unique_ptr<Project::DebugOptions> Project::Base::debug_options;
|
||
|
10 years ago
|
|
||
|
6 years ago
|
boost::filesystem::path Project::get_preferably_view_folder() {
|
||
|
|
boost::filesystem::path view_folder;
|
||
|
|
if(auto view = Notebook::get().get_current_view())
|
||
|
|
return view->file_path.parent_path();
|
||
|
|
else if(!Directories::get().path.empty())
|
||
|
|
return Directories::get().path;
|
||
|
|
else {
|
||
|
|
boost::system::error_code ec;
|
||
|
|
auto current_path = boost::filesystem::current_path(ec);
|
||
|
|
if(ec)
|
||
|
|
return boost::filesystem::path();
|
||
|
|
return current_path;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
boost::filesystem::path Project::get_preferably_directory_folder() {
|
||
|
|
if(!Directories::get().path.empty())
|
||
|
|
return Directories::get().path;
|
||
|
|
else if(auto view = Notebook::get().get_current_view())
|
||
|
|
return view->file_path.parent_path();
|
||
|
|
else {
|
||
|
|
boost::system::error_code ec;
|
||
|
|
auto current_path = boost::filesystem::current_path(ec);
|
||
|
|
if(ec)
|
||
|
|
return boost::filesystem::path();
|
||
|
|
return current_path;
|
||
|
|
}
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
10 years ago
|
void Project::save_files(const boost::filesystem::path &path) {
|
||
|
8 years ago
|
for(size_t c = 0; c < Notebook::get().size(); c++) {
|
||
|
|
auto view = Notebook::get().get_view(c);
|
||
|
10 years ago
|
if(view->get_buffer()->get_modified()) {
|
||
|
|
if(filesystem::file_in_path(view->file_path, path))
|
||
|
|
Notebook::get().save(c);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
void Project::on_save(size_t index) {
|
||
|
8 years ago
|
auto view = Notebook::get().get_view(index);
|
||
|
10 years ago
|
if(!view)
|
||
|
10 years ago
|
return;
|
||
|
7 years ago
|
|
||
|
|
if(view->file_path == Config::get().home_juci_path / "snippets.json") {
|
||
|
|
Snippets::get().load();
|
||
|
|
for(auto view : Notebook::get().get_views())
|
||
|
|
view->set_snippets();
|
||
|
|
}
|
||
|
|
|
||
|
9 years ago
|
boost::filesystem::path build_path;
|
||
|
8 years ago
|
if(view->language && view->language->get_id() == "cmake") {
|
||
|
|
if(view->file_path.filename() == "CMakeLists.txt")
|
||
|
|
build_path = view->file_path;
|
||
|
10 years ago
|
else
|
||
|
8 years ago
|
build_path = filesystem::find_file_in_path_parents("CMakeLists.txt", view->file_path.parent_path());
|
||
|
9 years ago
|
}
|
||
|
8 years ago
|
else if(view->language && view->language->get_id() == "meson") {
|
||
|
|
if(view->file_path.filename() == "meson.build")
|
||
|
|
build_path = view->file_path;
|
||
|
9 years ago
|
else
|
||
|
8 years ago
|
build_path = filesystem::find_file_in_path_parents("meson.build", view->file_path.parent_path());
|
||
|
9 years ago
|
}
|
||
|
8 years ago
|
|
||
|
9 years ago
|
if(!build_path.empty()) {
|
||
|
8 years ago
|
auto build = Build::create(build_path);
|
||
|
|
if(dynamic_cast<CMakeBuild *>(build.get()) || dynamic_cast<MesonBuild *>(build.get())) {
|
||
|
9 years ago
|
build->update_default(true);
|
||
|
8 years ago
|
Usages::Clang::erase_all_caches_for_project(build->project_path, build->get_default_path());
|
||
|
|
boost::system::error_code ec;
|
||
|
|
if(boost::filesystem::exists(build->get_debug_path()), ec)
|
||
|
9 years ago
|
build->update_debug(true);
|
||
|
8 years ago
|
|
||
|
|
for(size_t c = 0; c < Notebook::get().size(); c++) {
|
||
|
|
auto source_view = Notebook::get().get_view(c);
|
||
|
|
if(auto source_clang_view = dynamic_cast<Source::ClangView *>(source_view)) {
|
||
|
9 years ago
|
if(filesystem::file_in_path(source_clang_view->file_path, build->project_path))
|
||
|
8 years ago
|
source_clang_view->full_reparse_needed = true;
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
6 years ago
|
Gtk::Label &Project::debug_status_label() {
|
||
|
|
static Gtk::Label label;
|
||
|
|
return label;
|
||
|
|
}
|
||
|
|
|
||
|
9 years ago
|
void Project::debug_update_status(const std::string &new_debug_status) {
|
||
|
8 years ago
|
debug_status = new_debug_status;
|
||
|
10 years ago
|
if(debug_status.empty())
|
||
|
10 years ago
|
debug_status_label().set_text("");
|
||
|
10 years ago
|
else
|
||
|
9 years ago
|
debug_status_label().set_text(debug_status);
|
||
|
9 years ago
|
debug_activate_menu_items();
|
||
|
|
}
|
||
|
|
|
||
|
|
void Project::debug_activate_menu_items() {
|
||
|
8 years ago
|
auto &menu = Menu::get();
|
||
|
|
auto view = Notebook::get().get_current_view();
|
||
|
10 years ago
|
menu.actions["debug_stop"]->set_enabled(!debug_status.empty());
|
||
|
|
menu.actions["debug_kill"]->set_enabled(!debug_status.empty());
|
||
|
|
menu.actions["debug_step_over"]->set_enabled(!debug_status.empty());
|
||
|
|
menu.actions["debug_step_into"]->set_enabled(!debug_status.empty());
|
||
|
|
menu.actions["debug_step_out"]->set_enabled(!debug_status.empty());
|
||
|
9 years ago
|
menu.actions["debug_backtrace"]->set_enabled(!debug_status.empty());
|
||
|
|
menu.actions["debug_show_variables"]->set_enabled(!debug_status.empty());
|
||
|
10 years ago
|
menu.actions["debug_run_command"]->set_enabled(!debug_status.empty());
|
||
|
9 years ago
|
menu.actions["debug_toggle_breakpoint"]->set_enabled(view && view->toggle_breakpoint);
|
||
|
10 years ago
|
menu.actions["debug_goto_stop"]->set_enabled(!debug_status.empty());
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
|
void Project::debug_update_stop() {
|
||
|
10 years ago
|
if(!debug_last_stop_file_path.empty()) {
|
||
|
8 years ago
|
for(size_t c = 0; c < Notebook::get().size(); c++) {
|
||
|
|
auto view = Notebook::get().get_view(c);
|
||
|
|
if(view->file_path == debug_last_stop_file_path) {
|
||
|
10 years ago
|
view->get_source_buffer()->remove_source_marks(view->get_buffer()->begin(), view->get_buffer()->end(), "debug_stop");
|
||
|
9 years ago
|
view->get_source_buffer()->remove_source_marks(view->get_buffer()->begin(), view->get_buffer()->end(), "debug_breakpoint_and_stop");
|
||
|
10 years ago
|
break;
|
||
|
|
}
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
}
|
||
|
|
//Add debug stop source mark
|
||
|
10 years ago
|
debug_last_stop_file_path.clear();
|
||
|
8 years ago
|
for(size_t c = 0; c < Notebook::get().size(); c++) {
|
||
|
|
auto view = Notebook::get().get_view(c);
|
||
|
|
if(view->file_path == debug_stop.first) {
|
||
|
|
if(debug_stop.second.first < view->get_buffer()->get_line_count()) {
|
||
|
|
auto iter = view->get_buffer()->get_iter_at_line(debug_stop.second.first);
|
||
|
7 years ago
|
gtk_source_buffer_create_source_mark(view->get_source_buffer()->gobj(), nullptr, "debug_stop", iter.gobj()); // Gsv::Buffer::create_source_mark is bugged
|
||
|
8 years ago
|
if(view->get_source_buffer()->get_source_marks_at_iter(iter, "debug_breakpoint").size() > 0)
|
||
|
7 years ago
|
gtk_source_buffer_create_source_mark(view->get_source_buffer()->gobj(), nullptr, "debug_breakpoint_and_stop", iter.gobj()); // Gsv::Buffer::create_source_mark is bugged
|
||
|
8 years ago
|
debug_last_stop_file_path = debug_stop.first;
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
break;
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
|
||
|
8 years ago
|
std::shared_ptr<Project::Base> Project::create() {
|
||
|
10 years ago
|
std::unique_ptr<Project::Build> build;
|
||
|
8 years ago
|
|
||
|
|
if(auto view = Notebook::get().get_current_view()) {
|
||
|
|
build = Build::create(view->file_path);
|
||
|
10 years ago
|
if(view->language) {
|
||
|
8 years ago
|
auto language_id = view->language->get_id();
|
||
|
|
if(language_id == "markdown")
|
||
|
8 years ago
|
return std::shared_ptr<Project::Base>(new Project::Markdown(std::move(build)));
|
||
|
8 years ago
|
if(language_id == "js")
|
||
|
8 years ago
|
return std::shared_ptr<Project::Base>(new Project::JavaScript(std::move(build)));
|
||
|
7 years ago
|
if(language_id == "python")
|
||
|
|
return std::shared_ptr<Project::Base>(new Project::Python(std::move(build)));
|
||
|
8 years ago
|
if(language_id == "html")
|
||
|
8 years ago
|
return std::shared_ptr<Project::Base>(new Project::HTML(std::move(build)));
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
else
|
||
|
8 years ago
|
build = Build::create(Directories::get().path);
|
||
|
|
|
||
|
|
if(dynamic_cast<CMakeBuild *>(build.get()) || dynamic_cast<MesonBuild *>(build.get()))
|
||
|
8 years ago
|
return std::shared_ptr<Project::Base>(new Project::Clang(std::move(build)));
|
||
|
7 years ago
|
if(dynamic_cast<CargoBuild *>(build.get()))
|
||
|
8 years ago
|
return std::shared_ptr<Project::Base>(new Project::Rust(std::move(build)));
|
||
|
7 years ago
|
if(dynamic_cast<NpmBuild *>(build.get()))
|
||
|
8 years ago
|
return std::shared_ptr<Project::Base>(new Project::JavaScript(std::move(build)));
|
||
|
7 years ago
|
if(dynamic_cast<PythonMain *>(build.get()))
|
||
|
|
return std::shared_ptr<Project::Base>(new Project::Python(std::move(build)));
|
||
|
|
return std::shared_ptr<Project::Base>(new Project::Base(std::move(build)));
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
10 years ago
|
std::pair<std::string, std::string> Project::Base::get_run_arguments() {
|
||
|
|
Info::get().print("Could not find a supported project");
|
||
|
|
return {"", ""};
|
||
|
|
}
|
||
|
|
|
||
|
|
void Project::Base::compile() {
|
||
|
|
Info::get().print("Could not find a supported project");
|
||
|
|
}
|
||
|
|
|
||
|
|
void Project::Base::compile_and_run() {
|
||
|
|
Info::get().print("Could not find a supported project");
|
||
|
|
}
|
||
|
|
|
||
|
9 years ago
|
void Project::Base::recreate_build() {
|
||
|
|
Info::get().print("Could not find a supported project");
|
||
|
9 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::Base::show_symbols() {
|
||
|
6 years ago
|
Ctags ctags(get_preferably_view_folder());
|
||
|
|
if(!ctags) {
|
||
|
8 years ago
|
Info::get().print("No symbols found in current project");
|
||
|
|
return;
|
||
|
|
}
|
||
|
8 years ago
|
|
||
|
6 years ago
|
auto view = Notebook::get().get_current_view();
|
||
|
6 years ago
|
if(view)
|
||
|
|
SelectionDialog::create(view, true, true);
|
||
|
8 years ago
|
else
|
||
|
|
SelectionDialog::create(true, true);
|
||
|
8 years ago
|
|
||
|
8 years ago
|
std::vector<Source::Offset> rows;
|
||
|
8 years ago
|
|
||
|
8 years ago
|
std::string line;
|
||
|
6 years ago
|
while(std::getline(ctags.output, line)) {
|
||
|
|
auto location = ctags.get_location(line, true);
|
||
|
8 years ago
|
|
||
|
|
std::string row = location.file_path.string() + ":" + std::to_string(location.line + 1) + ": " + location.source;
|
||
|
8 years ago
|
rows.emplace_back(Source::Offset(location.line, location.index, location.file_path));
|
||
|
|
SelectionDialog::get()->add_row(row);
|
||
|
|
}
|
||
|
8 years ago
|
|
||
|
|
if(rows.size() == 0)
|
||
|
8 years ago
|
return;
|
||
|
6 years ago
|
SelectionDialog::get()->on_select = [rows = std::move(rows), project_path = std::move(ctags.project_path)](unsigned int index, const std::string &text, bool hide_window) {
|
||
|
8 years ago
|
if(index >= rows.size())
|
||
|
8 years ago
|
return;
|
||
|
8 years ago
|
auto offset = rows[index];
|
||
|
6 years ago
|
auto full_path = project_path / offset.file_path;
|
||
|
6 years ago
|
boost::system::error_code ec;
|
||
|
|
if(!boost::filesystem::is_regular_file(full_path, ec))
|
||
|
8 years ago
|
return;
|
||
|
|
Notebook::get().open(full_path);
|
||
|
8 years ago
|
auto view = Notebook::get().get_current_view();
|
||
|
8 years ago
|
view->place_cursor_at_line_index(offset.line, offset.index);
|
||
|
6 years ago
|
view->scroll_to_cursor_delayed(true, false);
|
||
|
8 years ago
|
};
|
||
|
|
if(view)
|
||
|
|
view->hide_tooltips();
|
||
|
|
SelectionDialog::get()->show();
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
std::pair<std::string, std::string> Project::Base::debug_get_run_arguments() {
|
||
|
|
Info::get().print("Could not find a supported project");
|
||
|
|
return {"", ""};
|
||
|
|
}
|
||
|
|
|
||
|
|
void Project::Base::debug_start() {
|
||
|
|
Info::get().print("Could not find a supported project");
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
#ifdef JUCI_ENABLE_DEBUG
|
||
|
8 years ago
|
std::pair<std::string, std::string> Project::LLDB::debug_get_run_arguments() {
|
||
|
8 years ago
|
auto debug_build_path = build->get_debug_path();
|
||
|
|
auto default_build_path = build->get_default_path();
|
||
|
9 years ago
|
if(debug_build_path.empty() || default_build_path.empty())
|
||
|
10 years ago
|
return {"", ""};
|
||
|
8 years ago
|
|
||
|
|
auto project_path = build->project_path.string();
|
||
|
|
auto run_arguments_it = debug_run_arguments.find(project_path);
|
||
|
10 years ago
|
std::string arguments;
|
||
|
8 years ago
|
if(run_arguments_it != debug_run_arguments.end())
|
||
|
|
arguments = run_arguments_it->second.arguments;
|
||
|
|
|
||
|
10 years ago
|
if(arguments.empty()) {
|
||
|
8 years ago
|
auto view = Notebook::get().get_current_view();
|
||
|
|
auto executable = build->get_executable(view ? view->file_path : Directories::get().path).string();
|
||
|
|
|
||
|
9 years ago
|
if(!executable.empty()) {
|
||
|
8 years ago
|
size_t pos = executable.find(default_build_path.string());
|
||
|
|
if(pos != std::string::npos)
|
||
|
9 years ago
|
executable.replace(pos, default_build_path.string().size(), debug_build_path.string());
|
||
|
8 years ago
|
arguments = filesystem::escape_argument(filesystem::get_short_path(executable).string());
|
||
|
10 years ago
|
}
|
||
|
|
else
|
||
|
8 years ago
|
arguments = filesystem::escape_argument(filesystem::get_short_path(build->get_debug_path()).string());
|
||
|
10 years ago
|
}
|
||
|
8 years ago
|
|
||
|
10 years ago
|
return {project_path, arguments};
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
Project::DebugOptions *Project::LLDB::debug_get_options() {
|
||
|
|
if(build->project_path.empty())
|
||
|
|
return nullptr;
|
||
|
8 years ago
|
|
||
|
|
debug_options = std::make_unique<DebugOptions>();
|
||
|
|
|
||
|
|
auto &arguments = Project::debug_run_arguments[build->project_path.string()];
|
||
|
|
|
||
|
|
auto remote_enabled = Gtk::manage(new Gtk::CheckButton());
|
||
|
|
auto remote_host_port = Gtk::manage(new Gtk::Entry());
|
||
|
8 years ago
|
remote_enabled->set_active(arguments.remote_enabled);
|
||
|
|
remote_enabled->set_label("Enabled");
|
||
|
|
remote_enabled->signal_clicked().connect([remote_enabled, remote_host_port] {
|
||
|
|
remote_host_port->set_sensitive(remote_enabled->get_active());
|
||
|
|
});
|
||
|
8 years ago
|
|
||
|
8 years ago
|
remote_host_port->set_sensitive(arguments.remote_enabled);
|
||
|
|
remote_host_port->set_text(arguments.remote_host_port);
|
||
|
|
remote_host_port->set_placeholder_text("host:port");
|
||
|
|
remote_host_port->signal_activate().connect([] {
|
||
|
|
debug_options->hide();
|
||
|
|
});
|
||
|
8 years ago
|
|
||
|
|
auto self = this->shared_from_this();
|
||
|
8 years ago
|
debug_options->signal_hide().connect([self, remote_enabled, remote_host_port] {
|
||
|
8 years ago
|
auto &arguments = Project::debug_run_arguments[self->build->project_path.string()];
|
||
|
|
arguments.remote_enabled = remote_enabled->get_active();
|
||
|
|
arguments.remote_host_port = remote_host_port->get_text();
|
||
|
8 years ago
|
});
|
||
|
8 years ago
|
|
||
|
|
auto remote_vbox = Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL));
|
||
|
8 years ago
|
remote_vbox->pack_start(*remote_enabled, true, true);
|
||
|
|
remote_vbox->pack_end(*remote_host_port, true, true);
|
||
|
8 years ago
|
|
||
|
|
auto remote_frame = Gtk::manage(new Gtk::Frame());
|
||
|
8 years ago
|
remote_frame->set_label("Remote Debugging");
|
||
|
|
remote_frame->add(*remote_vbox);
|
||
|
8 years ago
|
|
||
|
8 years ago
|
debug_options->vbox.pack_end(*remote_frame, true, true);
|
||
|
8 years ago
|
|
||
|
8 years ago
|
return debug_options.get();
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_start() {
|
||
|
8 years ago
|
auto debug_build_path = build->get_debug_path();
|
||
|
|
auto default_build_path = build->get_default_path();
|
||
|
9 years ago
|
if(debug_build_path.empty() || !build->update_debug() || default_build_path.empty())
|
||
|
9 years ago
|
return;
|
||
|
8 years ago
|
|
||
|
|
auto project_path = std::make_shared<boost::filesystem::path>(build->project_path);
|
||
|
|
|
||
|
|
auto run_arguments_it = debug_run_arguments.find(project_path->string());
|
||
|
|
auto run_arguments = std::make_shared<std::string>();
|
||
|
|
if(run_arguments_it != debug_run_arguments.end())
|
||
|
|
*run_arguments = run_arguments_it->second.arguments;
|
||
|
|
|
||
|
10 years ago
|
if(run_arguments->empty()) {
|
||
|
8 years ago
|
auto view = Notebook::get().get_current_view();
|
||
|
|
*run_arguments = build->get_executable(view ? view->file_path : Directories::get().path).string();
|
||
|
10 years ago
|
if(run_arguments->empty()) {
|
||
|
10 years ago
|
Terminal::get().print("Warning: could not find executable.\n");
|
||
|
9 years ago
|
Terminal::get().print("Solution: either use Debug Set Run Arguments, or open a source file within a directory where an executable is defined.\n", true);
|
||
|
10 years ago
|
return;
|
||
|
|
}
|
||
|
8 years ago
|
size_t pos = run_arguments->find(default_build_path.string());
|
||
|
|
if(pos != std::string::npos)
|
||
|
9 years ago
|
run_arguments->replace(pos, default_build_path.string().size(), debug_build_path.string());
|
||
|
8 years ago
|
*run_arguments = filesystem::escape_argument(filesystem::get_short_path(*run_arguments).string());
|
||
|
10 years ago
|
}
|
||
|
8 years ago
|
|
||
|
|
debugging = true;
|
||
|
|
|
||
|
10 years ago
|
if(Config::get().project.clear_terminal_on_compile)
|
||
|
|
Terminal::get().clear();
|
||
|
8 years ago
|
|
||
|
|
Terminal::get().print("Compiling and debugging " + *run_arguments + "\n");
|
||
|
|
Terminal::get().async_process(build->get_compile_command(), debug_build_path, [self = this->shared_from_this(), run_arguments, project_path](int exit_status) {
|
||
|
|
if(exit_status != EXIT_SUCCESS)
|
||
|
|
debugging = false;
|
||
|
10 years ago
|
else {
|
||
|
8 years ago
|
self->dispatcher.post([self, run_arguments, project_path] {
|
||
|
8 years ago
|
std::vector<std::pair<boost::filesystem::path, int>> breakpoints;
|
||
|
|
for(size_t c = 0; c < Notebook::get().size(); c++) {
|
||
|
|
auto view = Notebook::get().get_view(c);
|
||
|
10 years ago
|
if(filesystem::file_in_path(view->file_path, *project_path)) {
|
||
|
8 years ago
|
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);
|
||
|
10 years ago
|
while(view->get_source_buffer()->forward_iter_to_source_mark(iter, "debug_breakpoint"))
|
||
|
8 years ago
|
breakpoints.emplace_back(view->file_path, iter.get_line() + 1);
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
8 years ago
|
|
||
|
10 years ago
|
std::string remote_host;
|
||
|
8 years ago
|
auto debug_run_arguments_it = debug_run_arguments.find(project_path->string());
|
||
|
|
if(debug_run_arguments_it != debug_run_arguments.end() && debug_run_arguments_it->second.remote_enabled)
|
||
|
|
remote_host = debug_run_arguments_it->second.remote_host_port;
|
||
|
|
|
||
|
|
static auto on_exit_it = Debug::LLDB::get().on_exit.end();
|
||
|
|
if(on_exit_it != Debug::LLDB::get().on_exit.end())
|
||
|
8 years ago
|
Debug::LLDB::get().on_exit.erase(on_exit_it);
|
||
|
8 years ago
|
Debug::LLDB::get().on_exit.emplace_back([self, run_arguments](int exit_status) {
|
||
|
8 years ago
|
debugging = false;
|
||
|
|
Terminal::get().async_print(*run_arguments + " returned: " + std::to_string(exit_status) + '\n');
|
||
|
8 years ago
|
self->dispatcher.post([] {
|
||
|
8 years ago
|
debug_update_status("");
|
||
|
10 years ago
|
});
|
||
|
8 years ago
|
});
|
||
|
8 years ago
|
on_exit_it = std::prev(Debug::LLDB::get().on_exit.end());
|
||
|
|
|
||
|
|
static auto on_event_it = Debug::LLDB::get().on_event.end();
|
||
|
|
if(on_event_it != Debug::LLDB::get().on_event.end())
|
||
|
8 years ago
|
Debug::LLDB::get().on_event.erase(on_event_it);
|
||
|
8 years ago
|
Debug::LLDB::get().on_event.emplace_back([self](const lldb::SBEvent &event) {
|
||
|
8 years ago
|
std::string status;
|
||
|
|
boost::filesystem::path stop_path;
|
||
|
8 years ago
|
unsigned stop_line = 0, stop_column = 0;
|
||
|
|
|
||
|
7 years ago
|
LockGuard lock(Debug::LLDB::get().mutex);
|
||
|
8 years ago
|
auto process = lldb::SBProcess::GetProcessFromEvent(event);
|
||
|
|
auto state = lldb::SBProcess::GetStateFromEvent(event);
|
||
|
8 years ago
|
lldb::SBStream stream;
|
||
|
|
event.GetDescription(stream);
|
||
|
8 years ago
|
std::string event_desc = stream.GetData();
|
||
|
8 years ago
|
event_desc.pop_back();
|
||
|
8 years ago
|
auto pos = event_desc.rfind(" = ");
|
||
|
|
if(pos != std::string::npos && pos + 3 < event_desc.size())
|
||
|
|
status = event_desc.substr(pos + 3);
|
||
|
|
if(state == lldb::StateType::eStateStopped) {
|
||
|
8 years ago
|
char buffer[100];
|
||
|
8 years ago
|
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();
|
||
|
8 years ago
|
if(line_entry.IsValid()) {
|
||
|
|
lldb::SBStream stream;
|
||
|
|
line_entry.GetFileSpec().GetDescription(stream);
|
||
|
8 years ago
|
auto line = line_entry.GetLine();
|
||
|
|
status += " " + boost::filesystem::path(stream.GetData()).filename().string() + ":" + std::to_string(line);
|
||
|
|
auto column = line_entry.GetColumn();
|
||
|
|
if(column == 0)
|
||
|
|
column = 1;
|
||
|
|
stop_path = filesystem::get_normal_path(stream.GetData());
|
||
|
|
stop_line = line - 1;
|
||
|
|
stop_column = column - 1;
|
||
|
8 years ago
|
}
|
||
|
|
}
|
||
|
8 years ago
|
|
||
|
|
self->dispatcher.post([status = std::move(status), stop_path = std::move(stop_path), stop_line, stop_column] {
|
||
|
8 years ago
|
debug_update_status(status);
|
||
|
8 years ago
|
Project::debug_stop.first = stop_path;
|
||
|
|
Project::debug_stop.second.first = stop_line;
|
||
|
|
Project::debug_stop.second.second = stop_column;
|
||
|
10 years ago
|
debug_update_stop();
|
||
|
6 years ago
|
|
||
|
|
if(Config::get().source.debug_place_cursor_at_stop && !stop_path.empty()) {
|
||
|
|
Notebook::get().open(stop_path);
|
||
|
|
auto view = Notebook::get().get_current_view();
|
||
|
|
view->place_cursor_at_line_index(stop_line, stop_column);
|
||
|
6 years ago
|
view->scroll_to_cursor_delayed(true, false);
|
||
|
6 years ago
|
}
|
||
|
|
else if(auto view = Notebook::get().get_current_view())
|
||
|
10 years ago
|
view->get_buffer()->place_cursor(view->get_buffer()->get_insert()->get_iter());
|
||
|
|
});
|
||
|
8 years ago
|
});
|
||
|
8 years ago
|
on_event_it = std::prev(Debug::LLDB::get().on_event.end());
|
||
|
|
|
||
|
8 years ago
|
std::vector<std::string> startup_commands;
|
||
|
8 years ago
|
if(dynamic_cast<CargoBuild *>(self->build.get())) {
|
||
|
8 years ago
|
std::stringstream istream, ostream;
|
||
|
8 years ago
|
if(Terminal::get().process(istream, ostream, "rustc --print sysroot") == 0) {
|
||
|
|
auto sysroot = ostream.str();
|
||
|
|
while(!sysroot.empty() && (sysroot.back() == '\n' || sysroot.back() == '\r'))
|
||
|
8 years ago
|
sysroot.pop_back();
|
||
|
8 years ago
|
startup_commands.emplace_back("command script import \"" + sysroot + "/lib/rustlib/etc/lldb_rust_formatters.py\"");
|
||
|
8 years ago
|
startup_commands.emplace_back("type summary add --no-value --python-function lldb_rust_formatters.print_val -x \".*\" --category Rust");
|
||
|
|
startup_commands.emplace_back("type category enable Rust");
|
||
|
|
}
|
||
|
|
}
|
||
|
8 years ago
|
Debug::LLDB::get().start(*run_arguments, *project_path, breakpoints, startup_commands, remote_host);
|
||
|
10 years ago
|
});
|
||
|
10 years ago
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_continue() {
|
||
|
10 years ago
|
Debug::LLDB::get().continue_debug();
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_stop() {
|
||
|
10 years ago
|
if(debugging)
|
||
|
10 years ago
|
Debug::LLDB::get().stop();
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_kill() {
|
||
|
10 years ago
|
if(debugging)
|
||
|
10 years ago
|
Debug::LLDB::get().kill();
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_step_over() {
|
||
|
10 years ago
|
if(debugging)
|
||
|
10 years ago
|
Debug::LLDB::get().step_over();
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_step_into() {
|
||
|
10 years ago
|
if(debugging)
|
||
|
10 years ago
|
Debug::LLDB::get().step_into();
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_step_out() {
|
||
|
10 years ago
|
if(debugging)
|
||
|
10 years ago
|
Debug::LLDB::get().step_out();
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_backtrace() {
|
||
|
9 years ago
|
if(debugging) {
|
||
|
8 years ago
|
auto view = Notebook::get().get_current_view();
|
||
|
|
auto backtrace = Debug::LLDB::get().get_backtrace();
|
||
|
|
|
||
|
6 years ago
|
if(view)
|
||
|
|
SelectionDialog::create(view, true, true);
|
||
|
9 years ago
|
else
|
||
|
|
SelectionDialog::create(true, true);
|
||
|
8 years ago
|
std::vector<Debug::LLDB::Frame> rows;
|
||
|
8 years ago
|
if(backtrace.size() == 0) {
|
||
|
9 years ago
|
Info::get().print("No backtrace found");
|
||
|
10 years ago
|
return;
|
||
|
9 years ago
|
}
|
||
|
8 years ago
|
|
||
|
|
bool cursor_set = false;
|
||
|
|
for(auto &frame : backtrace) {
|
||
|
|
std::string row = "<i>" + frame.module_filename + "</i>";
|
||
|
|
|
||
|
10 years ago
|
//Shorten frame.function_name if it is too long
|
||
|
8 years ago
|
if(frame.function_name.size() > 120) {
|
||
|
|
frame.function_name = frame.function_name.substr(0, 58) + "...." + frame.function_name.substr(frame.function_name.size() - 58);
|
||
|
10 years ago
|
}
|
||
|
|
if(frame.file_path.empty())
|
||
|
8 years ago
|
row += " - " + Glib::Markup::escape_text(frame.function_name);
|
||
|
10 years ago
|
else {
|
||
|
8 years ago
|
auto file_path = frame.file_path.filename().string();
|
||
|
|
row += ":<b>" + Glib::Markup::escape_text(file_path) + ":" + std::to_string(frame.line_nr) + "</b> - " + Glib::Markup::escape_text(frame.function_name);
|
||
|
10 years ago
|
}
|
||
|
8 years ago
|
rows.emplace_back(frame);
|
||
|
9 years ago
|
SelectionDialog::get()->add_row(row);
|
||
|
8 years ago
|
if(!cursor_set && view && frame.file_path == view->file_path) {
|
||
|
9 years ago
|
SelectionDialog::get()->set_cursor_at_last_row();
|
||
|
8 years ago
|
cursor_set = true;
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
}
|
||
|
8 years ago
|
|
||
|
|
SelectionDialog::get()->on_select = [rows = std::move(rows)](unsigned int index, const std::string &text, bool hide_window) {
|
||
|
|
if(index >= rows.size())
|
||
|
8 years ago
|
return;
|
||
|
8 years ago
|
auto frame = rows[index];
|
||
|
10 years ago
|
if(!frame.file_path.empty()) {
|
||
|
10 years ago
|
Notebook::get().open(frame.file_path);
|
||
|
8 years ago
|
if(auto view = Notebook::get().get_current_view()) {
|
||
|
10 years ago
|
Debug::LLDB::get().select_frame(frame.index);
|
||
|
8 years ago
|
|
||
|
|
view->place_cursor_at_line_index(frame.line_nr - 1, frame.line_index - 1);
|
||
|
6 years ago
|
view->scroll_to_cursor_delayed(true, true);
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
9 years ago
|
if(view)
|
||
|
|
view->hide_tooltips();
|
||
|
|
SelectionDialog::get()->show();
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_show_variables() {
|
||
|
9 years ago
|
if(debugging) {
|
||
|
8 years ago
|
auto view = Notebook::get().get_current_view();
|
||
|
|
auto variables = Debug::LLDB::get().get_variables();
|
||
|
|
|
||
|
6 years ago
|
if(view)
|
||
|
|
SelectionDialog::create(view, true, true);
|
||
|
9 years ago
|
else
|
||
|
|
SelectionDialog::create(true, true);
|
||
|
8 years ago
|
auto rows = std::make_shared<std::vector<Debug::LLDB::Variable>>();
|
||
|
|
if(variables.size() == 0) {
|
||
|
9 years ago
|
Info::get().print("No variables found");
|
||
|
10 years ago
|
return;
|
||
|
9 years ago
|
}
|
||
|
8 years ago
|
|
||
|
|
for(auto &variable : variables) {
|
||
|
|
std::string row = "#" + std::to_string(variable.thread_index_id) + ":#" + std::to_string(variable.frame_index) + ":" + variable.file_path.filename().string() + ":" + std::to_string(variable.line_nr) + " - <b>" + Glib::Markup::escape_text(variable.name) + "</b>";
|
||
|
|
|
||
|
8 years ago
|
rows->emplace_back(variable);
|
||
|
9 years ago
|
SelectionDialog::get()->add_row(row);
|
||
|
10 years ago
|
}
|
||
|
8 years ago
|
|
||
|
|
SelectionDialog::get()->on_select = [rows](unsigned int index, const std::string &text, bool hide_window) {
|
||
|
|
if(index >= rows->size())
|
||
|
8 years ago
|
return;
|
||
|
8 years ago
|
auto variable = (*rows)[index];
|
||
|
10 years ago
|
Debug::LLDB::get().select_frame(variable.frame_index, variable.thread_index_id);
|
||
|
10 years ago
|
if(!variable.file_path.empty()) {
|
||
|
10 years ago
|
Notebook::get().open(variable.file_path);
|
||
|
8 years ago
|
if(auto view = Notebook::get().get_current_view()) {
|
||
|
|
view->place_cursor_at_line_index(variable.line_nr - 1, variable.line_index - 1);
|
||
|
6 years ago
|
view->scroll_to_cursor_delayed(true, true);
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
10 years ago
|
if(!variable.declaration_found)
|
||
|
8 years ago
|
Info::get().print("Debugger did not find declaration for the variable: " + variable.name);
|
||
|
10 years ago
|
};
|
||
|
8 years ago
|
|
||
|
|
SelectionDialog::get()->on_hide = [self = this->shared_from_this()]() {
|
||
|
8 years ago
|
self->debug_variable_tooltips.hide();
|
||
|
|
self->debug_variable_tooltips.clear();
|
||
|
10 years ago
|
};
|
||
|
8 years ago
|
|
||
|
6 years ago
|
SelectionDialog::get()->on_changed = [self = this->shared_from_this(), rows, view](unsigned int index, const std::string &text) {
|
||
|
8 years ago
|
if(index >= rows->size()) {
|
||
|
8 years ago
|
self->debug_variable_tooltips.hide();
|
||
|
10 years ago
|
return;
|
||
|
|
}
|
||
|
8 years ago
|
self->debug_variable_tooltips.clear();
|
||
|
7 years ago
|
|
||
|
6 years ago
|
auto set_tooltip_buffer = [rows, index](Tooltip &tooltip) {
|
||
|
8 years ago
|
auto variable = (*rows)[index];
|
||
|
|
|
||
|
|
Glib::ustring value = variable.value;
|
||
|
9 years ago
|
if(!value.empty()) {
|
||
|
|
Glib::ustring::iterator iter;
|
||
|
|
while(!value.validate(iter)) {
|
||
|
8 years ago
|
auto next_char_iter = iter;
|
||
|
9 years ago
|
next_char_iter++;
|
||
|
|
value.replace(iter, next_char_iter, "?");
|
||
|
10 years ago
|
}
|
||
|
6 years ago
|
tooltip.buffer->insert(tooltip.buffer->get_insert()->get_iter(), value.substr(0, value.size() - 1));
|
||
|
9 years ago
|
}
|
||
|
|
};
|
||
|
6 years ago
|
if(view) {
|
||
|
|
auto iter = view->get_buffer()->get_insert()->get_iter();
|
||
|
7 years ago
|
self->debug_variable_tooltips.emplace_back(view, view->get_buffer()->create_mark(iter), view->get_buffer()->create_mark(iter), std::move(set_tooltip_buffer));
|
||
|
6 years ago
|
}
|
||
|
9 years ago
|
else
|
||
|
7 years ago
|
self->debug_variable_tooltips.emplace_back(std::move(set_tooltip_buffer));
|
||
|
8 years ago
|
|
||
|
8 years ago
|
self->debug_variable_tooltips.show(true);
|
||
|
10 years ago
|
};
|
||
|
8 years ago
|
|
||
|
9 years ago
|
if(view)
|
||
|
|
view->hide_tooltips();
|
||
|
|
SelectionDialog::get()->show();
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_run_command(const std::string &command) {
|
||
|
10 years ago
|
if(debugging) {
|
||
|
8 years ago
|
auto command_return = Debug::LLDB::get().run_command(command);
|
||
|
10 years ago
|
Terminal::get().async_print(command_return.first);
|
||
|
|
Terminal::get().async_print(command_return.second, true);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_add_breakpoint(const boost::filesystem::path &file_path, int line_nr) {
|
||
|
10 years ago
|
Debug::LLDB::get().add_breakpoint(file_path, line_nr);
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_remove_breakpoint(const boost::filesystem::path &file_path, int line_nr, int line_count) {
|
||
|
10 years ago
|
Debug::LLDB::get().remove_breakpoint(file_path, line_nr, line_count);
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
bool Project::LLDB::debug_is_running() {
|
||
|
10 years ago
|
return Debug::LLDB::get().is_running();
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::LLDB::debug_write(const std::string &buffer) {
|
||
|
10 years ago
|
Debug::LLDB::get().write(buffer);
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
#endif
|
||
|
|
|
||
|
8 years ago
|
void Project::LanguageProtocol::show_symbols() {
|
||
|
7 years ago
|
auto project_path = std::make_shared<boost::filesystem::path>(build->project_path);
|
||
|
|
auto view = Notebook::get().get_current_view();
|
||
|
|
auto language_protocol_view = dynamic_cast<Source::LanguageProtocolView *>(view);
|
||
|
|
|
||
|
|
if(project_path->empty()) {
|
||
|
|
if(language_protocol_view)
|
||
|
|
*project_path = language_protocol_view->file_path.parent_path();
|
||
|
|
else {
|
||
|
|
Info::get().print("Could not find project folder");
|
||
|
|
return;
|
||
|
|
}
|
||
|
8 years ago
|
}
|
||
|
8 years ago
|
|
||
|
|
auto language_id = get_language_id();
|
||
|
|
auto executable_name = language_id + "-language-server";
|
||
|
7 years ago
|
if(filesystem::find_executable(executable_name).empty())
|
||
|
|
return Base::show_symbols();
|
||
|
8 years ago
|
|
||
|
7 years ago
|
auto client = ::LanguageProtocol::Client::get(language_protocol_view ? language_protocol_view->file_path : *project_path, language_id);
|
||
|
|
auto capabilities = client->initialize(language_protocol_view);
|
||
|
7 years ago
|
|
||
|
7 years ago
|
if(!capabilities.workspace_symbol && !(capabilities.document_symbol && language_protocol_view))
|
||
|
|
return Base::show_symbols();
|
||
|
8 years ago
|
|
||
|
6 years ago
|
if(view)
|
||
|
|
SelectionDialog::create(view, true, true);
|
||
|
8 years ago
|
else
|
||
|
|
SelectionDialog::create(true, true);
|
||
|
8 years ago
|
|
||
|
|
SelectionDialog::get()->on_hide = [] {
|
||
|
|
SelectionDialog::get()->on_search_entry_changed = nullptr; // To delete client object
|
||
|
8 years ago
|
};
|
||
|
8 years ago
|
|
||
|
6 years ago
|
auto locations = std::make_shared<std::vector<std::pair<::LanguageProtocol::Location, std::string>>>();
|
||
|
7 years ago
|
if(capabilities.workspace_symbol) {
|
||
|
7 years ago
|
SelectionDialog::get()->on_search_entry_changed = [client, project_path, locations](const std::string &text) {
|
||
|
7 years ago
|
if(text.size() > 1)
|
||
|
8 years ago
|
return;
|
||
|
7 years ago
|
else {
|
||
|
7 years ago
|
locations->clear();
|
||
|
7 years ago
|
SelectionDialog::get()->erase_rows();
|
||
|
|
if(text.empty())
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
std::promise<void> result_processed;
|
||
|
6 years ago
|
client->write_request(nullptr, "workspace/symbol", R"("query":")" + text + '"', [&result_processed, locations, project_path](const boost::property_tree::ptree &result, bool error) {
|
||
|
7 years ago
|
if(!error) {
|
||
|
|
for(auto it = result.begin(); it != result.end(); ++it) {
|
||
|
7 years ago
|
try {
|
||
|
|
::LanguageProtocol::Location location(it->second.get_child("location"));
|
||
|
7 years ago
|
if(filesystem::file_in_path(location.file, *project_path)) {
|
||
|
6 years ago
|
auto container = it->second.get<std::string>("containerName", "");
|
||
|
|
if(container == "null")
|
||
|
|
container.clear();
|
||
|
7 years ago
|
|
||
|
6 years ago
|
auto row = filesystem::get_relative_path(location.file, *project_path).string() + ':' + std::to_string(location.range.start.line + 1) + ": " + (!container.empty() ? container + "::" : "") + "<b>" + it->second.get<std::string>("name") + "</b>";
|
||
|
7 years ago
|
|
||
|
6 years ago
|
locations->emplace_back(std::make_pair(std::move(location), std::move(row)));
|
||
|
7 years ago
|
}
|
||
|
|
}
|
||
|
7 years ago
|
catch(...) {
|
||
|
|
}
|
||
|
7 years ago
|
}
|
||
|
|
}
|
||
|
|
result_processed.set_value();
|
||
|
|
});
|
||
|
|
result_processed.get_future().get();
|
||
|
7 years ago
|
|
||
|
6 years ago
|
std::sort(locations->begin(), locations->end());
|
||
|
|
for(auto &location : *locations) {
|
||
|
|
SelectionDialog::get()->add_row(location.second);
|
||
|
|
location.second.clear();
|
||
|
7 years ago
|
}
|
||
|
7 years ago
|
};
|
||
|
|
}
|
||
|
|
else {
|
||
|
8 years ago
|
std::promise<void> result_processed;
|
||
|
6 years ago
|
client->write_request(language_protocol_view, "textDocument/documentSymbol", R"("textDocument":{"uri":")" + language_protocol_view->uri + "\"}", [&result_processed, locations, language_protocol_view](const boost::property_tree::ptree &result, bool error) {
|
||
|
8 years ago
|
if(!error) {
|
||
|
6 years ago
|
std::function<void(const boost::property_tree::ptree &ptee, const std::string &container)> parse_result = [locations, &parse_result, language_protocol_view](const boost::property_tree::ptree &pt, const std::string &container) {
|
||
|
6 years ago
|
for(auto it = pt.begin(); it != pt.end(); ++it) {
|
||
|
|
try {
|
||
|
|
std::unique_ptr<::LanguageProtocol::Location> location;
|
||
|
|
std::string prefix;
|
||
|
|
auto location_pt = it->second.get_child_optional("location");
|
||
|
|
if(location_pt) {
|
||
|
|
location = std::make_unique<::LanguageProtocol::Location>(*location_pt);
|
||
|
|
std::string container = it->second.get<std::string>("containerName", "");
|
||
|
|
if(container == "null")
|
||
|
|
container.clear();
|
||
|
|
if(!container.empty())
|
||
|
|
prefix = container + "::";
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
location = std::make_unique<::LanguageProtocol::Location>(language_protocol_view->file_path.string(), ::LanguageProtocol::Range(it->second.get_child("range")));
|
||
|
|
if(!container.empty())
|
||
|
|
prefix = container + "::";
|
||
|
|
}
|
||
|
|
auto row = std::to_string(location->range.start.line + 1) + ": " + prefix + "<b>" + it->second.get<std::string>("name") + "</b>";
|
||
|
6 years ago
|
locations->emplace_back(std::make_pair(std::move(*location), std::move(row)));
|
||
|
6 years ago
|
auto children = it->second.get_child_optional("children");
|
||
|
|
if(children)
|
||
|
|
parse_result(*children, (!container.empty() ? container + "::" : "") + it->second.get<std::string>("name"));
|
||
|
|
}
|
||
|
|
catch(...) {
|
||
|
|
}
|
||
|
8 years ago
|
}
|
||
|
6 years ago
|
};
|
||
|
|
parse_result(result, "");
|
||
|
8 years ago
|
}
|
||
|
|
result_processed.set_value();
|
||
|
|
});
|
||
|
|
result_processed.get_future().get();
|
||
|
7 years ago
|
|
||
|
6 years ago
|
std::sort(locations->begin(), locations->end());
|
||
|
|
for(auto &location : *locations) {
|
||
|
|
SelectionDialog::get()->add_row(location.second);
|
||
|
|
location.second.clear();
|
||
|
7 years ago
|
}
|
||
|
7 years ago
|
}
|
||
|
8 years ago
|
|
||
|
7 years ago
|
SelectionDialog::get()->on_select = [locations](unsigned int index, const std::string &text, bool hide_window) {
|
||
|
6 years ago
|
auto &location = (*locations)[index].first;
|
||
|
6 years ago
|
boost::system::error_code ec;
|
||
|
6 years ago
|
if(!boost::filesystem::is_regular_file(location.file, ec))
|
||
|
8 years ago
|
return;
|
||
|
6 years ago
|
Notebook::get().open(location.file);
|
||
|
8 years ago
|
auto view = Notebook::get().get_current_view();
|
||
|
6 years ago
|
view->place_cursor_at_line_offset(location.range.start.line, location.range.start.character);
|
||
|
6 years ago
|
view->scroll_to_cursor_delayed(true, false);
|
||
|
8 years ago
|
};
|
||
|
8 years ago
|
|
||
|
8 years ago
|
if(view)
|
||
|
|
view->hide_tooltips();
|
||
|
|
SelectionDialog::get()->show();
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
std::pair<std::string, std::string> Project::Clang::get_run_arguments() {
|
||
|
8 years ago
|
auto build_path = build->get_default_path();
|
||
|
8 years ago
|
if(build_path.empty())
|
||
|
|
return {"", ""};
|
||
|
8 years ago
|
|
||
|
|
auto project_path = build->project_path.string();
|
||
|
|
auto run_arguments_it = run_arguments.find(project_path);
|
||
|
8 years ago
|
std::string arguments;
|
||
|
8 years ago
|
if(run_arguments_it != run_arguments.end())
|
||
|
|
arguments = run_arguments_it->second;
|
||
|
|
|
||
|
8 years ago
|
if(arguments.empty()) {
|
||
|
8 years ago
|
auto view = Notebook::get().get_current_view();
|
||
|
|
auto executable = build->get_executable(view ? view->file_path : Directories::get().path);
|
||
|
|
|
||
|
8 years ago
|
if(!executable.empty())
|
||
|
8 years ago
|
arguments = filesystem::escape_argument(filesystem::get_short_path(executable).string());
|
||
|
8 years ago
|
else
|
||
|
8 years ago
|
arguments = filesystem::escape_argument(filesystem::get_short_path(build->get_default_path()).string());
|
||
|
8 years ago
|
}
|
||
|
8 years ago
|
|
||
|
8 years ago
|
return {project_path, arguments};
|
||
|
|
}
|
||
|
|
|
||
|
|
void Project::Clang::compile() {
|
||
|
8 years ago
|
auto default_build_path = build->get_default_path();
|
||
|
8 years ago
|
if(default_build_path.empty() || !build->update_default())
|
||
|
|
return;
|
||
|
8 years ago
|
|
||
|
|
compiling = true;
|
||
|
|
|
||
|
8 years ago
|
if(Config::get().project.clear_terminal_on_compile)
|
||
|
|
Terminal::get().clear();
|
||
|
8 years ago
|
|
||
|
|
Terminal::get().print("Compiling project " + filesystem::get_short_path(build->project_path).string() + "\n");
|
||
|
8 years ago
|
Terminal::get().async_process(build->get_compile_command(), default_build_path, [](int exit_status) {
|
||
|
8 years ago
|
compiling = false;
|
||
|
8 years ago
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
void Project::Clang::compile_and_run() {
|
||
|
8 years ago
|
auto default_build_path = build->get_default_path();
|
||
|
8 years ago
|
if(default_build_path.empty() || !build->update_default())
|
||
|
|
return;
|
||
|
8 years ago
|
|
||
|
|
auto project_path = build->project_path;
|
||
|
|
|
||
|
|
auto run_arguments_it = run_arguments.find(project_path.string());
|
||
|
8 years ago
|
std::string arguments;
|
||
|
8 years ago
|
if(run_arguments_it != run_arguments.end())
|
||
|
|
arguments = run_arguments_it->second;
|
||
|
|
|
||
|
8 years ago
|
if(arguments.empty()) {
|
||
|
8 years ago
|
auto view = Notebook::get().get_current_view();
|
||
|
|
auto executable = build->get_executable(view ? view->file_path : Directories::get().path);
|
||
|
8 years ago
|
if(executable.empty()) {
|
||
|
|
Terminal::get().print("Warning: could not find executable.\n");
|
||
|
|
Terminal::get().print("Solution: either use Project Set Run Arguments, or open a source file within a directory where an executable is defined.\n", true);
|
||
|
|
return;
|
||
|
|
}
|
||
|
8 years ago
|
arguments = filesystem::escape_argument(filesystem::get_short_path(executable).string());
|
||
|
8 years ago
|
}
|
||
|
8 years ago
|
|
||
|
|
compiling = true;
|
||
|
|
|
||
|
8 years ago
|
if(Config::get().project.clear_terminal_on_compile)
|
||
|
|
Terminal::get().clear();
|
||
|
8 years ago
|
|
||
|
|
Terminal::get().print("Compiling and running " + arguments + "\n");
|
||
|
|
Terminal::get().async_process(build->get_compile_command(), default_build_path, [arguments, project_path](int exit_status) {
|
||
|
|
compiling = false;
|
||
|
|
if(exit_status == EXIT_SUCCESS) {
|
||
|
|
Terminal::get().async_process(arguments, project_path, [arguments](int exit_status) {
|
||
|
|
Terminal::get().async_print(arguments + " returned: " + std::to_string(exit_status) + '\n');
|
||
|
8 years ago
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
void Project::Clang::recreate_build() {
|
||
|
|
if(build->project_path.empty())
|
||
|
|
return;
|
||
|
8 years ago
|
auto default_build_path = build->get_default_path();
|
||
|
8 years ago
|
if(default_build_path.empty())
|
||
|
|
return;
|
||
|
8 years ago
|
|
||
|
|
auto debug_build_path = build->get_debug_path();
|
||
|
6 years ago
|
boost::system::error_code ec;
|
||
|
|
bool has_default_build = boost::filesystem::exists(default_build_path, ec);
|
||
|
|
bool has_debug_build = !debug_build_path.empty() && boost::filesystem::exists(debug_build_path, ec);
|
||
|
8 years ago
|
|
||
|
8 years ago
|
if(has_default_build || has_debug_build) {
|
||
|
8 years ago
|
Gtk::MessageDialog dialog(*static_cast<Gtk::Window *>(Notebook::get().get_toplevel()), "Recreate Build", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
|
||
|
8 years ago
|
dialog.set_default_response(Gtk::RESPONSE_NO);
|
||
|
8 years ago
|
std::string message = "Are you sure you want to recreate ";
|
||
|
8 years ago
|
if(has_default_build)
|
||
|
8 years ago
|
message += default_build_path.string();
|
||
|
8 years ago
|
if(has_debug_build) {
|
||
|
|
if(has_default_build)
|
||
|
8 years ago
|
message += " and ";
|
||
|
|
message += debug_build_path.string();
|
||
|
8 years ago
|
}
|
||
|
8 years ago
|
dialog.set_secondary_text(message + "?");
|
||
|
|
if(dialog.run() != Gtk::RESPONSE_YES)
|
||
|
8 years ago
|
return;
|
||
|
|
Usages::Clang::erase_all_caches_for_project(build->project_path, default_build_path);
|
||
|
|
try {
|
||
|
6 years ago
|
if(has_default_build) {
|
||
|
|
std::vector<boost::filesystem::path> paths;
|
||
|
|
for(boost::filesystem::directory_iterator it(default_build_path), end; it != end; ++it)
|
||
|
|
paths.emplace_back(*it);
|
||
|
|
for(auto &path : paths)
|
||
|
|
boost::filesystem::remove_all(path);
|
||
|
|
}
|
||
|
|
if(has_debug_build && boost::filesystem::exists(debug_build_path)) {
|
||
|
|
std::vector<boost::filesystem::path> paths;
|
||
|
|
for(boost::filesystem::directory_iterator it(debug_build_path), end; it != end; ++it)
|
||
|
|
paths.emplace_back(*it);
|
||
|
|
for(auto &path : paths)
|
||
|
|
boost::filesystem::remove_all(path);
|
||
|
|
}
|
||
|
8 years ago
|
}
|
||
|
|
catch(const std::exception &e) {
|
||
|
8 years ago
|
Terminal::get().print(std::string("Error: could not remove build: ") + e.what() + "\n", true);
|
||
|
8 years ago
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
8 years ago
|
|
||
|
8 years ago
|
build->update_default(true);
|
||
|
|
if(has_debug_build)
|
||
|
|
build->update_debug(true);
|
||
|
8 years ago
|
|
||
|
|
for(size_t c = 0; c < Notebook::get().size(); c++) {
|
||
|
|
auto source_view = Notebook::get().get_view(c);
|
||
|
|
if(auto source_clang_view = dynamic_cast<Source::ClangView *>(source_view)) {
|
||
|
8 years ago
|
if(filesystem::file_in_path(source_clang_view->file_path, build->project_path))
|
||
|
8 years ago
|
source_clang_view->full_reparse_needed = true;
|
||
|
8 years ago
|
}
|
||
|
|
}
|
||
|
8 years ago
|
|
||
|
|
if(auto view = Notebook::get().get_current_view()) {
|
||
|
8 years ago
|
if(view->full_reparse_needed)
|
||
|
|
view->full_reparse();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
|
||
|
10 years ago
|
void Project::Markdown::compile_and_run() {
|
||
|
6 years ago
|
auto command = Config::get().project.markdown_command + ' ' + filesystem::escape_argument(filesystem::get_short_path(Notebook::get().get_current_view()->file_path).string());
|
||
|
|
Terminal::get().async_process(command, "", [command](int exit_status) {
|
||
|
|
if(exit_status == 127)
|
||
|
|
Terminal::get().async_print("Error: executable not found: " + command + "\n", true);
|
||
|
|
}, true);
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
|
||
|
10 years ago
|
void Project::Python::compile_and_run() {
|
||
|
7 years ago
|
std::string command = Config::get().project.python_command + ' ';
|
||
|
|
boost::filesystem::path path;
|
||
|
7 years ago
|
if(dynamic_cast<PythonMain *>(build.get())) {
|
||
|
7 years ago
|
command += filesystem::get_short_path(build->project_path).string();
|
||
|
|
path = build->project_path;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
auto view = Notebook::get().get_current_view();
|
||
|
|
if(!view) {
|
||
|
|
Info::get().print("No executable found");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
command += filesystem::escape_argument(filesystem::get_short_path(view->file_path).string());
|
||
|
|
path = view->file_path.parent_path();
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
if(Config::get().project.clear_terminal_on_compile)
|
||
|
|
Terminal::get().clear();
|
||
|
8 years ago
|
|
||
|
|
Terminal::get().print("Running " + command + "\n");
|
||
|
7 years ago
|
Terminal::get().async_process(command, path, [command](int exit_status) {
|
||
|
8 years ago
|
Terminal::get().async_print(command + " returned: " + std::to_string(exit_status) + '\n');
|
||
|
10 years ago
|
});
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
void Project::JavaScript::compile_and_run() {
|
||
|
8 years ago
|
std::string command;
|
||
|
|
boost::filesystem::path path;
|
||
|
7 years ago
|
if(dynamic_cast<NpmBuild *>(build.get())) {
|
||
|
8 years ago
|
command = "npm start";
|
||
|
|
path = build->project_path;
|
||
|
8 years ago
|
}
|
||
|
|
else {
|
||
|
8 years ago
|
auto view = Notebook::get().get_current_view();
|
||
|
8 years ago
|
if(!view) {
|
||
|
|
Info::get().print("No executable found");
|
||
|
|
return;
|
||
|
|
}
|
||
|
6 years ago
|
command = "node " + filesystem::escape_argument(filesystem::get_short_path(view->file_path).string());
|
||
|
8 years ago
|
path = view->file_path.parent_path();
|
||
|
8 years ago
|
}
|
||
|
8 years ago
|
|
||
|
8 years ago
|
if(Config::get().project.clear_terminal_on_compile)
|
||
|
|
Terminal::get().clear();
|
||
|
8 years ago
|
|
||
|
|
Terminal::get().print("Running " + command + "\n");
|
||
|
8 years ago
|
Terminal::get().async_process(command, path, [command](int exit_status) {
|
||
|
8 years ago
|
Terminal::get().async_print(command + " returned: " + std::to_string(exit_status) + '\n');
|
||
|
10 years ago
|
});
|
||
|
|
}
|
||
|
10 years ago
|
|
||
|
10 years ago
|
void Project::HTML::compile_and_run() {
|
||
|
7 years ago
|
if(dynamic_cast<NpmBuild *>(build.get())) {
|
||
|
|
std::string command = "npm start";
|
||
|
|
|
||
|
|
if(Config::get().project.clear_terminal_on_compile)
|
||
|
|
Terminal::get().clear();
|
||
|
|
|
||
|
|
Terminal::get().print("Running " + command + "\n");
|
||
|
|
Terminal::get().async_process(command, build->project_path, [command](int exit_status) {
|
||
|
|
Terminal::get().async_print(command + " returned: " + std::to_string(exit_status) + '\n');
|
||
|
|
});
|
||
|
|
}
|
||
|
|
else
|
||
|
|
Notebook::get().open_uri(std::string("file://") + Notebook::get().get_current_view()->file_path.string());
|
||
|
10 years ago
|
}
|
||
|
8 years ago
|
|
||
|
8 years ago
|
std::pair<std::string, std::string> Project::Rust::get_run_arguments() {
|
||
|
8 years ago
|
auto project_path = build->project_path.string();
|
||
|
|
auto run_arguments_it = run_arguments.find(project_path);
|
||
|
8 years ago
|
std::string arguments;
|
||
|
8 years ago
|
if(run_arguments_it != run_arguments.end())
|
||
|
|
arguments = run_arguments_it->second;
|
||
|
|
|
||
|
8 years ago
|
if(arguments.empty())
|
||
|
8 years ago
|
arguments = filesystem::get_short_path(build->get_executable(project_path)).string();
|
||
|
|
|
||
|
8 years ago
|
return {project_path, arguments};
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::Rust::compile() {
|
||
|
8 years ago
|
compiling = true;
|
||
|
|
|
||
|
8 years ago
|
if(Config::get().project.clear_terminal_on_compile)
|
||
|
|
Terminal::get().clear();
|
||
|
8 years ago
|
|
||
|
|
Terminal::get().print("Compiling project " + filesystem::get_short_path(build->project_path).string() + "\n");
|
||
|
|
|
||
|
|
auto command = build->get_compile_command();
|
||
|
8 years ago
|
Terminal::get().async_process(command, build->project_path, [](int exit_status) {
|
||
|
8 years ago
|
compiling = false;
|
||
|
8 years ago
|
});
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
void Project::Rust::compile_and_run() {
|
||
|
8 years ago
|
compiling = true;
|
||
|
|
|
||
|
8 years ago
|
if(Config::get().project.clear_terminal_on_compile)
|
||
|
|
Terminal::get().clear();
|
||
|
8 years ago
|
|
||
|
|
auto arguments = get_run_arguments().second;
|
||
|
|
Terminal::get().print("Compiling and running " + arguments + "\n");
|
||
|
|
|
||
|
|
auto self = this->shared_from_this();
|
||
|
|
Terminal::get().async_process(build->get_compile_command(), build->project_path, [self, arguments = std::move(arguments)](int exit_status) {
|
||
|
|
compiling = false;
|
||
|
|
if(exit_status == EXIT_SUCCESS) {
|
||
|
8 years ago
|
Terminal::get().async_process(arguments, self->build->project_path, [arguments](int exit_status) {
|
||
|
8 years ago
|
Terminal::get().async_print(arguments + " returned: " + std::to_string(exit_status) + '\n');
|
||
|
8 years ago
|
});
|
||
|
|
}
|
||
|
8 years ago
|
});
|
||
|
|
}
|