Browse Source

Added Find Symbol through ctags

merge-requests/365/head
eidheim 10 years ago
parent
commit
18994bfa98
  1. 1
      README.md
  2. 12
      docs/install.md
  3. 1
      src/config.cc
  4. 1
      src/config.h
  5. 6
      src/files.h
  6. 25
      src/filesystem.cc
  7. 3
      src/filesystem.h
  8. 7
      src/menu.cc
  9. 19
      src/source_diff.cc
  10. 115
      src/window.cc

1
README.md

@ -23,6 +23,7 @@ towards libclang with speed and ease of use in mind.
* Highlighting of similar types (C++) * Highlighting of similar types (C++)
* Automated documentation search (C++) * Automated documentation search (C++)
* Go to declaration, implementation, methods and usages (C++) * Go to declaration, implementation, methods and usages (C++)
* Find symbol through ctags
* Spell checking depending on file context * Spell checking depending on file context
* Run shell commands within JuCi++ * Run shell commands within JuCi++
* Regex search and replace * Regex search and replace

12
docs/install.md

@ -16,7 +16,7 @@
## Debian testing/Linux Mint/Ubuntu ## Debian testing/Linux Mint/Ubuntu
Install dependencies: Install dependencies:
```sh ```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: Get juCi++ source, compile and install:
@ -32,7 +32,7 @@ sudo make install
## Debian stable/Linux Mint Debian Edition/Raspbian ## Debian stable/Linux Mint Debian Edition/Raspbian
Install dependencies: Install dependencies:
```sh ```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: Get juCi++ source, compile and install:
@ -58,7 +58,7 @@ Alternatively, follow the instructions below.
Install dependencies: Install dependencies:
```sh ```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: Get juCi++ source, compile and install:
@ -74,7 +74,7 @@ sudo make install
## Fedora 23 ## Fedora 23
Install dependencies: Install dependencies:
```sh ```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: Get juCi++ source, compile and install:
@ -120,7 +120,7 @@ sudo make install
Install dependencies: Install dependencies:
```sh ```sh
brew install --with-clang --with-lldb llvm 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: Get juCi++ source, compile and install:
@ -138,7 +138,7 @@ make install
Install dependencies (replace `x86_64` with `i686` for 32-bit MSYS2 installs): Install dependencies (replace `x86_64` with `i686` for 32-bit MSYS2 installs):
```sh ```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). Note that juCi++ must be built and run in a MinGW Shell (for instance MinGW-w64 Win64 Shell).

1
src/config.cc

