From 4b56c48e3e696b8f627ed5f35cbf706bd770e2cf Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 14 May 2020 10:12:09 +0200 Subject: [PATCH] Now uses ctags to find methods in C/C++ source files --- src/source.cc | 69 +++++++++++++++++++++++++ src/source_clang.cc | 101 +++++++++++++++++++------------------ src/source_generic.cc | 67 ------------------------ tests/source_clang_test.cc | 6 +++ 4 files changed, 126 insertions(+), 117 deletions(-) diff --git a/src/source.cc b/src/source.cc index 44a8af5..b9dda87 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1,5 +1,6 @@ #include "source.h" #include "config.h" +#include "ctags.h" #include "directories.h" #include "filesystem.h" #include "git.h" @@ -20,6 +21,18 @@ #include #include +#ifdef _WIN32 +#include +inline DWORD get_current_process_id() { + return GetCurrentProcessId(); +} +#else +#include +inline pid_t get_current_process_id() { + return getpid(); +} +#endif + Glib::RefPtr Source::LanguageManager::get_default() { static auto instance = Gsv::LanguageManager::create(); return instance; @@ -297,6 +310,62 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr< } }; } + + get_methods = [this]() { + std::vector> methods; + boost::filesystem::path file_path; + boost::system::error_code ec; + bool use_tmp_file = false; + + if(this->get_buffer()->get_modified()) { + use_tmp_file = true; + file_path = boost::filesystem::temp_directory_path(ec); + if(ec) { + Terminal::get().print("Error: could not get temporary directory folder\n", true); + return methods; + } + file_path /= "jucipp_get_methods" + std::to_string(get_current_process_id()); + boost::filesystem::create_directory(file_path, ec); + if(ec) { + Terminal::get().print("Error: could not create temporary folder\n", true); + return methods; + } + file_path /= this->file_path.filename(); + filesystem::write(file_path, this->get_buffer()->get_text().raw()); + } + else + file_path = this->file_path; + + Ctags ctags(file_path, false, true); + if(use_tmp_file) + boost::filesystem::remove_all(file_path.parent_path(), ec); + if(!ctags) { + Info::get().print("No methods found in current buffer"); + return methods; + } + + std::string line; + while(std::getline(ctags.output, line)) { + auto location = ctags.get_location(line, true); + std::transform(location.kind.begin(), location.kind.end(), location.kind.begin(), + [](char c) { return std::tolower(c); }); + std::vector ignore_kinds = {"variable", "local", "constant", "global", "property", "member", "enum", + "class", "struct", "namespace", + "macro", "param", "header", + "typedef", "using", "alias", + "project", "option"}; + if(std::none_of(ignore_kinds.begin(), ignore_kinds.end(), [&location](const std::string &e) { return location.kind.find(e) != std::string::npos; }) && + location.source.find("") != std::string::npos) + methods.emplace_back(Offset(location.line, location.index), std::to_string(location.line + 1) + ": " + location.source); + } + std::sort(methods.begin(), methods.end(), [](const std::pair &e1, const std::pair &e2) { + return e1.first < e2.first; + }); + + if(methods.empty()) + Info::get().print("No methods found in current buffer"); + return methods; + }; } Gsv::DrawSpacesFlags Source::View::parse_show_whitespace_characters(const std::string &text) { diff --git a/src/source_clang.cc b/src/source_clang.cc index 4cd6eba..67a4a48 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -1577,61 +1577,62 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file return std::string(); }; - get_methods = [this]() { - std::vector> methods; - if(!parsed) { - Info::get().print("Buffer is parsing"); - return methods; - } - clangmm::Offset last_offset{static_cast(-1), static_cast(-1)}; - for(auto &token : *clang_tokens) { - if(token.is_identifier()) { - auto cursor = token.get_cursor(); - auto kind = cursor.get_kind(); - if(kind == clangmm::Cursor::Kind::FunctionDecl || kind == clangmm::Cursor::Kind::CXXMethod || - kind == clangmm::Cursor::Kind::Constructor || kind == clangmm::Cursor::Kind::Destructor || - kind == clangmm::Cursor::Kind::FunctionTemplate || kind == clangmm::Cursor::Kind::ConversionFunction) { - auto offset = cursor.get_source_location().get_offset(); - if(offset == last_offset) - continue; - last_offset = offset; - - std::string prefix; - auto parent = cursor.get_semantic_parent(); - while(parent && parent.get_kind() != clangmm::Cursor::Kind::TranslationUnit) { - prefix.insert(0, parent.get_display_name() + (prefix.empty() ? "" : "::")); - parent = parent.get_semantic_parent(); - } - if(!prefix.empty()) - prefix += ':'; - prefix += std::to_string(offset.line) + ": "; - prefix = Glib::Markup::escape_text(prefix); - - std::string ret; - if(kind != clangmm::Cursor::Kind::Constructor && kind != clangmm::Cursor::Kind::Destructor) { - ret += cursor.get_type().get_result().get_spelling(); - if(!ret.empty() && ret.back() != '&' && ret.back() != '*') - ret += ' '; - } - ret = Glib::Markup::escape_text(ret); + if(language && (language->get_id() == "chdr" || language->get_id() == "cpphdr")) { + get_methods = [this]() { + std::vector> methods; + if(!parsed) { + Info::get().print("Buffer is parsing"); + return methods; + } + clangmm::Offset last_offset{static_cast(-1), static_cast(-1)}; + for(auto &token : *clang_tokens) { + if(token.is_identifier()) { + auto cursor = token.get_cursor(); + auto kind = cursor.get_kind(); + if(kind == clangmm::Cursor::Kind::FunctionDecl || kind == clangmm::Cursor::Kind::CXXMethod || + kind == clangmm::Cursor::Kind::Constructor || kind == clangmm::Cursor::Kind::Destructor || + kind == clangmm::Cursor::Kind::FunctionTemplate || kind == clangmm::Cursor::Kind::ConversionFunction) { + auto offset = cursor.get_source_location().get_offset(); + if(offset == last_offset) + continue; + last_offset = offset; + + std::string scope; + auto parent = cursor.get_semantic_parent(); + while(parent && parent.get_kind() != clangmm::Cursor::Kind::TranslationUnit) { + scope.insert(0, parent.get_display_name() + (scope.empty() ? "" : "::")); + parent = parent.get_semantic_parent(); + } + if(!scope.empty()) + scope += "::"; + scope = Glib::Markup::escape_text(scope); + + std::string ret; + if(kind != clangmm::Cursor::Kind::Constructor && kind != clangmm::Cursor::Kind::Destructor) { + ret += cursor.get_type().get_result().get_spelling(); + if(!ret.empty() && ret.back() != '&' && ret.back() != '*') + ret += ' '; + } + ret = Glib::Markup::escape_text(ret); - auto method = Glib::Markup::escape_text(cursor.get_display_name()); - // Add bold method token - auto end = method.find('('); - if(end == std::string::npos) - continue; - method.insert(end, ""); - method.insert(0, ""); + auto method = Glib::Markup::escape_text(cursor.get_display_name()); + // Add bold method token + auto end = method.find('('); + if(end == std::string::npos) + continue; + method.insert(end, ""); + method.insert(0, ""); - methods.emplace_back(Offset(offset.line - 1, offset.index - 1), prefix + ret + method); + methods.emplace_back(Offset(offset.line - 1, offset.index - 1), std::to_string(offset.line) + ": " + ret + scope + method); + } } } - } - if(methods.empty()) - Info::get().print("No methods found in current buffer"); + if(methods.empty()) + Info::get().print("No methods found in current buffer"); - return methods; - }; + return methods; + }; + } get_token_data = [this]() -> std::vector { clangmm::Cursor cursor; diff --git a/src/source_generic.cc b/src/source_generic.cc index ebe3c6f..47044d7 100644 --- a/src/source_generic.cc +++ b/src/source_generic.cc @@ -1,5 +1,4 @@ #include "source_generic.h" -#include "ctags.h" #include "filesystem.h" #include "info.h" #include "selection_dialog.h" @@ -7,18 +6,6 @@ #include "terminal.h" #include -#ifdef _WIN32 -#include -inline DWORD get_current_process_id() { - return GetCurrentProcessId(); -} -#else -#include -inline pid_t get_current_process_id() { - return getpid(); -} -#endif - Source::GenericView::GenericView(const boost::filesystem::path &file_path, const Glib::RefPtr &language) : BaseView(file_path, language), View(file_path, language, true), autocomplete(this, interactive_completion, last_keyval, false) { spellcheck_all = true; @@ -55,60 +42,6 @@ Source::GenericView::GenericView(const boost::filesystem::path &file_path, const setup_buffer_words(); setup_autocomplete(); - - get_methods = [this]() { - std::vector> methods; - boost::filesystem::path file_path; - boost::system::error_code ec; - bool use_tmp_file = false; - - if(this->get_buffer()->get_modified()) { - use_tmp_file = true; - file_path = boost::filesystem::temp_directory_path(ec); - if(ec) { - Terminal::get().print("Error: could not get temporary directory folder\n", true); - return methods; - } - file_path /= "jucipp_get_methods" + std::to_string(get_current_process_id()); - boost::filesystem::create_directory(file_path, ec); - if(ec) { - Terminal::get().print("Error: could not create temporary folder\n", true); - return methods; - } - file_path /= this->file_path.filename(); - filesystem::write(file_path, this->get_buffer()->get_text().raw()); - } - else - file_path = this->file_path; - - Ctags ctags(file_path, false, true); - if(use_tmp_file) - boost::filesystem::remove_all(file_path.parent_path(), ec); - if(!ctags) { - Info::get().print("No methods found in current buffer"); - return methods; - } - - std::string line; - while(std::getline(ctags.output, line)) { - auto location = ctags.get_location(line, true); - std::transform(location.kind.begin(), location.kind.end(), location.kind.begin(), - [](char c) { return std::tolower(c); }); - std::vector ignore_kinds = {"variable", "local", "constant", "global", "property", "member", "enum", - "macro", "param", "header", - "typedef", "using", "alias", - "project", "option"}; - if(std::none_of(ignore_kinds.begin(), ignore_kinds.end(), [&location](const std::string &e) { return location.kind.find(e) != std::string::npos; })) - methods.emplace_back(Offset(location.line, location.index), location.source); - } - std::sort(methods.begin(), methods.end(), [](const std::pair &e1, const std::pair &e2) { - return e1.first < e2.first; - }); - - if(methods.empty()) - Info::get().print("No methods found in current buffer"); - return methods; - }; } Source::GenericView::~GenericView() { diff --git a/tests/source_clang_test.cc b/tests/source_clang_test.cc index 3b66842..af941b6 100644 --- a/tests/source_clang_test.cc +++ b/tests/source_clang_test.cc @@ -23,6 +23,12 @@ int main() { auto app = Gtk::Application::create(); Gsv::init(); +#ifdef JUCI_USE_UCTAGS + Config::get().project.ctags_command = "uctags"; +#else + Config::get().project.ctags_command = "ctags"; +#endif + #ifdef _WIN32 g_assert_cmpstr(std::getenv("MSYSTEM_PREFIX"), !=, nullptr); #endif