From 9ac4e65ddd79092188bfd8b8546a5a82f7159da4 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 16 Apr 2020 08:45:43 +0200 Subject: [PATCH] Unescape Ctags source, and slight optimization of Ctag functions --- src/ctags.cc | 50 +++++++++++++++++++++++++++++----------- src/ctags.h | 4 ++-- src/source_generic.cc | 4 ++-- tests/ctags_grep_test.cc | 34 ++++++++++++++++++++++++--- 4 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/ctags.cc b/src/ctags.cc index cf63715..5a55fe4 100644 --- a/src/ctags.cc +++ b/src/ctags.cc @@ -8,9 +8,13 @@ #include #include -std::pair> Ctags::get_result(const boost::filesystem::path &path, bool enable_kinds) { +std::pair> Ctags::get_result(const boost::filesystem::path &path, bool enable_scope, bool enable_kind) { boost::filesystem::path run_path; - auto fields = std::string(" --fields=ns") + (enable_kinds ? "K" : ""); + std::string fields(" --fields=n"); + if(enable_scope) + fields += 's'; + if(enable_kind) + fields += 'K'; std::string command; boost::system::error_code ec; if(boost::filesystem::is_directory(path, ec)) { @@ -37,7 +41,7 @@ std::pair> Ctags::ge return {run_path, std::move(stdout_stream)}; } -Ctags::Location Ctags::get_location(const std::string &line_, bool add_markup, bool kinds_enabled) { +Ctags::Location Ctags::get_location(const std::string &line_, bool add_markup, bool scope_enabled, bool kind_enabled) { Location location; #ifdef _WIN32 @@ -86,10 +90,22 @@ Ctags::Location Ctags::get_location(const std::string &line_, bool add_markup, b std::cerr << "Warning (ctags): could not parse line: " << line << std::endl; return location; } - location.source = line.substr(source_start, source_end - source_start - (line[source_end - 1] == '$' ? 1 : 0)); + + // Unescape source + auto end = source_end - (line[source_end - 1] == '$' ? 1 : 0); + location.source.reserve(end - source_start); + bool escaped = false; + for(auto i = source_start; i < end; ++i) { + if(!escaped && line[i] == '\\') { + escaped = true; + continue; + } + escaped = false; + location.source += line[i]; + } size_t line_start; - if(kinds_enabled) { + if(kind_enabled) { auto kind_start = source_end + 4; if(kind_start >= line.size()) { std::cerr << "Warning (ctags): could not parse line: " << line << std::endl; @@ -119,26 +135,32 @@ Ctags::Location Ctags::get_location(const std::string &line_, bool add_markup, b location.line = 0; } - if(line_end != std::string::npos && line_end + 1 < line.size()) { + if(scope_enabled && line_end != std::string::npos && line_end + 1 < line.size()) { auto scope_start = line.find(':', line_end + 1); if(scope_start != std::string::npos && scope_start + 1 < line.size()) location.scope = line.substr(scope_start + 1); } - auto pos = location.source.find(location.symbol); - if(pos != std::string::npos) - location.index += pos; - if(add_markup) { location.source = Glib::Markup::escape_text(location.source); std::string symbol = Glib::Markup::escape_text(location.symbol); - pos = -1; - while((pos = location.source.find(symbol, pos + 1)) != std::string::npos) { + size_t pos = 0; + bool first = true; + while((pos = location.source.find(symbol, pos)) != std::string::npos) { + if(first) { + location.index += pos; + first = false; + } location.source.insert(pos + symbol.size(), ""); location.source.insert(pos, ""); pos += 7 + symbol.size(); } } + else { + auto pos = location.source.find(location.symbol); + if(pos != std::string::npos) + location.index += pos; + } return location; } @@ -166,7 +188,7 @@ std::vector Ctags::get_type_parts(const std::string &type) { } std::vector Ctags::get_locations(const boost::filesystem::path &path, const std::string &name, const std::string &type) { - auto result = get_result(path); + auto result = get_result(path, true); result.second->seekg(0, std::ios::end); if(result.second->tellg() == 0) return std::vector(); @@ -194,7 +216,7 @@ std::vector Ctags::get_locations(const boost::filesystem::path while(std::getline(*result.second, line)) { if(line.size() > 2048) continue; - auto location = Ctags::get_location(line, false); + auto location = Ctags::get_location(line, false, true); if(!location.scope.empty()) { if(location.scope + "::" + location.symbol != name) continue; diff --git a/src/ctags.h b/src/ctags.h index f31b97f..3f08b8d 100644 --- a/src/ctags.h +++ b/src/ctags.h @@ -18,9 +18,9 @@ public: operator bool() const { return !file_path.empty(); } }; - static std::pair> get_result(const boost::filesystem::path &path, bool enable_kinds = false); + static std::pair> get_result(const boost::filesystem::path &path, bool enable_scope = false, bool enable_kind = false); - static Location get_location(const std::string &line, bool add_markup, bool kinds_enabled = false); + static Location get_location(const std::string &line, bool add_markup, bool scope_enabled = false, bool kind_enabled = false); static std::vector get_locations(const boost::filesystem::path &path, const std::string &name, const std::string &type); diff --git a/src/source_generic.cc b/src/source_generic.cc index 127b98e..c427656 100644 --- a/src/source_generic.cc +++ b/src/source_generic.cc @@ -82,7 +82,7 @@ Source::GenericView::GenericView(const boost::filesystem::path &file_path, const else file_path = this->file_path; - auto pair = Ctags::get_result(file_path, true); + auto pair = Ctags::get_result(file_path, false, true); if(use_tmp_file) boost::filesystem::remove_all(file_path.parent_path(), ec); auto path = std::move(pair.first); @@ -97,7 +97,7 @@ Source::GenericView::GenericView(const boost::filesystem::path &file_path, const std::string line; while(std::getline(*stream, line)) { - auto location = Ctags::get_location(line, true, true); + auto location = Ctags::get_location(line, true, false, 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", diff --git a/tests/ctags_grep_test.cc b/tests/ctags_grep_test.cc index 737072a..e8eb8eb 100644 --- a/tests/ctags_grep_test.cc +++ b/tests/ctags_grep_test.cc @@ -7,6 +7,11 @@ void ctags_grep_test_function() { } +class Test { + void ctags_grep_test_function2() { + } +}; + int main() { auto app = Gtk::Application::create(); Config::get().project.ctags_command = "ctags"; @@ -50,14 +55,14 @@ int main() { g_assert(found == true); } { - auto result = Ctags::get_result(tests_path, true); + auto result = Ctags::get_result(tests_path, false, true); g_assert(result.first == tests_path.parent_path()); bool found = false; std::string line; while(std::getline(*result.second, line)) { if(line.find("ctags_grep_test_function") != std::string::npos) { { - auto location = Ctags::get_location(line, false, true); + auto location = Ctags::get_location(line, false, false, true); g_assert(location.source == "void ctags_grep_test_function() {"); g_assert(result.first / location.file_path == tests_path / "ctags_grep_test.cc"); g_assert_cmpint(location.line, ==, 6); @@ -67,7 +72,7 @@ int main() { g_assert(location.kind == "function"); } { - auto location = Ctags::get_location(line, true, true); + auto location = Ctags::get_location(line, true, false, true); g_assert(location.source == "void ctags_grep_test_function() {"); g_assert(result.first / location.file_path == tests_path / "ctags_grep_test.cc"); g_assert_cmpint(location.line, ==, 6); @@ -82,6 +87,29 @@ int main() { } g_assert(found == true); } + { + auto result = Ctags::get_result(tests_path, true); + g_assert(result.first == tests_path.parent_path()); + bool found = false; + std::string line; + while(std::getline(*result.second, line)) { + if(line.find("ctags_grep_test_function2") != std::string::npos) { + { + auto location = Ctags::get_location(line, false, true); + g_assert(location.source == "void ctags_grep_test_function2() {"); + g_assert(result.first / location.file_path == tests_path / "ctags_grep_test.cc"); + g_assert_cmpint(location.line, ==, 10); + g_assert_cmpint(location.index, ==, 7); + g_assert(location.symbol == "ctags_grep_test_function2"); + g_assert(location.scope == "Test"); + g_assert(location.kind.empty()); + } + found = true; + break; + } + } + g_assert(found == true); + } // Grep tests {