@ -94,6 +94,7 @@ void Config::retrieve_config() {
project.cmake_command=cfg.get<std::string>("project.cmake_command"); project.cmake_command=cfg.get<std::string>("project.cmake_command");
project.save_on_compile_or_run=cfg.get<bool>("project.save_on_compile_or_run"); project.save_on_compile_or_run=cfg.get<bool>("project.save_on_compile_or_run");
project.clear_terminal_on_compile=cfg.get<bool>("project.clear_terminal_on_compile"); project.clear_terminal_on_compile=cfg.get<bool>("project.clear_terminal_on_compile");
project.ctags_command=cfg.get<std::string>("project.ctags_command");
terminal.history_size=cfg.get<int>("terminal.history_size"); terminal.history_size=cfg.get<int>("terminal.history_size");
terminal.font=cfg.get<std::string>("terminal.font"); terminal.font=cfg.get<std::string>("terminal.font");

1
src/config.h

@ -42,6 +42,7 @@ public:
std::string make_command; std::string make_command;
bool save_on_compile_or_run; bool save_on_compile_or_run;
bool clear_terminal_on_compile; bool clear_terminal_on_compile;
std::string ctags_command;
}; };
class Source { class Source {

6
src/files.h

@ -2,7 +2,7 @@
#define JUCI_FILES_H_ #define JUCI_FILES_H_
#include <string> #include <string>
#define JUCI_VERSION "1.2.0" #define JUCI_VERSION "1.2.0-1"
const std::string default_config_file = R"RAW({ const std::string default_config_file = R"RAW({
"version": ")RAW"+std::string(JUCI_VERSION)+R"RAW(", "version": ")RAW"+std::string(JUCI_VERSION)+R"RAW(",
@ -101,6 +101,7 @@ R"RAW(
"source_indentation_auto_indent_buffer": "<primary><shift>i", "source_indentation_auto_indent_buffer": "<primary><shift>i",
"source_goto_line": "<primary>g", "source_goto_line": "<primary>g",
"source_center_cursor": "<primary>l", "source_center_cursor": "<primary>l",
"source_find_symbol_ctags": "<primary><shift>f",
"source_find_documentation": "<primary><shift>d", "source_find_documentation": "<primary><shift>d",
"source_goto_declaration": "<primary>d", "source_goto_declaration": "<primary>d",
"source_goto_implementation": "<primary>i", "source_goto_implementation": "<primary>i",
@ -156,7 +157,8 @@ R"RAW(
R"RAW( R"RAW(
"make_command": "cmake --build .", "make_command": "cmake --build .",
"save_on_compile_or_run": true, "save_on_compile_or_run": true,
"clear_terminal_on_compile": true "clear_terminal_on_compile": true,
"ctags_command": "ctags"
}, },
"documentation_searches": { "documentation_searches": {
"clang": { "clang": {

25
src/filesystem.cc

@ -198,3 +198,28 @@ boost::filesystem::path filesystem::get_canonical_path(const boost::filesystem::
return path; return path;
return canonical_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())<std::distance(base.begin(), base.end()))
return boost::filesystem::path();
auto base_it=base.begin();
auto path_it=path.begin();
while(path_it!=path.end() && base_it!=base.end()) {
if(*path_it!=*base_it)
return boost::filesystem::path();
++path_it;
++base_it;
}
for(;path_it!=path.end();++path_it)
relative_path/=*path_it;
#endif
return relative_path;
}

3
src/filesystem.h

@ -34,5 +34,8 @@ public:
///Attempts to get canonical path, if not, return the path parameter ///Attempts to get canonical path, if not, return the path parameter
static boost::filesystem::path get_canonical_path(const boost::filesystem::path &path) noexcept; static boost::filesystem::path get_canonical_path(const boost::filesystem::path &path) noexcept;
///Returns empty path on failure
static boost::filesystem::path get_relative_path(const boost::filesystem::path &path, const boost::filesystem::path &base) noexcept;
}; };
#endif // JUCI_FILESYSTEM_H_ #endif // JUCI_FILESYSTEM_H_

7
src/menu.cc

@ -216,6 +216,13 @@ Menu::Menu() {
" </section>" " </section>"
" <section>" " <section>"
" <item>" " <item>"
" <attribute name='label' translatable='yes'>_Find _Symbol (Ctags)</attribute>"
" <attribute name='action'>app.source_find_symbol_ctags</attribute>"
+accels["source_find_symbol_ctags"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Find _Documentation</attribute>" " <attribute name='label' translatable='yes'>_Find _Documentation</attribute>"
" <attribute name='action'>app.source_find_documentation</attribute>" " <attribute name='action'>app.source_find_documentation</attribute>"
+accels["source_find_documentation"]+ //For Ubuntu... +accels["source_find_documentation"]+ //For Ubuntu...

19
src/source_diff.cc

@ -1,6 +1,7 @@
#include "source_diff.h" #include "source_diff.h"
#include "config.h" #include "config.h"
#include "terminal.h" #include "terminal.h"
#include "filesystem.h"
#include <boost/version.hpp> #include <boost/version.hpp>
namespace sigc { namespace sigc {
@ -303,23 +304,9 @@ std::unique_ptr<Git::Repository::Diff> Source::DiffView::get_diff() {
boost::filesystem::path relative_path; boost::filesystem::path relative_path;
{ {
std::unique_lock<std::mutex> lock(file_path_mutex); std::unique_lock<std::mutex> lock(file_path_mutex);
#if BOOST_VERSION>=106000 relative_path=filesystem::get_relative_path(file_path, work_path);
relative_path=boost::filesystem::relative(file_path, work_path); if(relative_path.empty())
#else
if(std::distance(file_path.begin(), file_path.end())<std::distance(work_path.begin(), work_path.end()))
throw std::runtime_error("not a relative path"); throw std::runtime_error("not a relative path");
auto work_path_it=work_path.begin();
auto file_path_it=file_path.begin();
while(file_path_it!=file_path.end() && work_path_it!=work_path.end()) {
if(*file_path_it!=*work_path_it)
throw std::runtime_error("not a relative path");
++file_path_it;
++work_path_it;
}
for(;file_path_it!=file_path.end();++file_path_it)
relative_path/=*file_path_it;
#endif
} }
return std::unique_ptr<Git::Repository::Diff>(new Git::Repository::Diff(repository->get_diff(relative_path))); return std::unique_ptr<Git::Repository::Diff>(new Git::Repository::Diff(repository->get_diff(relative_path)));
} }

115
src/window.cc

@ -449,6 +449,120 @@ void Window::set_menu_actions() {
view->scroll_to_cursor_delayed(view, true, false); 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<boost::filesystem::path>(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<SelectionDialog>(new SelectionDialog(*view, view->get_buffer()->create_mark(dialog_iter), true, true));
auto rows=std::make_shared<std::unordered_map<std::string, Source::Offset> >();
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_index<source_line.size();++line_index) {
if(source_line[line_index]!=' ' && source_line[line_index]!='\t')
break;
}
if(line_index>0)
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(), "</b>");
source_line.insert(bold_pos, "<b>");
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]() { menu.add_action("source_find_documentation", [this]() {
if(auto view=Notebook::get().get_current_view()) { if(auto view=Notebook::get().get_current_view()) {
if(view->get_token_data) { if(view->get_token_data) {
@ -931,6 +1045,7 @@ void Window::activate_menu_items(bool activate) {
auto &menu = Menu::get(); auto &menu = Menu::get();
auto &notebook = Notebook::get(); auto &notebook = Notebook::get();
menu.actions["source_indentation_auto_indent_buffer"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->auto_indent) : false); menu.actions["source_indentation_auto_indent_buffer"]->set_enabled(activate ? static_cast<bool>(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<bool>(notebook.get_current_view()->get_token_data) : false); menu.actions["source_find_documentation"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->get_token_data) : false);
menu.actions["source_goto_declaration"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->get_declaration_location) : false); menu.actions["source_goto_declaration"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->get_declaration_location) : false);
menu.actions["source_goto_implementation"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->get_implementation_location) : false); menu.actions["source_goto_implementation"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->get_implementation_location) : false);

Loading…
Cancel
Save