Browse Source

Go to declaration implemented. Also some smaller fixes, including going to tab if opening an already open file. Scroll to iterator/cursor/insert/mark/whatever is bugged in GTK it seems, need a better workaround here.

merge-requests/365/head
eidheim 11 years ago
parent
commit
ffd7e2b1ec
  1. 1
      juci/config.json
  2. 2
      juci/juci.cc
  3. 5
      juci/menu.cc
  4. 2
      juci/menu.h
  5. 3
      juci/menu.xml
  6. 29
      juci/notebook.cc
  7. 2
      juci/notebook.h
  8. 44
      juci/source.cc
  9. 5
      juci/source.h
  10. 18
      juci/sourcefile.h
  11. 6
      juci/terminal.cc
  12. 2
      juci/window.cc

1
juci/config.json

@ -58,6 +58,7 @@
"edit_undo": "<control>z", "edit_undo": "<control>z",
"edit_redo": "<control>y", "edit_redo": "<control>y",
"edit_find": "<control>f", "edit_find": "<control>f",
"goto_declaration": "<control>d",
"compile_and_run": "<control><alt>r", "compile_and_run": "<control><alt>r",
"compile": "<control>r" "compile": "<control>r"
}, },

2
juci/juci.cc

@ -41,7 +41,7 @@ void Juci::on_activate() {
Singleton::notebook()->directories.open_folder(directory); Singleton::notebook()->directories.open_folder(directory);
} }
for(auto &f: files) for(auto &f: files)
Singleton::notebook()->OnOpenFile(f); Singleton::notebook()->open_file(f);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {

5
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("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("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("PluginMenu", "_Plugins"));
action_group->add(Gtk::Action::create("HelpMenu", Gtk::Stock::HELP)); action_group->add(Gtk::Action::create("HelpMenu", Gtk::Stock::HELP));
action_group->add(Gtk::Action::create("HelpAbout", Gtk::Stock::ABOUT), [this]() { 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"); return *ui_manager->get_widget("/MenuBar");
} }
Gtk::Menu& Menu::get_cpp() { Gtk::Menu& Menu::get_source_menu() {
return *(Gtk::Menu*)ui_manager->get_widget("/MenuBar/CppMenu"); return *(Gtk::Menu*)ui_manager->get_widget("/MenuBar/SourceMenu");
} }
void Menu::build() { void Menu::build() {

2
juci/menu.h

@ -9,7 +9,7 @@ class Menu {
public: public:
Menu(); Menu();
Gtk::Widget& get_widget(); Gtk::Widget& get_widget();
Gtk::Menu& get_cpp(); Gtk::Menu& get_source_menu();
void build(); void build();
Gtk::Box box; Gtk::Box box;

3
juci/menu.xml

@ -18,6 +18,9 @@
<menuitem action='EditUndo'/> <menuitem action='EditUndo'/>
<menuitem action='EditRedo'/> <menuitem action='EditRedo'/>
</menu> </menu>
<menu action='SourceMenu'>
<menuitem action='SourceGotoDeclaration'/>
</menu>
<menu action='ProjectMenu'> <menu action='ProjectMenu'>
<menuitem action='ProjectCompileAndRun'/> <menuitem action='ProjectCompileAndRun'/>
<menuitem action='ProjectCompile'/> <menuitem action='ProjectCompile'/>

29
juci/notebook.cc

@ -4,6 +4,8 @@
#include "singletons.h" #include "singletons.h"
#include <gtksourceview/gtksource.h> // c-library #include <gtksourceview/gtksource.h> // c-library
#include <iostream> //TODO: remove
using namespace std; //TODO: remove
Notebook::View::View() { Notebook::View::View() {
pack2(notebook); pack2(notebook);
@ -13,6 +15,7 @@ Notebook::View::View() {
Notebook::Controller::Controller() : Notebook::Controller::Controller() :
directories() { directories() {
INFO("Create notebook"); INFO("Create notebook");
Gsv::init();
clipboard = Gtk::Clipboard::get(); clipboard = Gtk::Clipboard::get();
view.pack1(directories.widget(), true, true); view.pack1(directories.widget(), true, true);
CreateKeybindings(); CreateKeybindings();
@ -71,6 +74,19 @@ void Notebook::Controller::CreateKeybindings() {
INFO("Done Redo"); 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]() { entry.button_apply_set_filename.signal_clicked().connect([this]() {
std::string filename=entry(); std::string filename=entry();
if(filename!="") { if(filename!="") {
@ -83,7 +99,7 @@ void Notebook::Controller::CreateKeybindings() {
else { else {
std::ofstream f(p.string().c_str()); std::ofstream f(p.string().c_str());
if(f) { if(f) {
OnOpenFile(boost::filesystem::canonical(p).string()); open_file(boost::filesystem::canonical(p).string());
if(project_path!="") if(project_path!="")
directories.open_folder(project_path); //TODO: Do refresh instead directories.open_folder(project_path); //TODO: Do refresh instead
} }
@ -113,14 +129,21 @@ void Notebook::Controller::CreateKeybindings() {
INFO("Notebook signal handlers sucsess"); 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 open file");
INFO("Notebook create page"); INFO("Notebook create page");
for(int c=0;c<Pages();c++) {
if(path==source_views.at(c)->view->file_path) {
view.notebook.set_current_page(c);
return;
}
}
source_views.emplace_back(new Source(path, project_path)); source_views.emplace_back(new Source(path, project_path));
scrolled_windows.emplace_back(new Gtk::ScrolledWindow()); scrolled_windows.emplace_back(new Gtk::ScrolledWindow());
hboxes.emplace_back(new Gtk::HBox()); hboxes.emplace_back(new Gtk::HBox());
scrolled_windows.back()->add(*source_views.back()->view); scrolled_windows.back()->add(*source_views.back()->view);
hboxes.back()->pack_start(*scrolled_windows.back(), true, true); hboxes.back()->pack_start(*scrolled_windows.back(), true, true);
boost::filesystem::path file_path(source_views.back()->view->file_path); boost::filesystem::path file_path(source_views.back()->view->file_path);
std::string title=file_path.filename().string(); std::string title=file_path.filename().string();
view.notebook.append_page(*hboxes.back(), title); view.notebook.append_page(*hboxes.back(), title);
@ -206,7 +229,7 @@ void Notebook::Controller
std::stringstream sstm; std::stringstream sstm;
sstm << row[directories.view().m_col_path]; sstm << row[directories.view().m_col_path];
std::string file = sstm.str(); std::string file = sstm.str();
OnOpenFile(file); open_file(file);
} }
} }
} }

2
juci/notebook.h

@ -29,7 +29,7 @@ namespace Notebook {
bool OnSaveFile(std::string path); bool OnSaveFile(std::string path);
void OnDirectoryNavigation(const Gtk::TreeModel::Path& path, void OnDirectoryNavigation(const Gtk::TreeModel::Path& path,
Gtk::TreeViewColumn* column); Gtk::TreeViewColumn* column);
void OnOpenFile(std::string filename); void open_file(std::string filename);
int Pages(); int Pages();
void search(bool forward); void search(bool forward);
View view; View view;

44
juci/source.cc

@ -8,6 +8,9 @@
#include <regex> #include <regex>
#include "singletons.h" #include "singletons.h"
#include <iostream> //TODO: remove
using namespace std; //TODO: remove
namespace sigc { namespace sigc {
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE 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): Source::View::View(const std::string& file_path, const std::string& project_path):
file_path(file_path), project_path(project_path) { file_path(file_path), project_path(project_path) {
Gsv::init();
set_smart_home_end(Gsv::SMART_HOME_END_BEFORE); set_smart_home_end(Gsv::SMART_HOME_END_BEFORE);
set_show_line_numbers(Singleton::Config::source()->show_line_numbers); set_show_line_numbers(Singleton::Config::source()->show_line_numbers);
set_highlight_current_line(Singleton::Config::source()->highlight_current_line); 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) { for (auto &item : Singleton::Config::source()->tags) {
get_source_buffer()->create_tag(item.first)->property_foreground() = item.second; 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) { string Source::View::get_line(size_t line_number) {
@ -62,12 +68,21 @@ string Source::View::get_line_before_insert() {
return line; 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 //Basic indentation
bool Source::View::on_key_press_event(GdkEventKey* key) { bool Source::View::on_key_press_event(GdkEventKey* key) {
auto config=Singleton::Config::source(); auto config=Singleton::Config::source();
const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$"); const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$");
//Indent as in next or previous line //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(); int line_nr=get_source_buffer()->get_insert()->get_iter().get_line();
string line(get_line_before_insert()); string line(get_line_before_insert());
std::smatch sm; std::smatch sm;
@ -124,7 +139,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) {
return true; return true;
} }
//"Smart" backspace key //"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(); Gtk::TextIter insert_it=get_source_buffer()->get_insert()->get_iter();
int line_nr=insert_it.get_line(); int line_nr=insert_it.get_line();
if(line_nr>0) { if(line_nr>0) {
@ -442,6 +457,9 @@ bool Source::ClangViewParse::on_scroll_event(GdkEventScroll* event) {
//Clang indentation //Clang indentation
//TODO: replace indentation methods with a better implementation or maybe use libclang //TODO: replace indentation methods with a better implementation or maybe use libclang
bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { 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(); auto config=Singleton::Config::source();
const std::regex bracket_regex(std::string("^(")+config->tab_char+"*).*\\{ *$"); 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) *\\(.*[^;}] *$"); 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<std::string, unsigned> 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;
};
} }
//////////////// ////////////////

5
juci/source.h

@ -49,11 +49,16 @@ public:
View(const std::string& file_path, const std::string& project_path); View(const std::string& file_path, const std::string& project_path);
std::string get_line(size_t line_number); std::string get_line(size_t line_number);
std::string get_line_before_insert(); std::string get_line_before_insert();
void scroll_to_insert();
std::string file_path; std::string file_path;
std::string project_path; std::string project_path;
Gtk::TextIter search_start, search_end; Gtk::TextIter search_start, search_end;
std::function<std::pair<std::string, unsigned>()> get_declaration_location;
protected: protected:
bool on_key_press_event(GdkEventKey* key); bool on_key_press_event(GdkEventKey* key);
private:
Glib::Dispatcher scroll_to_insert_dispatcher;
}; // class View }; // class View
class GenericView : public View { class GenericView : public View {

18
juci/sourcefile.h

@ -4,20 +4,18 @@
#include <string> #include <string>
#include <vector> #include <vector>
using namespace std;
class sourcefile { class sourcefile {
public: public:
explicit sourcefile(const string &filename); explicit sourcefile(const std::string &filename);
vector<string> get_lines(); std::vector<std::string> get_lines();
string get_content(); std::string get_content();
string get_line(int line_number); std::string get_line(int line_number);
int save(const string &text); int save(const std::string &text);
private: private:
void open(const string &filename); void open(const std::string &filename);
vector<string> lines; std::vector<std::string> lines;
string filename; std::string filename;
}; };
#endif // JUCI_SOURCEFILE_H_ #endif // JUCI_SOURCEFILE_H_

6
juci/terminal.cc

@ -87,8 +87,10 @@ int Terminal::Controller::print(std::string message){
INFO("Terminal: PrintMessage"); INFO("Terminal: PrintMessage");
view.text_view.get_buffer()->insert(view.text_view.get_buffer()->end(), "> "+message); 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()); auto mark_end=view.text_view.get_buffer()->create_mark(view.text_view.get_buffer()->end());
view.text_view.scroll_to(mark_end); view.text_view.scroll_to(view.text_view.get_buffer()->get_insert());
return mark_end->get_iter().get_line(); 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){ void Terminal::Controller::print(int line_nr, std::string message){

2
juci/window.cc

@ -148,7 +148,7 @@ void Window::OnOpenFile() {
switch (result) { switch (result) {
case(Gtk::RESPONSE_OK): { case(Gtk::RESPONSE_OK): {
std::string path = dialog.get_filename(); std::string path = dialog.get_filename();
Singleton::notebook()->OnOpenFile(path); Singleton::notebook()->open_file(path);
break; break;
} }
case(Gtk::RESPONSE_CANCEL): { case(Gtk::RESPONSE_CANCEL): {

Loading…
Cancel
Save