Browse Source

Merge with master

merge-requests/365/head
Jørgen Lien Sellæg 10 years ago
parent
commit
837b1abe43
  1. 1
      CMakeLists.txt
  2. 8
      docs/install.md
  3. 4
      share/juci.desktop
  4. 2
      src/CMakeLists.txt
  5. 20
      src/cmake.cc
  6. 13
      src/config.cc
  7. 8
      src/config.h
  8. 4
      src/dialogs.cc
  9. 5
      src/dialogs_win.cc
  10. 36
      src/directories.cc
  11. 1
      src/directories.h
  12. 9
      src/files.h
  13. 5
      src/menu.cc
  14. 57
      src/selectiondialog.cc
  15. 25
      src/selectiondialog.h
  16. 17
      src/source.cc
  17. 15
      src/source.h
  18. 129
      src/source_clang.cc
  19. 9
      src/source_clang.h
  20. 82
      src/window.cc

1
CMakeLists.txt

@ -11,5 +11,6 @@ add_subdirectory("src")
find_program(XDG_DESKTOP_MENU_EXECUTABLE xdg-desktop-menu)
if(XDG_DESKTOP_MENU_EXECUTABLE)
file(MAKE_DIRECTORY "/usr/share/desktop-directories") #Workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=730621
install(CODE "execute_process(COMMAND ${XDG_DESKTOP_MENU_EXECUTABLE} install --novendor share/juci.desktop)")
endif()

8
docs/install.md

@ -3,7 +3,7 @@
## Debian/Ubuntu 15
Install dependencies:
```sh
sudo apt-get install git cmake make g++ libclang-dev pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev
sudo apt-get install git cmake make g++ libclang-dev pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev
sudo apt-get install clang-format-3.6 || sudo apt-get install clang-format-3.5
```
@ -19,11 +19,7 @@ sudo make install
## Ubuntu 14/Linux Mint 17
Install dependencies:
```sh
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install g++-4.9
sudo apt-get remove g++-4.8
sudo apt-get install git cmake make g++ libclang-3.6-dev clang-format-3.6 pkg-config libboost-system1.55-dev libboost-thread1.55-dev libboost-filesystem1.55-dev libboost-log1.55-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev
sudo apt-get install git cmake make g++ libclang-3.6-dev clang-format-3.6 pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev
```
Get juCi++ source, compile and install:

4
share/juci.desktop

@ -1,8 +1,10 @@
[Desktop Entry]
Version=1.0
Name=juCi++
Comment=A lightweight IDE
Exec=juci %F
Terminal=false
Type=Application
StartupNotify=true
MimeType=text/plain;
MimeType=text/plain;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-cmake;
Categories=Utility;Development;TextEditor;

2
src/CMakeLists.txt

@ -32,7 +32,7 @@ find_package(LibClang REQUIRED)
#find_package(PythonLibs 2.7)
#find_package(Boost 1.55 COMPONENTS python thread log system filesystem REQUIRED)
find_package(Boost 1.55 COMPONENTS thread log system filesystem REQUIRED)
find_package(Boost 1.54 COMPONENTS thread log system filesystem regex REQUIRED)
pkg_check_modules(GTKMM gtkmm-3.0 REQUIRED) # The name GTKMM is set here for the variables abouve

20
src/cmake.cc

