Browse Source

Ctags cleanup

merge-requests/365/head
eidheim 10 years ago
parent
commit
b6e455fc0a
  1. 2
      README.md
  2. 1
      src/CMakeLists.txt
  3. 84
      src/ctags.cc
  4. 23
      src/ctags.h
  5. 132
      src/window.cc

2
README.md

@ -23,7 +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
* Find symbol through Ctags
* Spell checking depending on file context
* Run shell commands within JuCi++
* Regex search and replace

1
src/CMakeLists.txt

@ -40,6 +40,7 @@ set(global_libraries ${global_libraries}
set(project_files
config.cc
ctags.cc
dialogs.cc
dialogs_unix.cc
directories.cc

84
src/ctags.cc

@ -0,0 +1,84 @@
#include "ctags.h"
#include "config.h"
#include "terminal.h"
//Temporary fix for current Arch Linux boost linking problem
#ifdef __GNUC_PREREQ
#if __GNUC_PREREQ(5,1)
#include <regex>
#define REGEX_NS std
#endif
#endif
#ifndef REGEX_NS
#include <boost/regex.hpp>
#define REGEX_NS boost
#endif
std::unique_ptr<std::stringstream> Ctags::get_result(const boost::filesystem::path &path, std::vector<boost::filesystem::path> exclude_paths) {
std::string exclude;
for(auto &path: exclude_paths) {
if(!path.empty())
exclude+=" --exclude="+path.string();
}
std::stringstream stdin_stream;
//TODO: when debian stable gets newer g++ version that supports move on streams, remove unique_ptr below
std::unique_ptr<std::stringstream> stdout_stream(new std::stringstream());
auto command=Config::get().project.ctags_command+exclude+" --fields=n --sort=foldcase -f- -R *";
Terminal::get().process(stdin_stream, *stdout_stream, command, path);
return stdout_stream;
}
Ctags::Data Ctags::parse_line(const std::string &line) {
Data data;
const static REGEX_NS::regex regex("^([^\t]+)\t([^\t]+)\t(?:/\\^)?([ \t]*)(.+);\"\tline:([0-9]+)$");
REGEX_NS::smatch sm;
if(REGEX_NS::regex_match(line, sm, regex)) {
data.source=sm[4].str();
if(data.source.size()>1 && data.source[data.source.size()-1]=='/' && data.source[data.source.size()-2]!='\\') {
data.source.pop_back();
if(data.source.size()>1 && data.source[data.source.size()-1]=='$' && data.source[data.source.size()-2]!='\\')
data.source.pop_back();
auto symbol=sm[1].str();
data.path=sm[2].str();
data.index=sm[3].str().size();
try {
data.line=std::stoul(sm[5].str())-1;
}
catch(const std::exception&) {
data.line=0;
}
size_t pos=data.source.find(symbol);
if(pos!=std::string::npos)
data.index+=pos;
data.source=Glib::Markup::escape_text(data.source);
pos=-1;
while((pos=data.source.find(symbol, pos+1))!=std::string::npos) {
data.source.insert(pos+symbol.size(), "</b>");
data.source.insert(pos, "<b>");
pos+=7+symbol.size();
}
}
else {
data.path=sm[2].str();
data.index=0;
data.source=sm[1].str();
try {
data.line=std::stoul(sm[3].str())-1;
}
catch(const std::exception&) {
data.line=0;
}
data.source="<b>"+Glib::Markup::escape_text(data.source)+"</b>";
}
}
else {
Terminal::get().print("Warning (ctags): please report to the juCi++ project that the following line was not parsed:\n"+
line+'\n', true);
}
return data;
}

23
src/ctags.h

@ -0,0 +1,23 @@
#ifndef JUCI_CTAGS_H_
#define JUCI_CTAGS_H_
#include <string>
#include <boost/filesystem.hpp>
#include <sstream>
#include <vector>
class Ctags {
public:
class Data {
public:
std::string path;
unsigned long line;
unsigned long index;
std::string source;
};
static std::unique_ptr<std::stringstream> get_result(const boost::filesystem::path &path, std::vector<boost::filesystem::path> exclude_paths);
static Data parse_line(const std::string &line);
};
#endif //JUCI_CTAGS_H_

132
src/window.cc

@ -8,6 +8,7 @@
#include "project.h"
#include "entrybox.h"
#include "info.h"
#include "ctags.h"
namespace sigc {
#ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
@ -453,14 +454,10 @@ void Window::set_menu_actions() {
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;
std::vector<boost::filesystem::path> exclude_paths;
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();
exclude_paths.emplace_back(filesystem::get_relative_path(build->get_default_path(), build->project_path));
exclude_paths.emplace_back(filesystem::get_relative_path(build->get_debug_path(), build->project_path));
}
else {
if(!Directories::get().path.empty())
@ -468,98 +465,43 @@ void Window::set_menu_actions() {
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> >();
auto stream=Ctags::get_result(*run_path, exclude_paths);
stream->seekg(0, std::ios::end);
auto length=stream->tellg();
if(length==0)
return;
stream->seekg(0, std::ios::beg);
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);
}
std::string line;
while(std::getline(*stream, line)) {
auto data=Ctags::parse_line(line);
std::string row=data.path+":"+std::to_string(data.line+1)+": "+data.source;
(*rows)[row]=Source::Offset(data.line, data.index, data.path);
view->selection_dialog->add_row(row);
}
if(rows->size()==0)
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;
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();
};
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->selection_dialog->show();
}
};
view->hide_tooltips();
view->selection_dialog->show();
}
});

Loading…
Cancel
Save