From 18994bfa98029b3d771de7e7cc19992ea23c39b8 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 2 Jul 2016 10:44:14 +0200 Subject: [PATCH] Added Find Symbol through ctags --- README.md | 1 + docs/install.md | 12 ++--- src/config.cc | 1 + src/config.h | 1 + src/files.h | 6 ++- src/filesystem.cc | 25 ++++++++++ src/filesystem.h | 3 ++ src/menu.cc | 7 +++ src/source_diff.cc | 19 ++------ src/window.cc | 115 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 166 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index e704961..b482dbb 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ towards libclang with speed and ease of use in mind. * Highlighting of similar types (C++) * Automated documentation search (C++) * Go to declaration, implementation, methods and usages (C++) +* Find symbol through ctags * Spell checking depending on file context * Run shell commands within JuCi++ * Regex search and replace diff --git a/docs/install.md b/docs/install.md index 5aa5d1b..17c9231 100644 --- a/docs/install.md +++ b/docs/install.md @@ -16,7 +16,7 @@ ## Debian testing/Linux Mint/Ubuntu Install dependencies: ```sh -sudo apt-get install git cmake make g++ libclang-3.6-dev liblldb-3.6-dev clang-format-3.6 pkg-config libboost-filesystem-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev libgit2-dev +sudo apt-get install git cmake make g++ libclang-3.6-dev liblldb-3.6-dev clang-format-3.6 pkg-config libboost-filesystem-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev libgit2-dev exuberant-ctags ``` Get juCi++ source, compile and install: @@ -32,7 +32,7 @@ sudo make install ## Debian stable/Linux Mint Debian Edition/Raspbian Install dependencies: ```sh -sudo apt-get install git cmake make g++ libclang-3.5-dev liblldb-3.5-dev clang-format-3.5 pkg-config libboost-filesystem-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev libgit2-dev +sudo apt-get install git cmake make g++ libclang-3.5-dev liblldb-3.5-dev clang-format-3.5 pkg-config libboost-filesystem-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev libgit2-dev exuberant-ctags ``` Get juCi++ source, compile and install: @@ -58,7 +58,7 @@ Alternatively, follow the instructions below. Install dependencies: ```sh -sudo pacman -S git cmake pkg-config make clang lldb gtksourceviewmm boost aspell aspell-en libgit2 +sudo pacman -S git cmake pkg-config make clang lldb gtksourceviewmm boost aspell aspell-en libgit2 ctags ``` Get juCi++ source, compile and install: @@ -74,7 +74,7 @@ sudo make install ## Fedora 23 Install dependencies: ```sh -sudo dnf install git cmake make gcc-c++ clang-devel clang lldb-devel boost-devel gtksourceviewmm3-devel gtkmm30-devel aspell-devel aspell-en libgit2-devel +sudo dnf install git cmake make gcc-c++ clang-devel clang lldb-devel boost-devel gtksourceviewmm3-devel gtkmm30-devel aspell-devel aspell-en libgit2-devel ctags ``` Get juCi++ source, compile and install: @@ -120,7 +120,7 @@ sudo make install Install dependencies: ```sh brew install --with-clang --with-lldb llvm -brew install cmake pkg-config boost homebrew/x11/gtksourceviewmm3 aspell clang-format libgit2 +brew install cmake pkg-config boost homebrew/x11/gtksourceviewmm3 aspell clang-format libgit2 ctags ``` Get juCi++ source, compile and install: @@ -138,7 +138,7 @@ make install Install dependencies (replace `x86_64` with `i686` for 32-bit MSYS2 installs): ```sh -pacman -S git mingw-w64-x86_64-cmake make mingw-w64-x86_64-toolchain mingw-w64-x86_64-clang mingw-w64-x86_64-gtkmm3 mingw-w64-x86_64-gtksourceviewmm3 mingw-w64-x86_64-boost mingw-w64-x86_64-aspell mingw-w64-x86_64-aspell-en mingw-w64-x86_64-libgit2 +pacman -S git mingw-w64-x86_64-cmake make mingw-w64-x86_64-toolchain mingw-w64-x86_64-clang mingw-w64-x86_64-gtkmm3 mingw-w64-x86_64-gtksourceviewmm3 mingw-w64-x86_64-boost mingw-w64-x86_64-aspell mingw-w64-x86_64-aspell-en mingw-w64-x86_64-libgit2 mingw-w64-x86_64-universal-ctags-git ``` Note that juCi++ must be built and run in a MinGW Shell (for instance MinGW-w64 Win64 Shell). diff --git a/src/config.cc b/src/config.cc index de29e32..2941f38 100644 --- a/src/config.cc +++ b/src/config.cc @@ -94,6 +94,7 @@ void Config::retrieve_config() { project.cmake_command=cfg.get("project.cmake_command"); project.save_on_compile_or_run=cfg.get("project.save_on_compile_or_run"); project.clear_terminal_on_compile=cfg.get("project.clear_terminal_on_compile"); + project.ctags_command=cfg.get("project.ctags_command"); terminal.history_size=cfg.get("terminal.history_size"); terminal.font=cfg.get("terminal.font"); diff --git a/src/config.h b/src/config.h index fadd8b7..6d1c0d4 100644 --- a/src/config.h +++ b/src/config.h @@ -42,6 +42,7 @@ public: std::string make_command; bool save_on_compile_or_run; bool clear_terminal_on_compile; + std::string ctags_command; }; class Source { diff --git a/src/files.h b/src/files.h index 267bb8c..53d73fd 100644 --- a/src/files.h +++ b/src/files.h @@ -2,7 +2,7 @@ #define JUCI_FILES_H_ #include -#define JUCI_VERSION "1.2.0" +#define JUCI_VERSION "1.2.0-1" const std::string default_config_file = R"RAW({ "version": ")RAW"+std::string(JUCI_VERSION)+R"RAW(", @@ -101,6 +101,7 @@ R"RAW( "source_indentation_auto_indent_buffer": "i", "source_goto_line": "g", "source_center_cursor": "l", + "source_find_symbol_ctags": "f", "source_find_documentation": "d", "source_goto_declaration": "d", "source_goto_implementation": "i", @@ -156,7 +157,8 @@ R"RAW( R"RAW( "make_command": "cmake --build .", "save_on_compile_or_run": true, - "clear_terminal_on_compile": true + "clear_terminal_on_compile": true, + "ctags_command": "ctags" }, "documentation_searches": { "clang": { diff --git a/src/filesystem.cc b/src/filesystem.cc index cc6f353..ae41b82 100644 --- a/src/filesystem.cc +++ b/src/filesystem.cc @@ -198,3 +198,28 @@ boost::filesystem::path filesystem::get_canonical_path(const boost::filesystem:: return path; return canonical_path; } + +boost::filesystem::path filesystem::get_relative_path(const boost::filesystem::path &path, const boost::filesystem::path &base) noexcept { + boost::filesystem::path relative_path; + boost::system::error_code ec; +#if BOOST_VERSION>=106000 + relative_path=boost::filesystem::relative(path, base, ec); + if(ec) + return boost::filesystem::path(); +#else + if(std::distance(path.begin(), path.end())" "
" " " + " _Find _Symbol (Ctags)" + " app.source_find_symbol_ctags" + +accels["source_find_symbol_ctags"]+ //For Ubuntu... + " " + "
" + "
" + " " " _Find _Documentation" " app.source_find_documentation" +accels["source_find_documentation"]+ //For Ubuntu... diff --git a/src/source_diff.cc b/src/source_diff.cc index 87f36b7..2c62ea6 100644 --- a/src/source_diff.cc +++ b/src/source_diff.cc @@ -1,6 +1,7 @@ #include "source_diff.h" #include "config.h" #include "terminal.h" +#include "filesystem.h" #include namespace sigc { @@ -303,23 +304,9 @@ std::unique_ptr Source::DiffView::get_diff() { boost::filesystem::path relative_path; { std::unique_lock lock(file_path_mutex); -#if BOOST_VERSION>=106000 - relative_path=boost::filesystem::relative(file_path, work_path); -#else - if(std::distance(file_path.begin(), file_path.end())(new Git::Repository::Diff(repository->get_diff(relative_path))); } diff --git a/src/window.cc b/src/window.cc index b2aeffb..9a64f49 100644 --- a/src/window.cc +++ b/src/window.cc @@ -449,6 +449,120 @@ void Window::set_menu_actions() { view->scroll_to_cursor_delayed(view, true, false); }); + menu.add_action("source_find_symbol_ctags", [this]() { + if(auto view=Notebook::get().get_current_view()) { + auto build=Project::Build::create(view->file_path); + auto run_path=std::make_shared(build->project_path); + std::string exclude; + if(!run_path->empty()) { + auto relative_path=filesystem::get_relative_path(build->get_default_path(), build->project_path); + if(!relative_path.empty()) + exclude+=" --exclude="+relative_path.string(); + relative_path=filesystem::get_relative_path(build->get_debug_path(), build->project_path); + if(!relative_path.empty()) + exclude+=" --exclude="+relative_path.string(); + } + else { + if(!Directories::get().path.empty()) + *run_path=Directories::get().path; + else + *run_path=view->file_path.parent_path(); + } + std::stringstream stdin_stream, stdout_stream; + auto command=Config::get().project.ctags_command+exclude+" --fields=n --sort=foldcase -f- -R *"; + auto exit_status=Terminal::get().process(stdin_stream, stdout_stream, command, *run_path); + if(exit_status==0) { + auto dialog_iter=view->get_iter_for_dialog(); + view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, view->get_buffer()->create_mark(dialog_iter), true, true)); + auto rows=std::make_shared >(); + + std::string line; + while(std::getline(stdout_stream, line)) { + std::string symbol, file, source_line; + unsigned long line_nr; + size_t last_pos=-1, pos; + + pos=line.find("\t", last_pos+1); + if(pos==std::string::npos || last_pos+1>=line.size()) { + Terminal::get().print("Warning (ctags): failed to parse symbol\n", true); + continue; + } + symbol=line.substr(last_pos+1, pos-last_pos-1); + last_pos=pos; + + pos=line.find("\t", last_pos+1); + if(pos==std::string::npos || last_pos+1>=line.size()) { + Terminal::get().print("Warning (ctags): failed to parse file\n", true); + continue; + } + file=line.substr(last_pos+1, pos-last_pos-1); + last_pos=pos; + + pos=line.find("/;\"\t", last_pos+1); + if(pos==std::string::npos || last_pos+3>=line.size()) { + //Skipping defines + continue; + } + pos+=3; + source_line=line.substr(last_pos+3, pos-last_pos-7); + size_t line_index=0; + for(;line_index0) + source_line=source_line.substr(line_index); + size_t line_index_add=source_line.find(symbol); + if(line_index_add!=std::string::npos) + line_index+=line_index_add; + + source_line=Glib::Markup::escape_text(source_line); + size_t bold_pos=-1; + while((bold_pos=source_line.find(symbol, bold_pos+1))!=std::string::npos) { + source_line.insert(bold_pos+symbol.size(), ""); + source_line.insert(bold_pos, ""); + bold_pos+=7+symbol.size(); + } + last_pos=pos; + + if(last_pos+6>=line.size()) { + Terminal::get().print("Warning (ctags): failed to parse line number\n", true); + continue; + } + try { + line_nr=std::stoul(line.substr(last_pos+6, line.size()-last_pos-6)); + } + catch(const std::exception &) { + Terminal::get().print("Warning (ctags): failed to parse line number\n", true); + continue; + } + + std::string row=file+":"+std::to_string(line_nr)+": "+source_line; + (*rows)[row]=Source::Offset(line_nr-1, line_index, file); + view->selection_dialog->add_row(row); + } + + if(rows->size()==0) + return; + view->selection_dialog->on_select=[this, rows, run_path](const std::string &selected, bool hide_window) { + auto offset=rows->at(selected); + boost::filesystem::path declaration_file; + boost::system::error_code ec; + declaration_file=boost::filesystem::canonical(*run_path/offset.file_path, ec); + if(ec) + return; + Notebook::get().open(declaration_file); + auto view=Notebook::get().get_current_view(); + view->place_cursor_at_line_index(offset.line, offset.index); + view->scroll_to_cursor_delayed(view, true, false); + view->hide_tooltips(); + }; + view->hide_tooltips(); + view->selection_dialog->show(); + } + } + }); + menu.add_action("source_find_documentation", [this]() { if(auto view=Notebook::get().get_current_view()) { if(view->get_token_data) { @@ -931,6 +1045,7 @@ void Window::activate_menu_items(bool activate) { auto &menu = Menu::get(); auto ¬ebook = Notebook::get(); menu.actions["source_indentation_auto_indent_buffer"]->set_enabled(activate ? static_cast(notebook.get_current_view()->auto_indent) : false); + menu.actions["source_find_symbol_ctags"]->set_enabled(activate); menu.actions["source_find_documentation"]->set_enabled(activate ? static_cast(notebook.get_current_view()->get_token_data) : false); menu.actions["source_goto_declaration"]->set_enabled(activate ? static_cast(notebook.get_current_view()->get_declaration_location) : false); menu.actions["source_goto_implementation"]->set_enabled(activate ? static_cast(notebook.get_current_view()->get_implementation_location) : false);