@ -1,7 +1,7 @@
#include "cmake.h"
#include "singletons.h"
#include "filesystem.h"
#include <regex>
#include <boost/regex.hpp>
#include "dialogs.h"
#include <iostream> //TODO: remove
@ -10,9 +10,9 @@ using namespace std; //TODO: remove
CMake::CMake(const boost::filesystem::path &path) {
const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) {
for(auto &line: filesystem::read_lines(cmake_path)) {
const std::regex project_regex("^ *project *\\(.*$");
std::smatch sm;
if(std::regex_match(line, sm, project_regex)) {
const boost::regex project_regex("^ *project *\\(.*$");
boost::smatch sm;
if(boost::regex_match(line, sm, project_regex)) {
return true;
}
}
@ -142,9 +142,9 @@ void CMake::find_variables() {
end_line=file.size();
if(end_line>start_line) {
auto line=file.substr(start_line, end_line-start_line);
const std::regex set_regex("^ *set *\\( *([A-Za-z_][A-Za-z_0-9]*) +(.*)\\) *$");
std::smatch sm;
if(std::regex_match(line, sm, set_regex)) {
const boost::regex set_regex("^ *set *\\( *([A-Za-z_][A-Za-z_0-9]*) +(.*)\\) *$");
boost::smatch sm;
if(boost::regex_match(line, sm, set_regex)) {
auto data=sm[2].str();
while(data.size()>0 && data.back()==' ')
data.pop_back();
@ -264,9 +264,9 @@ std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > CMak
end_line=file.size();
if(end_line>start_line) {
auto line=file.substr(start_line, end_line-start_line);
const std::regex function_regex("^ *"+name+" *\\( *(.*)\\) *$");
std::smatch sm;
if(std::regex_match(line, sm, function_regex)) {
const boost::regex function_regex("^ *"+name+" *\\( *(.*)\\) *$");
boost::smatch sm;
if(boost::regex_match(line, sm, function_regex)) {
auto data=sm[1].str();
while(data.size()>0 && data.back()==' ')
data.pop_back();

13
src/config.cc

@ -81,7 +81,6 @@ void Config::retrieve_config() {
menu.keys[i.first] = i.second.get_value<std::string>();
}
get_source();
get_directory_filter();
window.theme_name=cfg.get<std::string>("gtk_theme.name");
window.theme_variant=cfg.get<std::string>("gtk_theme.variant");
@ -188,15 +187,3 @@ void Config::get_source() {
}
}
}
void Config::get_directory_filter() {
boost::property_tree::ptree dir_json = cfg.get_child("directoryfilter");
boost::property_tree::ptree ignore_json = dir_json.get_child("ignore");
boost::property_tree::ptree except_json = dir_json.get_child("exceptions");
directories.exceptions.clear();
directories.ignored.clear();
for ( auto &i : except_json )
directories.exceptions.emplace_back(i.second.get_value<std::string>());
for ( auto &i : ignore_json )
directories.ignored.emplace_back(i.second.get_value<std::string>());
}

8
src/config.h

@ -31,12 +31,6 @@ public:
int history_size;
};
class Directories {
public:
std::vector<std::string> ignored;
std::vector<std::string> exceptions;
};
class Source {
public:
class DocumentationSearch {
@ -72,7 +66,6 @@ public:
Menu menu;
Window window;
Terminal terminal;
Directories directories;
Source source;
const boost::filesystem::path& juci_home_path() const { return home; }
@ -83,7 +76,6 @@ private:
bool check_config_file(const boost::property_tree::ptree &default_cfg, std::string parent_path="");
void update_config_file();
void get_source();
void get_directory_filter();
boost::property_tree::ptree cfg;
boost::filesystem::path home;

4
src/dialogs.cc

@ -42,8 +42,10 @@ std::string Dialog::gtk_dialog(const std::string &title,
dialog.set_transient_for(*application->window);
auto current_path=application->window->notebook.get_current_folder();
boost::system::error_code ec;
if(current_path.empty())
current_path=boost::filesystem::current_path();
current_path=boost::filesystem::current_path(ec);
if(!ec)
gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), current_path.string().c_str());
if (!file_name.empty())

5
src/dialogs_win.cc

@ -99,8 +99,11 @@ private:
auto application=Glib::RefPtr<Application>::cast_static(gio_application);
auto current_path=application->window->notebook.get_current_folder();
boost::system::error_code ec;
if(current_path.empty())
current_path=boost::filesystem::current_path();
current_path=boost::filesystem::current_path(ec);
if(ec)
return false;
std::wstring path=current_path.native();
size_t pos=0;

36
src/directories.cc

@ -90,9 +90,10 @@ Directories::Directories() : stop_update_thread(false) {
update_mutex.lock();
if(update_paths.size()==0) {
for(auto it=last_write_times.begin();it!=last_write_times.end();) {
try {
if(boost::filesystem::exists(it->first)) { //Added for older boost versions (no exception thrown)
if(it->second.second<boost::filesystem::last_write_time(it->first)) {
boost::system::error_code ec;
auto last_write_time=boost::filesystem::last_write_time(it->first, ec);
if(!ec) {
if(it->second.second<last_write_time) {
update_paths.emplace_back(it->first);
}
it++;
@ -100,10 +101,6 @@ Directories::Directories() : stop_update_thread(false) {
else
it=last_write_times.erase(it);
}
catch(const std::exception &e) {
it=last_write_times.erase(it);
}
}
if(update_paths.size()>0)
update_dispatcher();
}
@ -197,23 +194,12 @@ void Directories::select(const boost::filesystem::path &path) {
JDEBUG("end");
}
bool Directories::ignored(std::string path) {
std::transform(path.begin(), path.end(), path.begin(), ::tolower);
for(std::string &i : Singleton::config->directories.exceptions) {
if(i == path)
return false;
}
for(auto &i : Singleton::config->directories.ignored) {
if(path.find(i, 0) != std::string::npos)
return true;
}
return false;
}
void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) {
last_write_times[dir_path.string()]={parent, boost::filesystem::last_write_time(dir_path)};
boost::system::error_code ec;
auto last_write_time=boost::filesystem::last_write_time(dir_path, ec);
if(ec)
return;
last_write_times[dir_path.string()]={parent, last_write_time};
std::unique_ptr<Gtk::TreeNodeChildren> children; //Gtk::TreeNodeChildren is missing default constructor...
if(parent)
children=std::unique_ptr<Gtk::TreeNodeChildren>(new Gtk::TreeNodeChildren(parent.children()));
@ -227,7 +213,6 @@ void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::T
boost::filesystem::directory_iterator end_it;
for(boost::filesystem::directory_iterator it(dir_path);it!=end_it;it++) {
auto filename=it->path().filename().string();
if (!ignored(filename)) {
bool already_added=false;
if(*children) {
for(auto &child: *children) {
@ -243,7 +228,7 @@ void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::T
not_deleted.emplace(filename);
child->set_value(column_record.name, filename);
child->set_value(column_record.path, it->path().string());
if (boost::filesystem::is_directory(*it)) {
if (boost::filesystem::is_directory(it->path())) {
child->set_value(column_record.id, "a"+filename);
auto grandchild=tree_store->append(child->children());
grandchild->set_value(column_record.name, std::string("(empty)"));
@ -263,7 +248,6 @@ void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::T
}
}
}
}
if(*children) {
for(auto it=children->begin();it!=children->end();) {
if(not_deleted.count(it->get_value(column_record.name))==0) {

1
src/directories.h

@ -38,7 +38,6 @@ public:
private:
void add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &row);
bool ignored(std::string path);
Gtk::TreeView tree_view;
Glib::RefPtr<Gtk::TreeStore> tree_store;
ColumnRecord column_record;

9
src/files.h

@ -1,6 +1,6 @@
#include <string>
#define JUCI_VERSION "0.9.5"
#define JUCI_VERSION "0.9.6"
const std::string configjson =
"{\n"
@ -85,6 +85,7 @@ const std::string configjson =
" \"source_center_cursor\": \"<primary>l\",\n"
" \"source_find_documentation\": \"<primary><shift>d\",\n"
" \"source_goto_declaration\": \"<primary>d\",\n"
" \"source_goto_usage\": \"<primary>u\",\n"
" \"source_goto_method\": \"<primary>m\",\n"
" \"source_rename\": \"<primary>r\",\n"
" \"source_goto_next_diagnostic\": \"<primary>e\",\n"
@ -117,12 +118,6 @@ const std::string configjson =
" \"@any\": \"https://www.google.com/search?btnI&q=\"\n"
" }\n"
" }\n"
" },\n"
" \"directoryfilter\": {\n"
" \"ignore\": [\n"
" ],\n"
" \"exceptions\": [\n"
" ]\n"
" }\n"
"}\n";

5
src/menu.cc

@ -211,6 +211,11 @@ void Menu::init() {
+accels["source_goto_declaration"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Go to Usage</attribute>"
" <attribute name='action'>app.source_goto_usage</attribute>"
+accels["source_goto_usage"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Go to Method</attribute>"
" <attribute name='action'>app.source_goto_method</attribute>"
+accels["source_goto_method"]+ //For Ubuntu...

57
src/selectiondialog.cc

@ -15,8 +15,36 @@ namespace sigc {
#endif
}
SelectionDialogBase::SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry): text_view(text_view),
start_mark(start_mark), show_search_entry(show_search_entry), list_view_text(1, false, Gtk::SelectionMode::SELECTION_BROWSE) {
ListViewText::ListViewText(bool use_markup) : Gtk::TreeView(), use_markup(use_markup) {
list_store = Gtk::ListStore::create(column_record);
set_model(list_store);
append_column("", cell_renderer);
if(use_markup)
get_column(0)->add_attribute(cell_renderer.property_markup(), column_record.text);
else
get_column(0)->add_attribute(cell_renderer.property_text(), column_record.text);
get_selection()->set_mode(Gtk::SelectionMode::SELECTION_BROWSE);
set_enable_search(true);
set_headers_visible(false);
set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_NATURAL);
set_activate_on_single_click(true);
set_hover_selection(false);
set_rules_hint(true);
}
void ListViewText::ListViewText::append(const std::string& value) {
auto new_row=list_store->append();
new_row->set_value(column_record.text, value);
}
void ListViewText::ListViewText::hide() {
Gtk::TreeView::hide();
list_store->clear();
}
SelectionDialogBase::SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup): text_view(text_view),
list_view_text(use_markup), start_mark(start_mark), show_search_entry(show_search_entry) {
if(!show_search_entry)
window=std::unique_ptr<Gtk::Window>(new Gtk::Window(Gtk::WindowType::WINDOW_POPUP));
else
@ -27,13 +55,6 @@ start_mark(start_mark), show_search_entry(show_search_entry), list_view_text(1,
window->property_decorated()=false;
window->set_skip_taskbar_hint(true);
scrolled_window.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC, Gtk::PolicyType::POLICY_AUTOMATIC);
list_view_text.set_enable_search(true);
list_view_text.set_headers_visible(false);
list_view_text.set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_NATURAL);
list_view_text.set_activate_on_single_click(true);
list_view_text.set_hover_selection(false);
list_view_text.set_rules_hint(true);
//list_view_text.set_fixed_height_mode(true); //TODO: This is buggy on OS X, remember to post an issue on GTK+ 3
list_view_text.signal_realize().connect([this](){
resize();
@ -89,8 +110,8 @@ void SelectionDialogBase::hide() {
}
void SelectionDialogBase::update_tooltips() {
if(list_view_text.get_selected().size()>0) {
auto it=list_view_text.get_selection()->get_selected();
if(it) {
std::string row;
it->get_value(0, row);
if(row!=last_row || last_row.size()==0) {
@ -155,7 +176,7 @@ void SelectionDialogBase::resize() {
}
}
SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry) : SelectionDialogBase(text_view, start_mark, show_search_entry) {}
SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup) : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) {}
void SelectionDialog::show() {
SelectionDialogBase::show();
@ -168,6 +189,14 @@ void SelectionDialog::show() {
auto search_key_lc=*search_key;
std::transform(row_lc.begin(), row_lc.end(), row_lc.begin(), ::tolower);
std::transform(search_key_lc.begin(), search_key_lc.end(), search_key_lc.begin(), ::tolower);
if(list_view_text.use_markup) {
size_t pos=0;
while((pos=row_lc.find('<', pos))!=std::string::npos) {
auto pos2=row_lc.find('>', pos+1);
row_lc.erase(pos, pos2-pos+1);
}
search_key_lc=Glib::Markup::escape_text(search_key_lc);
}
if(row_lc.find(search_key_lc)!=std::string::npos)
return true;
return false;
@ -221,8 +250,8 @@ void SelectionDialog::show() {
});
auto activate=[this](){
if(on_select && list_view_text.get_selected().size()>0) {
auto it=list_view_text.get_selection()->get_selected();
if(on_select && it) {
std::string row;
it->get_value(0, row);
on_select(row, true);
@ -288,7 +317,7 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) {
return false;
}
CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark) : SelectionDialogBase(text_view, start_mark, false) {}
CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark) : SelectionDialogBase(text_view, start_mark, false, false) {}
void CompletionDialog::show() {
SelectionDialogBase::show();
@ -344,8 +373,8 @@ void CompletionDialog::show() {
void CompletionDialog::select(bool hide_window) {
row_in_entry=true;
if(list_view_text.get_selected().size()>0) {
auto it=list_view_text.get_selection()->get_selected();
if(it) {
std::string row;
it->get_value(0, row);
if(on_select)

25
src/selectiondialog.h

@ -6,9 +6,28 @@
#include "tooltips.h"
#include <unordered_map>
class ListViewText : public Gtk::TreeView {
class ColumnRecord : public Gtk::TreeModel::ColumnRecord {
public:
ColumnRecord() {
add(text);
}
Gtk::TreeModelColumn<std::string> text;
};
public:
bool use_markup;
ListViewText(bool use_markup);
void append(const std::string& value);
void hide();
private:
Glib::RefPtr<Gtk::ListStore> list_store;
ColumnRecord column_record;
Gtk::CellRendererText cell_renderer;
};
class SelectionDialogBase {
public:
SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry);
SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup);
~SelectionDialogBase();
virtual void add_row(const std::string& row, const std::string& tooltip="");
virtual void show();
@ -25,7 +44,7 @@ protected:
std::unique_ptr<Gtk::Window> window;
Gtk::ScrolledWindow scrolled_window;
Gtk::ListViewText list_view_text;
ListViewText list_view_text;
Gtk::Entry search_entry;
bool show_search_entry;
std::unique_ptr<Tooltips> tooltips;
@ -37,7 +56,7 @@ private:
class SelectionDialog : public SelectionDialogBase {
public:
SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry=true);
SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry=true, bool use_markup=false);
bool on_key_press(GdkEventKey* key);
void show();
};

17
src/source.cc

@ -371,8 +371,10 @@ void Source::View::configure() {
note_tag->property_foreground()=style->property_foreground();
}
if(Singleton::config->source.spellcheck_language.size()>0)
if(Singleton::config->source.spellcheck_language.size()>0) {
aspell_config_replace(spellcheck_config, "lang", Singleton::config->source.spellcheck_language.c_str());
aspell_config_replace(spellcheck_config, "encoding", "utf-8");
}
spellcheck_possible_err=new_aspell_speller(spellcheck_config);
if(spellcheck_checker!=NULL)
delete_aspell_speller(spellcheck_checker);
@ -533,10 +535,13 @@ void Source::View::replace_all(const std::string &replacement) {
void Source::View::paste() {
std::string text=Gtk::Clipboard::get()->wait_for_text();
//remove carriage returns (which leads to crash)
for(auto it=text.begin();it!=text.end();it++) {
if(*it=='\r') {
it=text.erase(it);
//Replace carriage returns (which leads to crash) with newlines
for(size_t c=0;c<text.size();c++) {
if(text[c]=='\r') {
if((c+1)<text.size() && text[c+1]=='\n')
text.replace(c, 2, "\n");
else
text.replace(c, 1, "\n");
}
}
@ -655,6 +660,8 @@ void Source::View::set_info(const std::string &info) {
}
void Source::View::spellcheck(const Gtk::TextIter& start, const Gtk::TextIter& end) {
if(spellcheck_checker==NULL)
return;
auto iter=start;
while(iter && iter<end) {
if(is_word_iter(iter)) {

15
src/source.h

@ -16,14 +16,15 @@ namespace Source {
class Token {
public:
Token(): type(-1) {}
Token(int type, const std::string &spelling, const std::string &usr):
type(type), spelling(spelling), usr(usr) {}
Token(Glib::RefPtr<Gsv::Language> language, int type, const std::string &spelling, const std::string &usr):
language(language), type(type), spelling(spelling), usr(usr) {}
operator bool() const {return (type>=0 && spelling.size()>0 && usr.size()>0);}
bool operator==(const Token &o) const {return (type==o.type &&
spelling==o.spelling &&
usr==o.usr);}
bool operator!=(const Token &o) const {return !(*this==o);}
Glib::RefPtr<Gsv::Language> language;
int type;
std::string spelling;
std::string usr;
@ -32,11 +33,12 @@ namespace Source {
class Offset {
public:
Offset() {}
Offset(unsigned line, unsigned index): line(line), index(index) {}
Offset(unsigned line, unsigned index, const boost::filesystem::path &file_path=""): line(line), index(index), file_path(file_path) {}
bool operator==(const Offset &o) {return (line==o.line && index==o.index);}
unsigned line;
unsigned index;
boost::filesystem::path file_path;
};
class FixIt {
@ -74,7 +76,8 @@ namespace Source {
Glib::RefPtr<Gsv::Language> language;
std::function<void()> auto_indent;
std::function<std::pair<std::string, Offset>()> get_declaration_location;
std::function<Offset()> get_declaration_location;
std::function<std::vector<std::pair<Offset, std::string> >(const Token &token)> get_usages;
std::function<void()> goto_method;
std::function<Token()> get_token;
std::function<std::vector<std::string>()> get_token_data;
@ -82,6 +85,9 @@ namespace Source {
std::function<void()> goto_next_diagnostic;
std::function<void()> apply_fix_its;
std::unique_ptr<SelectionDialog> selection_dialog;
sigc::connection delayed_tooltips_connection;
std::function<void(View* view, const std::string &status)> on_update_status;
std::function<void(View* view, const std::string &info)> on_update_info;
void set_status(const std::string &status);
@ -103,7 +109,6 @@ namespace Source {
virtual void show_type_tooltips(const Gdk::Rectangle &rectangle) {}
gdouble on_motion_last_x;
gdouble on_motion_last_y;
sigc::connection delayed_tooltips_connection;
void set_tooltip_events();
std::string get_line(const Gtk::TextIter &iter);

129
src/source_clang.cc

@ -100,9 +100,9 @@ void Source::ClangViewParse::configure() {
}
}
bracket_regex=std::regex("^([ \\t]*).*\\{ *$");
no_bracket_statement_regex=std::regex("^([ \\t]*)(if|for|else if|catch|while) *\\(.*[^;}] *$");
no_bracket_no_para_statement_regex=std::regex("^([ \\t]*)(else|try|do) *$");
bracket_regex=boost::regex("^([ \\t]*).*\\{ *$");
no_bracket_statement_regex=boost::regex("^([ \\t]*)(if|for|else if|catch|while) *\\(.*[^;}] *$");
no_bracket_no_para_statement_regex=boost::regex("^([ \\t]*)(else|try|do) *$");
}
void Source::ClangViewParse::init_parse() {
@ -194,9 +194,9 @@ std::vector<std::string> Source::ClangViewParse::get_compilation_commands() {
}
}
auto clang_version_string=clang::to_string(clang_getClangVersion());
const std::regex clang_version_regex("^[A-Za-z ]+([0-9.]+).*$");
std::smatch sm;
if(std::regex_match(clang_version_string, sm, clang_version_regex)) {
const boost::regex clang_version_regex("^[A-Za-z ]+([0-9.]+).*$");
boost::smatch sm;
if(boost::regex_match(clang_version_string, sm, clang_version_regex)) {
auto clang_version=sm[1].str();
arguments.emplace_back("-I/usr/lib/clang/"+clang_version+"/include");
arguments.emplace_back("-I/usr/local/Cellar/llvm/"+clang_version+"/lib/clang/"+clang_version+"/include");
@ -464,7 +464,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) {
auto start_sentence_tabs_end_iter=get_tabs_end_iter(start_of_sentence_iter);
auto tabs=get_line_before(start_sentence_tabs_end_iter);
std::smatch sm;
boost::smatch sm;
if(iter.backward_char() && *iter=='{') {
auto found_iter=iter;
bool found_right_bracket=find_right_bracket_forward(iter, found_iter);
@ -516,13 +516,13 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) {
iter.forward_char();
}
}
else if(std::regex_match(line, sm, no_bracket_statement_regex)) {
else if(boost::regex_match(line, sm, no_bracket_statement_regex)) {
get_source_buffer()->insert_at_cursor("\n"+tabs+tab);
scroll_to(get_source_buffer()->get_insert());
get_source_buffer()->end_user_action();
return true;
}
else if(std::regex_match(line, sm, no_bracket_no_para_statement_regex)) {
else if(boost::regex_match(line, sm, no_bracket_no_para_statement_regex)) {
get_source_buffer()->insert_at_cursor("\n"+tabs+tab);
scroll_to(get_source_buffer()->get_insert());
get_source_buffer()->end_user_action();
@ -530,18 +530,18 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) {
}
//Indenting after for instance if(...)\n...;\n
else if(iter.backward_char() && *iter==';') {
std::smatch sm2;
boost::smatch sm2;
size_t line_nr=get_source_buffer()->get_insert()->get_iter().get_line();
if(line_nr>0 && tabs.size()>=tab_size) {
std::string previous_line=get_line(line_nr-1);
if(!std::regex_match(previous_line, sm2, bracket_regex)) {
if(std::regex_match(previous_line, sm2, no_bracket_statement_regex)) {
if(!boost::regex_match(previous_line, sm2, bracket_regex)) {
if(boost::regex_match(previous_line, sm2, no_bracket_statement_regex)) {
get_source_buffer()->insert_at_cursor("\n"+sm2[1].str());
scroll_to(get_source_buffer()->get_insert());
get_source_buffer()->end_user_action();
return true;
}
else if(std::regex_match(previous_line, sm2, no_bracket_no_para_statement_regex)) {
else if(boost::regex_match(previous_line, sm2, no_bracket_no_para_statement_regex)) {
get_source_buffer()->insert_at_cursor("\n"+sm2[1].str());
scroll_to(get_source_buffer()->get_insert());
get_source_buffer()->end_user_action();
@ -558,7 +558,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) {
left_bracket_iter.forward_char();
Gtk::TextIter start_of_left_bracket_sentence_iter;
if(find_start_of_closed_expression(left_bracket_iter, start_of_left_bracket_sentence_iter)) {
std::smatch sm;
boost::smatch sm;
auto tabs_end_iter=get_tabs_end_iter(start_of_left_bracket_sentence_iter);
auto tabs_start_of_sentence=get_line_before(tabs_end_iter);
if(tabs.size()==(tabs_start_of_sentence.size()+tab_size)) {
@ -689,10 +689,10 @@ void Source::ClangViewAutocomplete::start_autocomplete() {
}
std::string line=" "+get_line_before();
if((std::count(line.begin(), line.end(), '\"')%2)!=1 && line.find("//")==std::string::npos) {
const std::regex in_specified_namespace("^(.*[a-zA-Z0-9_\\)\\]\\>])(->|\\.|::)([a-zA-Z0-9_]*)$");
const std::regex within_namespace("^(.*)([^a-zA-Z0-9_]+)([a-zA-Z0-9_]{3,})$");
std::smatch sm;
if(std::regex_match(line, sm, in_specified_namespace)) {
const boost::regex in_specified_namespace("^(.*[a-zA-Z0-9_\\)\\]\\>])(->|\\.|::)([a-zA-Z0-9_]*)$");
const boost::regex within_namespace("^(.*)([^a-zA-Z0-9_]+)([a-zA-Z0-9_]{3,})$");
boost::smatch sm;
if(boost::regex_match(line, sm, in_specified_namespace)) {
prefix_mutex.lock();
prefix=sm[3].str();
prefix_mutex.unlock();
@ -702,7 +702,7 @@ void Source::ClangViewAutocomplete::start_autocomplete() {
else if(last_keyval=='.' && autocomplete_starting)
autocomplete_cancel_starting=true;
}
else if(std::regex_match(line, sm, within_namespace)) {
else if(boost::regex_match(line, sm, within_namespace)) {
prefix_mutex.lock();
prefix=sm[3].str();
prefix_mutex.unlock();
@ -984,7 +984,7 @@ Source::ClangViewAutocomplete(file_path, project_path, language) {
continue;
auto referenced=cursor.get_referenced();
if(referenced)
return Token(static_cast<int>(referenced.get_kind()), token.get_spelling(), referenced.get_usr());
return Token(this->language, static_cast<int>(referenced.get_kind()), token.get_spelling(), referenced.get_usr());
}
}
}
@ -994,7 +994,8 @@ Source::ClangViewAutocomplete(file_path, project_path, language) {
rename_similar_tokens=[this](const Token &token, const std::string &text) {
size_t number=0;
if(source_readable) {
if(source_readable && token.language &&
(token.language->get_id()=="chdr" || token.language->get_id()=="cpphdr" || token.language->get_id()=="c" || token.language->get_id()=="cpp" || token.language->get_id()=="objc")) {
auto offsets=clang_tokens->get_similar_token_offsets(static_cast<clang::CursorKind>(token.type), token.spelling, token.usr);
std::vector<std::pair<Glib::RefPtr<Gtk::TextMark>, Glib::RefPtr<Gtk::TextMark> > > marks;
for(auto &offset: offsets) {
@ -1027,7 +1028,7 @@ Source::ClangViewAutocomplete(file_path, project_path, language) {
});
get_declaration_location=[this](){
std::pair<std::string, Offset> location;
Offset location;
if(source_readable) {
auto iter=get_buffer()->get_insert()->get_iter();
auto line=(unsigned)iter.get_line();
@ -1038,10 +1039,10 @@ Source::ClangViewAutocomplete(file_path, project_path, language) {
if(line==token.offsets.first.line-1 && index>=token.offsets.first.index-1 && index <=token.offsets.second.index-1) {
auto referenced=cursor.get_referenced();
if(referenced) {
location.first=referenced.get_source_location().get_path();
location.file_path=referenced.get_source_location().get_path();
auto clang_offset=referenced.get_source_location().get_offset();
location.second.line=clang_offset.line;
location.second.index=clang_offset.index;
location.line=clang_offset.line;
location.index=clang_offset.index;
break;
}
}
@ -1051,6 +1052,49 @@ Source::ClangViewAutocomplete(file_path, project_path, language) {
return location;
};
get_usages=[this](const Token &token) {
std::vector<std::pair<Offset, std::string> > usages;
if(source_readable && token.language &&
(token.language->get_id()=="chdr" || token.language->get_id()=="cpphdr" || token.language->get_id()=="c" || token.language->get_id()=="cpp" || token.language->get_id()=="objc")) {
auto offsets=clang_tokens->get_similar_token_offsets(static_cast<clang::CursorKind>(token.type), token.spelling, token.usr);
for(auto &offset: offsets) {
size_t whitespaces_removed=0;
auto start_iter=get_buffer()->get_iter_at_line(offset.first.line-1);
while(!start_iter.ends_line() && (*start_iter==' ' || *start_iter=='\t')) {
start_iter.forward_char();
whitespaces_removed++;
}
auto end_iter=start_iter;
while(!end_iter.ends_line())
end_iter.forward_char();
std::string line=Glib::Markup::escape_text(get_buffer()->get_text(start_iter, end_iter));
//markup token as bold
size_t token_start_pos=offset.first.index-1-whitespaces_removed;
size_t token_end_pos=offset.second.index-1-whitespaces_removed;
size_t pos=0;
while((pos=line.find('&', pos))!=std::string::npos) {
size_t pos2=line.find(';', pos+2);
if(token_start_pos>pos) {
token_start_pos+=pos2-pos;
token_end_pos+=pos2-pos;
}
else if(token_end_pos>pos)
token_end_pos+=pos2-pos;
else
break;
pos=pos2+1;
}
line.insert(token_end_pos, "</b>");
line.insert(token_start_pos, "<b>");
usages.emplace_back(Offset(offset.first.line-1, offset.first.index-1, this->file_path), line);
}
}
return usages;
};
goto_method=[this](){
if(source_readable) {
auto iter=get_buffer()->get_insert()->get_iter();
@ -1062,14 +1106,43 @@ Source::ClangViewAutocomplete(file_path, project_path, language) {
if(!visible_rect.intersects(iter_rect)) {
get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3);
}
selection_dialog=std::unique_ptr<SelectionDialog>(new SelectionDialog(*this, get_buffer()->create_mark(iter)));
selection_dialog=std::unique_ptr<SelectionDialog>(new SelectionDialog(*this, get_buffer()->create_mark(iter), true, true));
auto rows=std::make_shared<std::unordered_map<std::string, clang::Offset> >();
auto methods=clang_tokens->get_cxx_methods();
if(methods.size()==0)
return;
for(auto &method: methods) {
(*rows)[method.first]=method.second;
selection_dialog->add_row(method.first);
std::string row=std::to_string(method.second.line)+": "+Glib::Markup::escape_text(method.first);
//Add bold method token
size_t token_end_pos=row.find('(');
if(token_end_pos==0 || token_end_pos==std::string::npos)
continue;
if(token_end_pos>8 && row.substr(token_end_pos-4, 4)=="&gt;") {
token_end_pos-=8;
size_t angle_bracket_count=1;
do {
if(row.substr(token_end_pos-4, 4)=="&gt;") {
angle_bracket_count++;
token_end_pos-=4;
}
else if(row.substr(token_end_pos-4, 4)=="&lt;") {
angle_bracket_count--;
token_end_pos-=4;
}
else
token_end_pos--;
} while(angle_bracket_count>0 && token_end_pos>4);
}
auto pos=token_end_pos;
do {
pos--;
} while(((row[pos]>='a' && row[pos]<='z') ||
(row[pos]>='A' && row[pos]<='Z') ||
(row[pos]>='0' && row[pos]<='9') || row[pos]=='_' || row[pos]=='~') && pos>0);
row.insert(token_end_pos, "</b>");
row.insert(pos+1, "<b>");
(*rows)[row]=method.second;
selection_dialog->add_row(row);
}
selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) {
auto offset=rows->at(selected);

9
src/source_clang.h

@ -5,7 +5,7 @@
#include <atomic>
#include <mutex>
#include <set>
#include <regex>
#include <boost/regex.hpp>
#include "clangmm.h"
#include "source.h"
#include "terminal.h"
@ -42,9 +42,9 @@ namespace Source {
virtual void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle);
virtual void show_type_tooltips(const Gdk::Rectangle &rectangle);
std::regex bracket_regex;
std::regex no_bracket_statement_regex;
std::regex no_bracket_no_para_statement_regex;
boost::regex bracket_regex;
boost::regex no_bracket_statement_regex;
boost::regex no_bracket_no_para_statement_regex;
std::set<int> diagnostic_offsets;
std::vector<FixIt> fix_its;
@ -121,7 +121,6 @@ namespace Source {
void tag_similar_tokens(const Token &token);
Glib::RefPtr<Gtk::TextTag> similar_tokens_tag;
Token last_tagged_token;
std::unique_ptr<SelectionDialog> selection_dialog;
bool renaming=false;
};

82
src/window.cc

@ -172,7 +172,9 @@ void Window::set_menu_actions() {
auto time_now=std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
boost::filesystem::path path = Dialog::new_folder();
if(path!="" && boost::filesystem::exists(path)) {
if(boost::filesystem::last_write_time(path)>=time_now) {
boost::system::error_code ec;
auto last_write_time=boost::filesystem::last_write_time(path, ec);
if(!ec && last_write_time>=time_now) {
if(Singleton::directories->current_path!="")
Singleton::directories->update();
Singleton::terminal->print("New folder "+path.string()+" created.\n");
@ -382,10 +384,15 @@ void Window::set_menu_actions() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->get_declaration_location) {
auto location=notebook.get_current_view()->get_declaration_location();
if(location.first.size()>0) {
notebook.open(location.first);
auto line=static_cast<int>(location.second.line)-1;
auto index=static_cast<int>(location.second.index)-1;
if(!location.file_path.empty()) {
boost::filesystem::path declaration_file;
boost::system::error_code ec;
declaration_file=boost::filesystem::canonical(location.file_path, ec);
if(ec)
declaration_file=location.file_path;
notebook.open(declaration_file);
auto line=static_cast<int>(location.line)-1;
auto index=static_cast<int>(location.index)-1;
auto buffer=notebook.get_current_view()->get_buffer();
line=std::min(line, buffer->get_line_count()-1);
if(line>=0) {
@ -405,6 +412,68 @@ void Window::set_menu_actions() {
}
}
});
menu->add_action("source_goto_usage", [this]() {
if(notebook.get_current_page()!=-1) {
auto current_view=notebook.get_current_view();
if(current_view->get_token && current_view->get_usages) {
auto token=current_view->get_token();
if(token) {
auto iter=current_view->get_buffer()->get_insert()->get_iter();
Gdk::Rectangle visible_rect;
current_view->get_visible_rect(visible_rect);
Gdk::Rectangle iter_rect;
current_view->get_iter_location(iter, iter_rect);
iter_rect.set_width(1);
if(!visible_rect.intersects(iter_rect)) {
current_view->get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3);
}
current_view->selection_dialog=std::unique_ptr<SelectionDialog>(new SelectionDialog(*current_view, current_view->get_buffer()->create_mark(iter), true, true));
auto rows=std::make_shared<std::unordered_map<std::string, Source::Offset> >();
//First add usages in current file
auto usages=current_view->get_usages(token);
for(auto &usage: usages) {
auto iter=current_view->get_buffer()->get_iter_at_line_index(usage.first.line, usage.first.index);
auto row=std::to_string(iter.get_line()+1)+':'+std::to_string(iter.get_line_offset()+1)+' '+usage.second;
(*rows)[row]=usage.first;
current_view->selection_dialog->add_row(row);
}
//Then the remaining opened files
for(int page=0;page<notebook.size();page++) {
auto view=notebook.get_view(page);
if(view!=current_view) {
if(view->get_usages) {
auto usages=view->get_usages(token);
for(auto &usage: usages) {
auto iter=view->get_buffer()->get_iter_at_line_index(usage.first.line, usage.first.index);
auto row=usage.first.file_path.filename().string()+":"+std::to_string(iter.get_line()+1)+':'+std::to_string(iter.get_line_offset()+1)+' '+usage.second;
(*rows)[row]=usage.first;
current_view->selection_dialog->add_row(row);
}
}
}
}
if(rows->size()==0)
return;
current_view->selection_dialog->on_select=[this, rows](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(offset.file_path, ec);
if(ec)
declaration_file=offset.file_path;
notebook.open(declaration_file);
auto view=notebook.get_current_view();
view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(offset.line, offset.index));
view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5);
view->delayed_tooltips_connection.disconnect();
};
current_view->selection_dialog->show();
}
}
}
});
menu->add_action("source_goto_method", [this]() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->goto_method) {
@ -567,6 +636,7 @@ void Window::activate_menu_items(bool activate) {
menu->actions["source_indentation_auto_indent_buffer"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->auto_indent) : 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_usage"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->get_usages) : false);
menu->actions["source_goto_method"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->goto_method) : false);
menu->actions["source_rename"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->rename_similar_tokens) : false);
menu->actions["source_goto_next_diagnostic"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->goto_next_diagnostic) : false);
@ -806,7 +876,7 @@ void Window::rename_token_entry() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->get_token) {
auto token=std::make_shared<Source::Token>(notebook.get_current_view()->get_token());
if(token) {
if(*token) {
entry_box.labels.emplace_back();
auto label_it=entry_box.labels.begin();
label_it->update=[label_it](int state, const std::string& message){

Loading…
Cancel
Save