From cfeef6c618ee025a6af1eaa2c8e4a09293c213f4 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 20 Feb 2017 12:30:03 +0100 Subject: [PATCH] Fixes to #317: Use primary-left click to move to implementation or declaration --- src/source.cc | 27 ++++++++-- src/source.h | 2 +- src/source_clang.cc | 118 +++++++++++++++++++++++++------------------- 3 files changed, 90 insertions(+), 57 deletions(-) diff --git a/src/source.cc b/src/source.cc index 716d94b..a9fe2c6 100644 --- a/src/source.cc +++ b/src/source.cc @@ -2213,6 +2213,7 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) { } bool Source::View::on_button_press_event(GdkEventButton *event) { + // Select range when double clicking if(event->type==GDK_2BUTTON_PRESS) { Gtk::TextIter start, end; get_buffer()->get_selection_bounds(start, end); @@ -2230,14 +2231,32 @@ bool Source::View::on_button_press_event(GdkEventButton *event) { return true; } + // Go to implementation or declaration if((event->type == GDK_BUTTON_PRESS) && (event->button == 1)){ - if(event->state & GDK_CONTROL_MASK) { - hide_tooltips(); - Menu::get().actions["source_goto_implementation"]->activate(); - return true; +#ifdef __APPLE__ + GdkModifierType mask=GDK_MOD2_MASK; +#else + GdkModifierType mask=GDK_CONTROL_MASK; +#endif + if(event->state & mask) { + int x, y; + window_to_buffer_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, event->x, event->y, x, y); + Gtk::TextIter iter; + get_iter_at_location(iter, x, y); + if(iter) + get_buffer()->place_cursor(iter); + + if(is_implementation_location) { + if(is_implementation_location()) + Menu::get().actions["source_goto_declaration"]->activate(); + else + Menu::get().actions["source_goto_implementation"]->activate(); + return true; + } } } + // Open right click menu if((event->type == GDK_BUTTON_PRESS) && (event->button == 3)){ hide_tooltips(); if(!get_buffer()->get_has_selection()){ diff --git a/src/source.h b/src/source.h index 87d8b1a..ee966d9 100644 --- a/src/source.h +++ b/src/source.h @@ -68,7 +68,7 @@ namespace Source { std::function non_interactive_completion; std::function format_style; std::function get_declaration_location; - std::function is_implementation; + std::function is_implementation_location; std::function(const std::vector &views)> get_implementation_locations; std::function >(const std::vector &views)> get_usages; std::function get_method; diff --git a/src/source_clang.cc b/src/source_clang.cc index c5efa0b..2ca0cb7 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -1012,7 +1012,60 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file } }); - get_declaration_location=[this](){ + auto get_header_location=[this]() { + // If cursor is at an include line, return offset to included file + const static std::regex include_regex("^[ \t]*#[ \t]*include[ \t]*[<\"](.+)[>\"][ \t]*$"); + std::smatch sm; + auto line=get_line(); + if(std::regex_match(line, sm, include_regex)) { + struct ClientData { + boost::filesystem::path &file_path; + std::string found_include; + int line_nr; + std::string sm_str; + }; + ClientData client_data{this->file_path, std::string(), get_buffer()->get_insert()->get_iter().get_line(), sm[1].str()}; + + // Attempt to find the 100% correct include file first + clang_getInclusions(clang_tu->cx_tu, [](CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data_) { + auto client_data=static_cast(client_data_); + if(client_data->found_include.empty() && include_len>0) { + auto source_location=clang::SourceLocation(inclusion_stack[0]); + if(static_cast(source_location.get_offset().line)-1==client_data->line_nr && + filesystem::get_normal_path(source_location.get_path())==client_data->file_path) + client_data->found_include=clang::to_string(clang_getFileName(included_file)); + } + }, &client_data); + + if(!client_data.found_include.empty()) + return Offset(0, 0, client_data.found_include); + + // Find a matching include file if no include was found previously + clang_getInclusions(clang_tu->cx_tu, [](CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data_) { + auto client_data=static_cast(client_data_); + if(client_data->found_include.empty()) { + for(unsigned c=1;c(source_location.get_offset().line)-1<=client_data->line_nr && + filesystem::get_normal_path(source_location.get_path())==client_data->file_path) { + auto included_file_str=clang::to_string(clang_getFileName(included_file)); + if(included_file_str.size()>=client_data->sm_str.size() && + included_file_str.compare(included_file_str.size()-client_data->sm_str.size(), client_data->sm_str.size(), client_data->sm_str)==0) { + client_data->found_include=included_file_str; + break; + } + } + } + } + }, &client_data); + + if(!client_data.found_include.empty()) + return Offset(0, 0, client_data.found_include); + } + return Offset(); + }; + + get_declaration_location=[this, get_header_location](){ if(!parsed) { Info::get().print("Buffer is parsing"); return Offset(); @@ -1024,61 +1077,15 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file return Offset(offset.line-1, offset.index-1, source_location.get_path()); } else { - // If cursor is at an include line, return offset to included file - const static std::regex include_regex("^[ \t]*#[ \t]*include[ \t]*[<\"](.+)[>\"][ \t]*$"); - std::smatch sm; - auto line=get_line(); - if(std::regex_match(line, sm, include_regex)) { - struct ClientData { - boost::filesystem::path &file_path; - std::string found_include; - int line_nr; - std::string sm_str; - }; - ClientData client_data{this->file_path, std::string(), get_buffer()->get_insert()->get_iter().get_line(), sm[1].str()}; - - // Attempt to find the 100% correct include file first - clang_getInclusions(clang_tu->cx_tu, [](CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data_) { - auto client_data=static_cast(client_data_); - if(client_data->found_include.empty() && include_len>0) { - auto source_location=clang::SourceLocation(inclusion_stack[0]); - if(static_cast(source_location.get_offset().line)-1==client_data->line_nr && - filesystem::get_normal_path(source_location.get_path())==client_data->file_path) - client_data->found_include=clang::to_string(clang_getFileName(included_file)); - } - }, &client_data); - - if(!client_data.found_include.empty()) - return Offset(0, 0, client_data.found_include); - - // Find a matching include file if no include was found previously - clang_getInclusions(clang_tu->cx_tu, [](CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data_) { - auto client_data=static_cast(client_data_); - if(client_data->found_include.empty()) { - for(unsigned c=1;c(source_location.get_offset().line)-1<=client_data->line_nr && - filesystem::get_normal_path(source_location.get_path())==client_data->file_path) { - auto included_file_str=clang::to_string(clang_getFileName(included_file)); - if(included_file_str.size()>=client_data->sm_str.size() && - included_file_str.compare(included_file_str.size()-client_data->sm_str.size(), client_data->sm_str.size(), client_data->sm_str)==0) { - client_data->found_include=included_file_str; - break; - } - } - } - } - }, &client_data); - - if(!client_data.found_include.empty()) - return Offset(0, 0, client_data.found_include); - } + auto location=get_header_location(); + if(location) + return location; } Info::get().print("No declaration found"); return Offset(); }; - is_implementation=[this]() { + is_implementation_location=[this]() { if(!parsed) return false; auto iter=get_buffer()->get_insert()->get_iter(); @@ -1093,7 +1100,7 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file return false; }; - get_implementation_locations=[this](const std::vector &views){ + get_implementation_locations=[this, get_header_location](const std::vector &views){ std::vector locations; if(!parsed) { Info::get().print("Buffer is parsing"); @@ -1163,6 +1170,13 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file return locations; } } + else { + auto location=get_header_location(); + if(location) { + locations.emplace_back(location); + return locations; + } + } Info::get().print("No implementation found"); return locations; };