diff --git a/juci/CMakeLists.txt b/juci/CMakeLists.txt index 5cd0026..b7f4dfa 100644 --- a/juci/CMakeLists.txt +++ b/juci/CMakeLists.txt @@ -1,12 +1,17 @@ cmake_minimum_required (VERSION 2.8.4) set(project_name juci) set(module juci_to_python_api) - project (${project_name}) add_definitions(-DBOOST_LOG_DYN_LINK) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -std=c++11 -pthread") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake/Modules/") +#You are of course using Homebrew: +if(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L/usr/local/opt/gettext/lib -I/usr/local/opt/gettext/include -undefined dynamic_lookup") #TODO: fix this + set(CMAKE_MACOSX_RPATH 1) + set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig") +endif() INCLUDE(FindPkgConfig) message("Searcing for libclang") @@ -83,6 +88,14 @@ else() message("Gtkmm link dirs ${GTKMM_LIBRARIES}") message(FATAL_ERROR "The gtkmm libraries are required. Quitting.") endif() + +pkg_check_modules(GTKSVMM gtksourceviewmm-3.0) +if(${GTKSVMM_FOUND}) + message("Gtksourceviewmm libraries found. Continuing") +else() + message(FATAL_ERROR "The gtksourceviewmm libraries are required. Quitting.") +endif() + # name of the executable on Windows will be example.exe add_executable(${project_name} #list of every needed file to create the executable @@ -124,11 +137,13 @@ include_directories( ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} + ${GTKSVMM_INCLUDE_DIRS} ${LCL_INCLUDE_DIRS} ${LIBCLANG_INCLUDE_DIRS} ) link_directories( ${GTKMM_LIBRARY_DIRS} + ${GTKSVMM_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${PYTHON_INCLUDE_DIRS} ${LCL_LIBRARY_DIRS} @@ -139,6 +154,6 @@ set_target_properties(${module} PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/") target_link_libraries(${module} ${PYTHON_LIBRARIES} ${Boost_LIBRARIES}) #executable: -target_link_libraries(${project_name} ${LIVCLANG_LIBRARIES} ${LCL_LIBRARIES} ${GTKMM_LIBRARIES} ${Boost_LIBRARIES} ${PYTHON_LIBRARIES}) +target_link_libraries(${project_name} ${LIVCLANG_LIBRARIES} ${LCL_LIBRARIES} ${GTKMM_LIBRARIES} ${GTKSVMM_LIBRARIES} ${Boost_LIBRARIES} ${PYTHON_LIBRARIES}) diff --git a/juci/api.cc b/juci/api.cc index ee5a634..cf1099d 100644 --- a/juci/api.cc +++ b/juci/api.cc @@ -12,7 +12,9 @@ PluginApi::PluginApi(Menu::Controller& menu_ctl_, menu_ = &menu_ctl_; notebook_ = ¬ebook_ctl_; DEBUG("Initiating plugins(from plugins.py).."); - InitPlugins(); +#ifndef __APPLE__ + InitPlugins(); //TODO: fix this +#endif DEBUG("Plugins initiated.."); } diff --git a/juci/notebook.cc b/juci/notebook.cc index 909ed36..b634762 100644 --- a/juci/notebook.cc +++ b/juci/notebook.cc @@ -1,6 +1,7 @@ #include #include "notebook.h" #include "logging.h" +#include Notebook::Model::Model() { cc_extension_ = ".cpp"; @@ -163,6 +164,77 @@ bool Notebook::Controller:: OnMouseRelease(GdkEventButton* button) { return false; } +bool Notebook::Controller::OnKeyPress(GdkEventKey* key) { + //Indent as in previous line, and indent left after if/else/etc + if(key->keyval==GDK_KEY_Return && key->state==0) { + Gtk::TextIter insert_it = Buffer(text_vec_.at(CurrentPage()))->get_insert()->get_iter(); + Gtk::TextIter line_it = Buffer(text_vec_.at(CurrentPage()))->get_iter_at_line(insert_it.get_line()); + std::string line(Buffer(text_vec_.at(CurrentPage()))->get_text(line_it, insert_it)); + std::smatch sm; + const std::regex bracket_regex("^( *).*\\{ *$"); + const std::regex no_bracket_statement_regex("^( *)(if|else|else if|try|catch|while)[^\\}]*$"); + const std::regex no_bracket_regex("^( *).*$"); + if(std::regex_match(line, sm, bracket_regex)) { + Buffer(text_vec_.at(CurrentPage()))->insert_at_cursor("\n"+sm[1].str()+" "); + } + else if(std::regex_match(line, sm, no_bracket_statement_regex)) { + Buffer(text_vec_.at(CurrentPage()))->insert_at_cursor("\n"+sm[1].str()+" "); + } + else if(std::regex_match(line, sm, no_bracket_regex)) { + Buffer(text_vec_.at(CurrentPage()))->insert_at_cursor("\n"+sm[1].str()); + } + CurrentTextView().scroll_to(Buffer(text_vec_.at(CurrentPage()))->get_insert()); + return true; + } + //Indent right when clicking tab, no matter where in the line the cursor is. Also works on selected text. + if(key->keyval==GDK_KEY_Tab && key->state==0) { + Gtk::TextIter selection_start, selection_end; + Buffer(text_vec_.at(CurrentPage()))->get_selection_bounds(selection_start, selection_end); + int line_start=selection_start.get_line(); + int line_end=selection_end.get_line(); + for(int line=line_start;line<=line_end;line++) { + Gtk::TextIter line_it = Buffer(text_vec_.at(CurrentPage()))->get_iter_at_line(line); + Buffer(text_vec_.at(CurrentPage()))->insert(line_it, " "); + } + return true; + } + //Indent left when clicking shift-tab, no matter where in the line the cursor is. Also works on selected text. + else if((key->keyval==GDK_KEY_ISO_Left_Tab || key->keyval==GDK_KEY_Tab) && key->state==GDK_SHIFT_MASK) { + Gtk::TextIter selection_start, selection_end; + Buffer(text_vec_.at(CurrentPage()))->get_selection_bounds(selection_start, selection_end); + int line_start=selection_start.get_line(); + int line_end=selection_end.get_line(); + for(int line=line_start;line<=line_end;line++) { + Gtk::TextIter line_it = Buffer(text_vec_.at(CurrentPage()))->get_iter_at_line(line); + Gtk::TextIter line_plus_it=line_it; + line_plus_it++; + line_plus_it++; + std::string start(Buffer(text_vec_.at(CurrentPage()))->get_text(line_it, line_plus_it)); + if(start==" ") + Buffer(text_vec_.at(CurrentPage()))->erase(line_it, line_plus_it); + } + return true; + } + //Indent left when writing } on a new line + else if(key->keyval==GDK_KEY_braceright) { + Gtk::TextIter insert_it = Buffer(text_vec_.at(CurrentPage()))->get_insert()->get_iter(); + Gtk::TextIter line_it = Buffer(text_vec_.at(CurrentPage()))->get_iter_at_line(insert_it.get_line()); + Gtk::TextIter line_plus_it=line_it; + line_plus_it++; + line_plus_it++; + std::string start(Buffer(text_vec_.at(CurrentPage()))->get_text(line_it, line_plus_it)); + std::string line(Buffer(text_vec_.at(CurrentPage()))->get_text(line_it, insert_it)); + for(auto &c: line) { + if(c!=' ') + return false; + } + if(start==" ") + Buffer(text_vec_.at(CurrentPage()))->erase(line_it, line_plus_it); + return false; + } + return false; +} + bool Notebook::Controller::OnKeyRelease(GdkEventKey* key) { return GeneratePopup(key->keyval); } @@ -265,29 +337,11 @@ bool Notebook::Controller::GeneratePopup(int key_id) { return true; } -bool Notebook::Controller::ScrollEventCallback(GdkEventScroll* scroll_event) { - int page = CurrentPage(); - int direction_y = scroll_event->delta_y; - int direction_x = scroll_event->delta_x; - - Glib::RefPtr adj = - scrolledtext_vec_.at(page)-> - get_vscrollbar()->get_adjustment(); - if ( direction_y != 0 ) { - int dir_val = direction_y == -1 ? -model_.scrollvalue_:+model_.scrollvalue_; - adj->set_value(adj->get_value()+dir_val); - text_vec_.at(page)->view().set_vadjustment(adj); - linenumbers_vec_.at(page)->view().set_vadjustment(adj); - } - return true; -} Notebook::Controller::~Controller() { INFO("Notebook destructor"); for (auto &i : text_vec_) delete i; - for (auto &i : linenumbers_vec_) delete i; for (auto &i : editor_vec_) delete i; for (auto &i : scrolledtext_vec_) delete i; - for (auto &i : scrolledline_vec_) delete i; } Gtk::Paned& Notebook::Controller::view() { @@ -326,27 +380,15 @@ void Notebook::Controller::OnOpenFile(std::string path) { Notebook().show_all_children(); Notebook().set_current_page(Pages()-1); Notebook().set_focus_child(text_vec_.back()->view()); - OnBufferChange(); text_vec_.back()->set_is_changed(false); } void Notebook::Controller::OnCreatePage() { INFO("Notebook create page"); text_vec_.push_back(new Source::Controller(source_config(), this)); - linenumbers_vec_.push_back(new Source::Controller(source_config(), this)); - scrolledline_vec_.push_back(new Gtk::ScrolledWindow()); scrolledtext_vec_.push_back(new Gtk::ScrolledWindow()); editor_vec_.push_back(new Gtk::HBox()); scrolledtext_vec_.back()->add(text_vec_.back()->view()); - scrolledline_vec_.back()->add(linenumbers_vec_.back()->view()); - linenumbers_vec_.back()->view().get_buffer()->set_text("1 "); - linenumbers_vec_.back()->view().override_color(Gdk::RGBA("Black")); - linenumbers_vec_.back()-> - view().set_justification(Gtk::Justification::JUSTIFY_RIGHT); - scrolledline_vec_.back()->get_vscrollbar()->hide(); - linenumbers_vec_.back()->view().set_editable(false); - linenumbers_vec_.back()->view().set_sensitive(false); - editor_vec_.back()->pack_start(*scrolledline_vec_.back(), false, false); editor_vec_.back()->pack_start(*scrolledtext_vec_.back(), true, true); TextViewHandlers(text_vec_.back()->view()); } @@ -360,14 +402,10 @@ void Notebook::Controller::OnCloseCurrentPage() { int page = CurrentPage(); Notebook().remove_page(page); delete text_vec_.at(page); - delete linenumbers_vec_.at(page); delete scrolledtext_vec_.at(page); - delete scrolledline_vec_.at(page); delete editor_vec_.at(page); text_vec_.erase(text_vec_.begin()+ page); - linenumbers_vec_.erase(linenumbers_vec_.begin()+page); scrolledtext_vec_.erase(scrolledtext_vec_.begin()+page); - scrolledline_vec_.erase(scrolledline_vec_.begin()+page); editor_vec_.erase(editor_vec_.begin()+page); } } @@ -455,36 +493,6 @@ void Notebook::Controller::Search(bool forward) { } } -void Notebook::Controller::OnBufferChange() { - int page = CurrentPage(); - int text_nr = Buffer(text_vec_.at(page))->get_line_count(); - int line_nr = Buffer(linenumbers_vec_.at(page))->get_line_count(); - while (line_nr < text_nr) { - line_nr++; - Buffer(linenumbers_vec_.at(page))-> - insert(Buffer(linenumbers_vec_.at(page))->end(), - "\n"+std::to_string(line_nr)+" "); - } - while (line_nr > text_nr) { - Gtk::TextIter iter = - Buffer(linenumbers_vec_.at(page))->get_iter_at_line(line_nr); - iter.backward_char(); - line_nr--; - Buffer(linenumbers_vec_.at(page))-> - erase(iter, - Buffer(linenumbers_vec_.at(page))->end()); - } - if (Buffer(text_vec_.at(page))->get_insert()->get_iter().starts_line() && - Buffer(text_vec_.at(page))->get_insert()->get_iter().get_line() == - Buffer(text_vec_.at(page))->end().get_line()) { - GdkEventScroll* scroll = new GdkEventScroll; - scroll->delta_y = 1.0; - scroll->delta_x = 0.0; - ScrollEventCallback(scroll); - delete scroll; - } - text_vec_.at(page)->set_is_changed(true); -} void Notebook::Controller ::OnDirectoryNavigation(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column) { @@ -529,10 +537,6 @@ Gtk::Notebook& Notebook::Controller::Notebook() { void Notebook::Controller::BufferChangeHandler(Glib::RefPtr buffer) { - buffer->signal_changed().connect( - [this]() { - OnBufferChange(); - }); buffer->signal_end_user_action().connect( [this]() { //UpdateHistory(); @@ -540,14 +544,12 @@ void Notebook::Controller::BufferChangeHandler(Glib::RefPtr } void Notebook::Controller::TextViewHandlers(Gtk::TextView& textview) { - textview.get_buffer()->signal_changed().connect( - [this]() { - OnBufferChange(); - }); - textview.signal_button_release_event(). connect(sigc::mem_fun(*this, &Notebook::Controller::OnMouseRelease), false); + textview.signal_key_press_event(). + connect(sigc::mem_fun(*this, &Notebook::Controller::OnKeyPress), false); + textview.signal_key_release_event(). connect(sigc::mem_fun(*this, &Notebook::Controller::OnKeyRelease), false); } diff --git a/juci/notebook.h b/juci/notebook.h index e2521a9..e7681ca 100644 --- a/juci/notebook.h +++ b/juci/notebook.h @@ -71,6 +71,7 @@ namespace Notebook { void Search(bool forward); Source::Config& source_config() { return source_config_; } bool OnMouseRelease(GdkEventButton* button); + bool OnKeyPress(GdkEventKey* key); bool OnKeyRelease(GdkEventKey* key); std::string OnSaveFileAs(); bool LegalExtension(std::string extension); @@ -101,8 +102,8 @@ namespace Notebook { bool is_new_file_; Entry::Controller entry_; - std::vector text_vec_, linenumbers_vec_; - std::vector scrolledtext_vec_, scrolledline_vec_; + std::vector text_vec_; + std::vector scrolledtext_vec_; std::vector editor_vec_; std::list listTargets_; Gtk::TextIter search_match_end_; diff --git a/juci/source.cc b/juci/source.cc index c88d2a9..9e54688 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -5,6 +5,7 @@ #include #include "notebook.h" #include "logging.h" +#include Source::Location:: Location(int line_number, int column_offset) : @@ -28,6 +29,9 @@ Range(const Source::Range &org) : ////////////// Source::View::View() { override_font(Pango::FontDescription("Monospace")); + set_show_line_numbers(true); + set_highlight_current_line(true); + set_smart_home_end(Gsv::SMART_HOME_END_ALWAYS); } string Source::View::GetLine(const Gtk::TextIter &begin) { @@ -114,7 +118,7 @@ InitSyntaxHighlighting(const std::string &filepath, int end_offset, clang::Index *index) { set_project_path(project_path); - std::vector arguments = get_compilation_commands(); + std::vector arguments = get_compilation_commands(); tu_ = clang::TranslationUnit(index, filepath, arguments, @@ -201,16 +205,16 @@ const Source::Config& Source::Model::config() const { return config_; } -std::vector Source::Model:: +std::vector Source::Model:: get_compilation_commands() { clang::CompilationDatabase db(project_path()+"/"); clang::CompileCommands commands(file_path(), &db); std::vector cmds = commands.get_commands(); - std::vector arguments; + std::vector arguments; for (auto &i : cmds) { std::vector lol = i.get_command_as_args(); for (int a = 1; a < lol.size()-4; a++) { - arguments.emplace_back(lol[a].c_str()); + arguments.emplace_back(lol[a]); } } return arguments; @@ -353,44 +357,37 @@ void Source::Controller::OnOpenFile(const string &filepath) { view().OnUpdateSyntax(model().ExtractTokens(start_offset, end_offset), model().config()); + //OnUpdateSyntax must happen in main thread, so the parse-thread + //sends a signal to the main thread that it is to call the following function: + parsing_done.connect([this](){ + INFO("Updating syntax"); + view(). + OnUpdateSyntax(model().ExtractTokens(0, buffer()->get_text().size()), + model().config()); + INFO("Syntax updated"); + }); + buffer()->signal_end_user_action().connect([this]() { - if (!go) { - std::thread parse([this]() { - if (parsing.try_lock()) { - INFO("Starting parsing"); - while (true) { - const std::string raw = buffer()->get_text().raw(); - std::map buffers; - notebook_->MapBuffers(&buffers); - buffers[model().file_path()] = raw; - if (model().ReParse(buffers) == 0 && - raw == buffer()->get_text().raw()) { - syntax.lock(); - go = true; - syntax.unlock(); - break; - } - } - parsing.unlock(); - INFO("Parsing completed"); - } - }); - parse.detach(); - } - }); - - buffer()->signal_begin_user_action().connect([this]() { - if (go) { - syntax.lock(); - INFO("Updating syntax"); - view(). - OnUpdateSyntax(model().ExtractTokens(0, buffer()->get_text().size()), - model().config()); - go = false; - INFO("Syntax updated"); - syntax.unlock(); + std::thread parse([this]() { + if (parsing.try_lock()) { + INFO("Starting parsing"); + while (true) { + const std::string raw = buffer()->get_text().raw(); + std::map buffers; + notebook_->MapBuffers(&buffers); + buffers[model().file_path()] = raw; + if (model().ReParse(buffers) == 0 && + raw == buffer()->get_text().raw()) { + break; + } + } + parsing.unlock(); + parsing_done(); + INFO("Parsing completed"); } }); + parse.detach(); + }); } } Glib::RefPtr Source::Controller::buffer() { diff --git a/juci/source.h b/juci/source.h index ee7ebbf..89aa1f2 100644 --- a/juci/source.h +++ b/juci/source.h @@ -8,6 +8,7 @@ #include #include #include +#include "gtksourceviewmm.h" namespace Notebook { class Controller; @@ -60,7 +61,7 @@ namespace Source { int kind_; }; - class View : public Gtk::TextView { + class View : public Gsv::View { public: View(); virtual ~View() { } @@ -135,7 +136,7 @@ namespace Source { int token_kind); void HighlightCursor(clang::Token *token, std::vector *source_ranges); - std::vector get_compilation_commands(); + std::vector get_compilation_commands(); }; class Controller { @@ -162,9 +163,8 @@ namespace Source { private: void OnLineEdit(); void OnSaveFile(); - std::mutex syntax; std::mutex parsing; - bool go = false; + Glib::Dispatcher parsing_done; bool is_saved_ = false; bool is_changed_ = false;