From 7516d1d9b0456d0814e0931e71e1b4f97e0369f1 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 27 Jul 2017 13:10:23 +0200 Subject: [PATCH] Terminal links cleanup, and added links for a assert error messages. Also added terminal_test.cc --- src/CMakeLists.txt | 2 +- src/terminal.cc | 113 +++++++++++++++++++++++++--------------- src/terminal.h | 4 +- tests/CMakeLists.txt | 8 ++- tests/stubs/notebook.cc | 9 ++++ tests/stubs/project.cc | 3 ++ tests/stubs/terminal.cc | 33 ------------ tests/terminal_test.cc | 41 +++++++++++++++ 8 files changed, 136 insertions(+), 77 deletions(-) create mode 100644 tests/stubs/notebook.cc create mode 100644 tests/stubs/project.cc delete mode 100644 tests/stubs/terminal.cc create mode 100644 tests/terminal_test.cc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e6e309f..fe8d28e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,6 @@ set(project_files notebook.cc project.cc selection_dialog.cc - terminal.cc tooltips.cc window.cc ) @@ -33,6 +32,7 @@ set(project_shared_files source_clang.cc source_diff.cc source_spellcheck.cc + terminal.cc ${PROJECT_SOURCE_DIR}/libclangmm/src/CodeCompleteResults.cc ${PROJECT_SOURCE_DIR}/libclangmm/src/CompilationDatabase.cc diff --git a/src/terminal.cc b/src/terminal.cc index 8cd9ab2..076a54a 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -43,8 +43,6 @@ void Terminal::InProgress::cancel(const std::string& msg) { Terminal::get().async_print(line_nr-1, msg); } -const std::regex Terminal::link_regex("^([A-Z]:)?([^:]+):([0-9]+):([0-9]+)$"); - Terminal::Terminal() { bold_tag=get_buffer()->create_tag(); bold_tag->property_weight()=PANGO_WEIGHT_BOLD; @@ -177,39 +175,70 @@ bool Terminal::on_motion_notify_event(GdkEventMotion *motion_event) { return Gtk::TextView::on_motion_notify_event(motion_event); } +std::tuple Terminal::find_link(const std::string &line) { + const static std::regex link_regex("^([A-Z]:)?([^:]+):([0-9]+):([0-9]+): .*$|" //compile warning/error + "^Assertion failed: .*file ([A-Z]:)?([^:]+), line ([0-9]+)\\.$|" //clang assert() + "^[^:]*: ([A-Z]:)?([^:]+):([0-9]+): .* Assertion .* failed\\.$|" //gcc assert() + "^ERROR:([A-Z]:)?([^:]+):([0-9]+):.*$"); //g_assert (glib.h) + size_t start_position=-1, end_position=-1; + std::string path, line_number, line_offset; + std::smatch sm; + if(std::regex_match(line, sm, link_regex)) { + for(size_t sub=1;subget_text(start_path_iter, iter).raw(), sm, link_regex)) - get_buffer()->apply_tag(link_tag, start_path_iter, iter); - possible_path=false; - } - } + if(line_start_set && (*iter=='\\' || *iter=='/')) + delimiter_found=true; + else if(line_start_set && *iter=='.') + dot_found=true; + else if(line_start_set && (*iter>='0' && *iter<='9')) + number_found=true; + else if(line_start_set && delimiter_found && dot_found && number_found && iter.ends_line()) { + auto line=get_buffer()->get_text(line_start, iter); + //Convert to ascii for std::regex and Gtk::Iter::forward_chars + for(size_t c=0;c127) + line.replace(c, 1, "a"); + } + auto link=find_link(line.raw()); + if(std::get<0>(link)!=static_cast(-1)) { + auto link_start=line_start; + auto link_end=line_start; + link_start.forward_chars(std::get<0>(link)); + link_end.forward_chars(std::get<1>(link)); + get_buffer()->apply_tag(link_tag, link_start, link_end); } + line_start_set=false; } } while(iter.forward_char() && iter!=end_iter); } @@ -348,14 +377,16 @@ bool Terminal::on_button_press_event(GdkEventButton* button_event) { int location_x, location_y; window_to_buffer_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, button_event->x, button_event->y, location_x, location_y); get_iter_at_location(iter, location_x, location_y); - auto start_iter=iter; - auto end_iter=iter; - if(iter.has_tag(link_tag) && - start_iter.backward_to_tag_toggle(link_tag) && end_iter.forward_to_tag_toggle(link_tag)) { - std::string path_str=get_buffer()->get_text(start_iter, end_iter); - std::smatch sm; - if(std::regex_match(path_str, sm, link_regex)) { - auto path=boost::filesystem::path(sm[1].str()+sm[2].str()); + if(iter.has_tag(link_tag)) { + auto start_iter=get_buffer()->get_iter_at_line(iter.get_line()); + auto end_iter=start_iter; + while(!end_iter.ends_line() && end_iter.forward_char()) {} + auto link=find_link(get_buffer()->get_text(start_iter, end_iter).raw()); + if(std::get<0>(link)!=static_cast(-1)) { + boost::filesystem::path path=std::get<2>(link); + std::string line=std::get<3>(link); + std::string index=std::get<4>(link); + if(path.is_relative()) { if(Project::current) { auto absolute_path=Project::current->build->get_default_path()/path; @@ -371,13 +402,13 @@ bool Terminal::on_button_press_event(GdkEventButton* button_event) { Notebook::get().open(path); if(auto view=Notebook::get().get_current_view()) { try { - int line = std::stoi(sm[3].str())-1; - int index = std::stoi(sm[4].str())-1; - view->place_cursor_at_line_index(line, index); + int line_int = std::stoi(line)-1; + int index_int = std::stoi(index)-1; + view->place_cursor_at_line_index(line_int, index_int); view->scroll_to_cursor_delayed(view, true, true); return true; } - catch(const std::exception &) {} + catch(...) {} } } } diff --git a/src/terminal.h b/src/terminal.h index 4823ddb..2020cd6 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -12,6 +12,7 @@ #include "dispatcher.h" #include #include +#include class Terminal : public Gtk::TextView { public: @@ -64,7 +65,8 @@ private: Glib::RefPtr link_mouse_cursor; Glib::RefPtr default_mouse_cursor; size_t deleted_lines=0; - const static std::regex link_regex; + + std::tuple find_link(const std::string &line); void apply_link_tags(Gtk::TextIter start_iter, Gtk::TextIter end_iter); std::vector> processes; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 086f345..009dd6b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,8 +5,9 @@ set(stub_files stubs/dialogs.cc stubs/directories.cc stubs/info.cc + stubs/notebook.cc + stubs/project.cc stubs/selection_dialog.cc - stubs/terminal.cc stubs/tooltips.cc ) @@ -54,6 +55,11 @@ add_executable(source_key_test source_key_test.cc target_link_libraries(source_key_test ${global_libraries}) add_test(source_key_test source_key_test) +add_executable(terminal_test terminal_test.cc + $ $) +target_link_libraries(terminal_test ${global_libraries}) +add_test(terminal_test terminal_test) + if(LIBLLDB_FOUND) add_executable(lldb_test lldb_test.cc $ $) diff --git a/tests/stubs/notebook.cc b/tests/stubs/notebook.cc new file mode 100644 index 0000000..a4681b4 --- /dev/null +++ b/tests/stubs/notebook.cc @@ -0,0 +1,9 @@ +#include "notebook.h" + +Notebook::Notebook() {} + +Source::View *Notebook::get_current_view() { + return nullptr; +} + +void Notebook::open(const boost::filesystem::path &file_path, size_t notebook_index) {} diff --git a/tests/stubs/project.cc b/tests/stubs/project.cc new file mode 100644 index 0000000..3487dbf --- /dev/null +++ b/tests/stubs/project.cc @@ -0,0 +1,3 @@ +#include "project.h" + +std::unique_ptr Project::current; diff --git a/tests/stubs/terminal.cc b/tests/stubs/terminal.cc deleted file mode 100644 index 43f97c6..0000000 --- a/tests/stubs/terminal.cc +++ /dev/null @@ -1,33 +0,0 @@ -#include "terminal.h" - -Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) {} - -Terminal::InProgress::~InProgress() {} - -std::shared_ptr Terminal::print_in_progress(std::string start_msg) { - return std::make_shared(""); -} - -void Terminal::InProgress::done(const std::string& msg) {} - -void Terminal::InProgress::cancel(const std::string &msg) {} - -Terminal::Terminal() {} - -bool Terminal::on_motion_notify_event(GdkEventMotion* motion_event) {return false;} -bool Terminal::on_button_press_event(GdkEventButton* button_event) {return false;} -bool Terminal::on_key_press_event(GdkEventKey *event) {return false;} - -int Terminal::process(const std::string &command, const boost::filesystem::path &path, bool use_pipes) { - return 0; -} - -int Terminal::process(std::istream &stdin_stream, std::ostream &stdout_stream, const std::string &command, const boost::filesystem::path &path) { - return 0; -} - -size_t Terminal::print(const std::string &message, bool bold) { - return 0; -} - -void Terminal::async_print(const std::string &message, bool bold) {} diff --git a/tests/terminal_test.cc b/tests/terminal_test.cc new file mode 100644 index 0000000..904db0e --- /dev/null +++ b/tests/terminal_test.cc @@ -0,0 +1,41 @@ +#include "terminal.h" +#include + +//Requires display server to work +//However, it is possible to use the Broadway backend if the test is run in a pure terminal environment: +//broadwayd& +//make test + +int main() { + auto app = Gtk::Application::create(); + + { + auto link=Terminal::get().find_link("~/test/test.cc:7:41: error: expected ';' after expression."); + assert(std::get<0>(link)==0); + assert(std::get<1>(link)==19); + assert(std::get<2>(link)=="~/test/test.cc"); + assert(std::get<3>(link)=="7"); + assert(std::get<4>(link)=="41"); + } + { + auto link=Terminal::get().find_link("Assertion failed: (false), function main, file ~/test/test.cc, line 15."); + assert(std::get<0>(link)==47); + assert(std::get<1>(link)==70); + assert(std::get<2>(link)=="~/test/test.cc"); + assert(std::get<3>(link)=="15"); + } + { + auto link=Terminal::get().find_link("test: ~/examples/main.cpp:17: int main(int, char**): Assertion `false' failed."); + assert(std::get<0>(link)==6); + assert(std::get<1>(link)==28); + assert(std::get<2>(link)=="~/examples/main.cpp"); + assert(std::get<3>(link)=="17"); + } + { + auto link=Terminal::get().find_link("ERROR:~/test/test.cc:36:int main(): assertion failed: (false)"); + assert(std::get<0>(link)==6); + assert(std::get<1>(link)==23); + assert(std::get<2>(link)=="~/test/test.cc"); + assert(std::get<3>(link)=="36"); + } +}