diff --git a/juci/config.json b/juci/config.json index 42effbb..9c3e0a0 100644 --- a/juci/config.json +++ b/juci/config.json @@ -58,6 +58,7 @@ "edit_undo": "z", "edit_redo": "y", "edit_find": "f", + "goto_declaration": "d", "compile_and_run": "r", "compile": "r" }, diff --git a/juci/juci.cc b/juci/juci.cc index 0785b9a..4ca0558 100644 --- a/juci/juci.cc +++ b/juci/juci.cc @@ -41,7 +41,7 @@ void Juci::on_activate() { Singleton::notebook()->directories.open_folder(directory); } for(auto &f: files) - Singleton::notebook()->OnOpenFile(f); + Singleton::notebook()->open_file(f); } int main(int argc, char *argv[]) { diff --git a/juci/menu.cc b/juci/menu.cc index f5ccefa..a613492 100644 --- a/juci/menu.cc +++ b/juci/menu.cc @@ -11,6 +11,7 @@ Menu::Menu() : box(Gtk::ORIENTATION_VERTICAL) { action_group->add(Gtk::Action::create("WindowSplitWindow", "Split window"), Gtk::AccelKey(key_map["split_window"]), [this]() { }); action_group->add(Gtk::Action::create("ProjectMenu", "P_roject")); + action_group->add(Gtk::Action::create("SourceMenu", "_Source")); action_group->add(Gtk::Action::create("PluginMenu", "_Plugins")); action_group->add(Gtk::Action::create("HelpMenu", Gtk::Stock::HELP)); action_group->add(Gtk::Action::create("HelpAbout", Gtk::Stock::ABOUT), [this]() { @@ -21,8 +22,8 @@ Gtk::Widget& Menu::get_widget() { return *ui_manager->get_widget("/MenuBar"); } -Gtk::Menu& Menu::get_cpp() { - return *(Gtk::Menu*)ui_manager->get_widget("/MenuBar/CppMenu"); +Gtk::Menu& Menu::get_source_menu() { + return *(Gtk::Menu*)ui_manager->get_widget("/MenuBar/SourceMenu"); } void Menu::build() { diff --git a/juci/menu.h b/juci/menu.h index dc95ce4..40e3cb3 100644 --- a/juci/menu.h +++ b/juci/menu.h @@ -9,7 +9,7 @@ class Menu { public: Menu(); Gtk::Widget& get_widget(); - Gtk::Menu& get_cpp(); + Gtk::Menu& get_source_menu(); void build(); Gtk::Box box; diff --git a/juci/menu.xml b/juci/menu.xml index 9c6a63f..5f79da8 100644 --- a/juci/menu.xml +++ b/juci/menu.xml @@ -17,7 +17,10 @@ - + + + + diff --git a/juci/notebook.cc b/juci/notebook.cc index 261b438..e812dcd 100644 --- a/juci/notebook.cc +++ b/juci/notebook.cc @@ -4,6 +4,8 @@ #include "singletons.h" #include // c-library +#include //TODO: remove +using namespace std; //TODO: remove Notebook::View::View() { pack2(notebook); @@ -13,6 +15,7 @@ Notebook::View::View() { Notebook::Controller::Controller() : directories() { INFO("Create notebook"); + Gsv::init(); clipboard = Gtk::Clipboard::get(); view.pack1(directories.widget(), true, true); CreateKeybindings(); @@ -70,6 +73,19 @@ void Notebook::Controller::CreateKeybindings() { } INFO("Done Redo"); }); + + menu->action_group->add(Gtk::Action::create("SourceGotoDeclaration", "Go to declaration"), Gtk::AccelKey(menu->key_map["goto_declaration"]), [this]() { + if(CurrentPage()!=-1) { + if(CurrentSourceView()->get_declaration_location) { + auto location=CurrentSourceView()->get_declaration_location(); + if(location.first.size()>0) { + open_file(location.first); + CurrentSourceView()->get_buffer()->place_cursor(CurrentSourceView()->get_buffer()->get_iter_at_offset(location.second)); + CurrentSourceView()->scroll_to_insert(); + } + } + } + }); entry.button_apply_set_filename.signal_clicked().connect([this]() { std::string filename=entry(); @@ -83,7 +99,7 @@ void Notebook::Controller::CreateKeybindings() { else { std::ofstream f(p.string().c_str()); if(f) { - OnOpenFile(boost::filesystem::canonical(p).string()); + open_file(boost::filesystem::canonical(p).string()); if(project_path!="") directories.open_folder(project_path); //TODO: Do refresh instead } @@ -113,14 +129,21 @@ void Notebook::Controller::CreateKeybindings() { INFO("Notebook signal handlers sucsess"); } -void Notebook::Controller::OnOpenFile(std::string path) { +void Notebook::Controller::open_file(std::string path) { INFO("Notebook open file"); INFO("Notebook create page"); + for(int c=0;cview->file_path) { + view.notebook.set_current_page(c); + return; + } + } source_views.emplace_back(new Source(path, project_path)); scrolled_windows.emplace_back(new Gtk::ScrolledWindow()); hboxes.emplace_back(new Gtk::HBox()); scrolled_windows.back()->add(*source_views.back()->view); hboxes.back()->pack_start(*scrolled_windows.back(), true, true); + boost::filesystem::path file_path(source_views.back()->view->file_path); std::string title=file_path.filename().string(); view.notebook.append_page(*hboxes.back(), title); @@ -206,7 +229,7 @@ void Notebook::Controller std::stringstream sstm; sstm << row[directories.view().m_col_path]; std::string file = sstm.str(); - OnOpenFile(file); + open_file(file); } } } diff --git a/juci/notebook.h b/juci/notebook.h index 13808c2..9c1f507 100644 --- a/juci/notebook.h +++ b/juci/notebook.h @@ -29,7 +29,7 @@ namespace Notebook { bool OnSaveFile(std::string path); void OnDirectoryNavigation(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column); - void OnOpenFile(std::string filename); + void open_file(std::string filename); int Pages(); void search(bool forward); View view; diff --git a/juci/source.cc b/juci/source.cc index f01d35b..6643431 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -8,6 +8,9 @@ #include #include "singletons.h" +#include //TODO: remove +using namespace std; //TODO: remove + namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE } @@ -27,7 +30,6 @@ bool Source::Config::legal_extension(std::string e) const { ////////////// Source::View::View(const std::string& file_path, const std::string& project_path): file_path(file_path), project_path(project_path) { - Gsv::init(); set_smart_home_end(Gsv::SMART_HOME_END_BEFORE); set_show_line_numbers(Singleton::Config::source()->show_line_numbers); set_highlight_current_line(Singleton::Config::source()->highlight_current_line); @@ -44,6 +46,10 @@ file_path(file_path), project_path(project_path) { for (auto &item : Singleton::Config::source()->tags) { get_source_buffer()->create_tag(item.first)->property_foreground() = item.second; } + + scroll_to_insert_dispatcher.connect([this](){ + scroll_to(get_buffer()->get_insert()); + }); } string Source::View::get_line(size_t line_number) { @@ -62,12 +68,21 @@ string Source::View::get_line_before_insert() { return line; } +//TODO: Fix this dirty hack. Gtk's scroll_to is bugged... +void Source::View::scroll_to_insert() { + std::thread scroll_to_insert_thread([this](){ + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + scroll_to_insert_dispatcher(); + }); + scroll_to_insert_thread.detach(); +} + //Basic indentation bool Source::View::on_key_press_event(GdkEventKey* key) { auto config=Singleton::Config::source(); const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$"); //Indent as in next or previous line - if(key->keyval==GDK_KEY_Return && key->state==0) { + if(key->keyval==GDK_KEY_Return && key->state==0 && !get_buffer()->get_has_selection()) { int line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); string line(get_line_before_insert()); std::smatch sm; @@ -124,7 +139,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { return true; } //"Smart" backspace key - else if(key->keyval==GDK_KEY_BackSpace) { + else if(key->keyval==GDK_KEY_BackSpace && !get_buffer()->get_has_selection()) { Gtk::TextIter insert_it=get_source_buffer()->get_insert()->get_iter(); int line_nr=insert_it.get_line(); if(line_nr>0) { @@ -421,7 +436,7 @@ void Source::ClangViewParse::on_mark_set(const Gtk::TextBuffer::iterator& iterat return false; }, 500); type_tooltips.hide(); - diagnostic_tooltips.hide(); + diagnostic_tooltips.hide(); } } @@ -442,6 +457,9 @@ bool Source::ClangViewParse::on_scroll_event(GdkEventScroll* event) { //Clang indentation //TODO: replace indentation methods with a better implementation or maybe use libclang bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { + if(get_buffer()->get_has_selection()) { + return Source::View::on_key_press_event(key); + } auto config=Singleton::Config::source(); const std::regex bracket_regex(std::string("^(")+config->tab_char+"*).*\\{ *$"); const std::regex no_bracket_statement_regex(std::string("^(")+config->tab_char+"*)(if|for|else if|catch|while) *\\(.*[^;}] *$"); @@ -766,6 +784,26 @@ Source::ClangViewAutocomplete(file_path, project_path) { } } }); + + get_declaration_location=[this](){ + std::pair location; + if(clang_readable) { + for(auto &token: *clang_tokens) { + if(token.has_type()) { + auto insert_offset=(unsigned)get_buffer()->get_insert()->get_iter().get_offset(); + if(insert_offset>=token.offsets.first && insert_offset<=token.offsets.second) { + auto referenced=token.get_cursor().get_referenced(); + if(referenced) { + location.first=referenced.get_source_location().get_path(); + location.second=referenced.get_source_location().get_offset(); + break; + } + } + } + } + } + return location; + }; } //////////////// diff --git a/juci/source.h b/juci/source.h index 6762980..26dc02f 100644 --- a/juci/source.h +++ b/juci/source.h @@ -49,11 +49,16 @@ public: View(const std::string& file_path, const std::string& project_path); std::string get_line(size_t line_number); std::string get_line_before_insert(); + void scroll_to_insert(); std::string file_path; std::string project_path; Gtk::TextIter search_start, search_end; + + std::function()> get_declaration_location; protected: bool on_key_press_event(GdkEventKey* key); + private: + Glib::Dispatcher scroll_to_insert_dispatcher; }; // class View class GenericView : public View { diff --git a/juci/sourcefile.h b/juci/sourcefile.h index 608ea05..2afc263 100644 --- a/juci/sourcefile.h +++ b/juci/sourcefile.h @@ -4,20 +4,18 @@ #include #include -using namespace std; - class sourcefile { public: - explicit sourcefile(const string &filename); - vector get_lines(); - string get_content(); - string get_line(int line_number); - int save(const string &text); + explicit sourcefile(const std::string &filename); + std::vector get_lines(); + std::string get_content(); + std::string get_line(int line_number); + int save(const std::string &text); private: - void open(const string &filename); - vector lines; - string filename; + void open(const std::string &filename); + std::vector lines; + std::string filename; }; #endif // JUCI_SOURCEFILE_H_ diff --git a/juci/terminal.cc b/juci/terminal.cc index 20f1033..aad7e45 100644 --- a/juci/terminal.cc +++ b/juci/terminal.cc @@ -87,8 +87,10 @@ int Terminal::Controller::print(std::string message){ INFO("Terminal: PrintMessage"); view.text_view.get_buffer()->insert(view.text_view.get_buffer()->end(), "> "+message); auto mark_end=view.text_view.get_buffer()->create_mark(view.text_view.get_buffer()->end()); - view.text_view.scroll_to(mark_end); - return mark_end->get_iter().get_line(); + view.text_view.scroll_to(view.text_view.get_buffer()->get_insert()); + auto line=mark_end->get_iter().get_line(); + view.text_view.get_buffer()->delete_mark(mark_end); + return line; } void Terminal::Controller::print(int line_nr, std::string message){ diff --git a/juci/window.cc b/juci/window.cc index 63b2d8f..cdf27d0 100644 --- a/juci/window.cc +++ b/juci/window.cc @@ -148,7 +148,7 @@ void Window::OnOpenFile() { switch (result) { case(Gtk::RESPONSE_OK): { std::string path = dialog.get_filename(); - Singleton::notebook()->OnOpenFile(path); + Singleton::notebook()->open_file(path); break; } case(Gtk::RESPONSE_CANCEL): {