diff --git a/juci/api.h b/juci/api.h index eb17fc5..46f3f98 100644 --- a/juci/api.h +++ b/juci/api.h @@ -55,9 +55,9 @@ namespace libjuci { const std::string plugin_path, const std::string menu_keybinding); void AddMenuXml(const std::string plugin_name, - const string parent_menu); + const std::string parent_menu); void AddSubMenuXml(const std::string plugin_name, - const string parent_menu); + const std::string parent_menu); ////////////////////////////// //// Boost.Python methods //// ////////////////////////////// diff --git a/juci/config.cc b/juci/config.cc index 3e8a264..689fd19 100644 --- a/juci/config.cc +++ b/juci/config.cc @@ -17,16 +17,14 @@ void MainConfig::GenerateSource() { boost::property_tree::ptree colors_json = source_json.get_child("colors"); for ( auto &i : colors_json ) { source_cfg_.InsertTag(i.first, i.second.get_value()); - std::cout << "inserting tag, key: " << i.first << " value: " << i.second.get_value() << std::endl; } for ( auto &i : syntax_json ) { source_cfg_.InsertType(i.first, i.second.get_value()); - std::cout << "inserting type, key: " << i.first << " value: " << i.second.get_value() << std::endl; } } void MainConfig::GenerateKeybindings() { - string line; + std::string line; std::ifstream menu_xml("menu.xml"); if (menu_xml.is_open()) { while (getline(menu_xml, line)) { diff --git a/juci/config.json b/juci/config.json index 68bb33e..3305cf8 100644 --- a/juci/config.json +++ b/juci/config.json @@ -24,7 +24,11 @@ "new_cc_file": "c", "close_tab": "w", "open_folder": "o", - "edit_undo": "z" + "edit_undo": "z", + "save": "s", + "save_as": "s", + "compile_and_run": "r>", + "compile": "r" }, "directoryfilter": { "ignore": [ diff --git a/juci/menu.cc b/juci/menu.cc index 880d7df..4fba192 100644 --- a/juci/menu.cc +++ b/juci/menu.cc @@ -27,6 +27,8 @@ Menu::Controller::Controller(Keybindings::Controller& keybindings) : [this]() { OnWindowSplitWindow(); }); + keybindings_.action_group_menu()->add(Gtk::Action::create("ProjectMenu", + "P_roject")); keybindings_.action_group_menu()->add(Gtk::Action::create("PluginMenu", "_Plugins")); keybindings_.action_group_menu()->add(Gtk::Action::create("HelpMenu", diff --git a/juci/menu.xml b/juci/menu.xml index f427348..eb7bd04 100644 --- a/juci/menu.xml +++ b/juci/menu.xml @@ -7,7 +7,9 @@ - + + + @@ -19,6 +21,10 @@ + + + + diff --git a/juci/notebook.cc b/juci/notebook.cc index 6ba31f7..28a1e2e 100644 --- a/juci/notebook.cc +++ b/juci/notebook.cc @@ -1,4 +1,5 @@ #include "notebook.h" +#include Notebook::Model::Model() { cc_extension_ = ".cc"; @@ -6,21 +7,25 @@ Notebook::Model::Model() { scrollvalue_ = 50; } -Notebook::View::View() { +Notebook::View::View() : notebook_() { view_.pack2(notebook_); view_.set_position(120); } -Notebook::Controller::Controller(Keybindings::Controller& keybindings, +Notebook::Controller::Controller(Gtk::Window* window, Keybindings::Controller& keybindings, Source::Config& source_cfg, Directories::Config& dir_cfg) : source_config_(source_cfg), - directories_(dir_cfg) { + directories_(dir_cfg), + index_(0, 1) { + window_ = window; OnNewPage("juCi++"); refClipboard_ = Gtk::Clipboard::get(); + ispopup = false; view().pack1(directories_.widget(), true, true); CreateKeybindings(keybindings); - } // Constructor +} // Constructor + void Notebook::Controller::CreateKeybindings(Keybindings::Controller &keybindings) { @@ -100,15 +105,8 @@ void Notebook::Controller::CreateKeybindings(Keybindings::Controller Gtk::AccelKey(keybindings.config_ .key_map()["edit_undo"]), [this]() { - OnUndo(); - }); - - keybindings.action_group_hidden()-> - add(Gtk::Action::create("EditPaste", - Gtk::Stock::PASTE), - [this]() { - OnEditPaste(); - }); + //OnUndo(); + }); entry_.view_.entry().signal_activate(). connect( [this]() { @@ -142,53 +140,108 @@ void Notebook::Controller::CreateKeybindings(Keybindings::Controller }); } -void Notebook::Controller::GeneratePopup(std::vector items) { +bool Notebook::Controller:: OnMouseRelease(GdkEventButton* button) { + if (button->button == 1 && ispopup) { + popup_.response(Gtk::RESPONSE_DELETE_EVENT); + return true; + } + return false; +} + +bool Notebook::Controller::OnKeyRelease(GdkEventKey* key) { + return GeneratePopup(key->keyval); +} + +bool Notebook::Controller::GeneratePopup(int key_id) { + // Get function to fill popup with suggests item vector under is for testing + Gtk::TextIter beg = CurrentTextView().get_buffer()->get_insert()->get_iter(); + Gtk::TextIter end = CurrentTextView().get_buffer()->get_insert()->get_iter(); + Gtk::TextIter tmp = CurrentTextView().get_buffer()->get_insert()->get_iter(); + Gtk::TextIter tmp1 = CurrentTextView().get_buffer()->get_insert()->get_iter(); + Gtk::TextIter line = + CurrentTextView().get_buffer()->get_iter_at_line(tmp.get_line()); + if (end.backward_char() && end.backward_char()) { + bool illegal_chars = + end.backward_search("\"", Gtk::TEXT_SEARCH_VISIBLE_ONLY, tmp, tmp1, line) + || + end.backward_search("//", Gtk::TEXT_SEARCH_VISIBLE_ONLY, tmp, tmp1, line); + if (illegal_chars) { + return false; + } + std::string c = text_vec_[CurrentPage()]->buffer()->get_text(end, beg); + switch (key_id) { + case 46: + break; + case 58: + if (c != "::") return false; + break; + case 60: + if (c != "->") return false; + break; + case 62: + if (c != "->") return false; + break; + default: + return false; + } + } else { + return false; + } + std::vector acdata; + text_vec_.at(CurrentPage())-> + GetAutoCompleteSuggestions(beg.get_line()+1, + beg.get_line_offset()+2, + &acdata); + std::map items; + for (auto &data : acdata) { + std::stringstream ss; + std::string return_value; + for (auto &chunk : data.chunks_) { + switch (chunk.kind()) { + case clang::CompletionChunk_ResultType: + return_value = chunk.chunk(); + break; + case clang::CompletionChunk_Informative: + break; + default: + ss << chunk.chunk(); + break; + } + } + items[ss.str() + " --> " + return_value] = ss.str(); + } + // Replace over with get suggestions from zalox! OVER IS JUST FOR TESTING Gtk::ScrolledWindow popup_scroll_; Gtk::ListViewText listview_(1, false, Gtk::SelectionMode::SELECTION_SINGLE); - Gtk::Dialog popup_("", true); - listview_.set_enable_search(false); + popup_scroll_.set_policy(Gtk::PolicyType::POLICY_NEVER, + Gtk::PolicyType::POLICY_NEVER); + listview_.set_enable_search(true); + listview_.set_headers_visible(false); listview_.set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_NATURAL); listview_.set_activate_on_single_click(true); - listview_.signal_row_activated(). - connect([this, &listview_, &popup_](const Gtk::TreeModel::Path& path, - Gtk::TreeViewColumn*) { - std::string t = listview_.get_text(listview_.get_selected()[0]); - CurrentTextView().get_buffer()->insert_at_cursor(t); - popup_.response(Gtk::RESPONSE_DELETE_EVENT); - }); - for (auto &i : items) listview_.append(i); - listview_.set_headers_visible(false); + if (items.empty()) { + items["No suggestions found..."] = ""; + } + for (auto &i : items) { + listview_.append(i.first); + } popup_scroll_.add(listview_); popup_.get_vbox()->pack_start(popup_scroll_); - popup_.set_size_request(80, 80); + popup_.set_transient_for(*window_); popup_.show_all(); - Gdk::Rectangle temp1, temp2; - CurrentTextView(). - get_cursor_locations( - CurrentTextView(). - get_buffer()->get_insert()-> - get_iter(), temp1, temp2); - - - int x = temp1.get_x(); - int y = temp1.get_y(); - text_vec_.at(CurrentPage())-> - view().buffer_to_window_coords( - Gtk::TextWindowType::TEXT_WINDOW_WIDGET, - temp2.get_x(), - temp2.get_y(), - x, y); - - int widht = Notebook().get_width()-88; - int height = Notebook().get_height()-180; - if (x > widht) { - x = widht; } - if (y > height) { - y = height; - } - popup_.move(x, y+88); + int popup_x = popup_.get_width(); + int popup_y = items.size() * 20; + PopupSetSize(popup_scroll_, popup_x, popup_y); + int x, y; + FindPopupPosition(CurrentTextView(), popup_x, popup_y, x, y); + popup_.move(x, y+15); + PopupSelectHandler(popup_, listview_, &items); + ispopup = true; popup_.run(); + popup_.hide(); + ispopup = false; + return true; } bool Notebook::Controller::ScrollEventCallback(GdkEventScroll* scroll_event) { @@ -229,28 +282,35 @@ void Notebook::Controller::OnNewPage(std::string name) { Notebook().show_all_children(); Notebook().set_current_page(Pages()-1); Notebook().set_focus_child(text_vec_.at(Pages()-1)->view()); - NewBufferHistory(text_vec_.back()->view().get_buffer()); + +} + +void Notebook::Controller:: +MapBuffers(std::map *buffers) { + for (auto &buffer : text_vec_) { + buffers->operator[](buffer->model().file_path()) = + buffer->buffer()->get_text().raw(); + } } void Notebook::Controller::OnOpenFile(std::string path) { OnCreatePage(); text_vec_.back()->OnOpenFile(path); + text_vec_.back()->set_is_saved(true); unsigned pos = path.find_last_of("/\\"); Notebook().append_page(*editor_vec_.back(), path.substr(pos+1)); Notebook().show_all_children(); - std::cout << "setting current page"<< std::endl; Notebook().set_current_page(Pages()-1); - std::cout << "current page set" << std::endl; Notebook().set_focus_child(text_vec_.back()->view()); OnBufferChange(); - NewBufferHistory(text_vec_.back()->view().get_buffer()); + } void Notebook::Controller::OnCreatePage() { - text_vec_.push_back(new Source::Controller(source_config())); - linenumbers_vec_.push_back(new Source::Controller(source_config())); + 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()); @@ -265,7 +325,7 @@ void Notebook::Controller::OnCreatePage() { 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); - BufferChangeHandler(text_vec_.back()->view().get_buffer()); + TextViewHandlers(text_vec_.back()->view()); } void Notebook::Controller::OnCloseCurrentPage() { @@ -396,24 +456,6 @@ void Notebook::Controller::OnBufferChange() { ScrollEventCallback(scroll); delete scroll; } - Gtk::TextIter start, end; - std::string word, last_word; - start = Buffer(text_vec_.at(page))->get_insert()->get_iter(); - end = Buffer(text_vec_.at(page))->get_insert()->get_iter(); - start.backward_char(); - word = Buffer(text_vec_.at(page))->get_text(start, end); - last_word = Buffer(text_vec_.at(page))->get_text(--start, --end); - if (word == ".") { - // TODO(Forgie) Zalox,Forgie) Remove TEST - UpdateHistory(); - std::vector TEST; - TEST.push_back("toString()"); - TEST.push_back("toLower()"); - TEST.push_back("toUpper()"); - TEST.push_back("fuckOFF()"); - TEST.push_back("fuckOFF()"); - GeneratePopup(TEST); - } } void Notebook::Controller ::OnDirectoryNavigation(const Gtk::TreeModel::Path& path, @@ -464,91 +506,142 @@ void Notebook::Controller::BufferChangeHandler(Glib::RefPtr }); buffer->signal_end_user_action().connect( [this]() { - UpdateHistory(); + //UpdateHistory(); }); } +void Notebook::Controller::TextViewHandlers(Gtk::TextView& textview) { + textview.get_buffer()->signal_changed().connect( + [this]() { + OnBufferChange(); + }); -// History methods -void Notebook::Controller:: -NewBufferHistory(Glib::RefPtr buffer) { - Glib::ustring text = buffer->get_text(); - std::deque queue; - queue.push_back(text); - history_.push_back(queue); -} + textview.signal_button_release_event(). + connect(sigc::mem_fun(*this, &Notebook::Controller::OnMouseRelease), false); -void Notebook::Controller::UpdateHistory() { - Gtk::TextIter start, end; - std::string word, last_word; - int page = CurrentPage(); - start = Buffer(text_vec_.at(page))->get_insert()->get_iter(); - end = Buffer(text_vec_.at(page))->get_insert()->get_iter(); - start.backward_char(); - word = Buffer(text_vec_.at(page))->get_text(start, end); - last_word = Buffer(text_vec_.at(page))->get_text(--start, --end); - /*if(word == "." - || word == " " - || word == ";" - || word == ":" - || word == "}" - || word == ")" - || word == "]" - || word == ">") { - if(last_word != "." - && last_word != " " - && last_word != ";" - && last_word != ":" - && last_word != "}" - && last_word != ")" - && last_word != "]" - && last_word != ">") {*/ - AppendBufferState(); - // } - // } -} -void Notebook::Controller:: -AppendBufferState() { - Glib::ustring text = CurrentTextView().get_buffer()->get_text(); - std::cout << "buf.size(): " << text.size() << std::endl; - if(BufferHistory().size() < kHistorySize) { - BufferHistory().push_back(text); - } else { - BufferHistory().pop_front(); - BufferHistory().push_back(text); - } + textview.signal_key_release_event(). + connect(sigc::mem_fun(*this, &Notebook::Controller::OnKeyRelease), false); } -void Notebook::Controller::RemoveBufferHistory() { - history_.erase(history_.begin()+CurrentPage()); +void Notebook::Controller::PopupSelectHandler(Gtk::Dialog &popup, + Gtk::ListViewText &listview, + std::map + *items) { + listview.signal_row_activated(). + connect([this, &listview, &popup, items](const Gtk::TreeModel::Path& path, + Gtk::TreeViewColumn*) { + std::string selected = items-> + at(listview.get_text(listview.get_selected()[0])); + CurrentTextView().get_buffer()->insert_at_cursor(selected); + popup.response(Gtk::RESPONSE_DELETE_EVENT); + }); } - -std::deque& Notebook::Controller::BufferHistory() { - return history_.at(CurrentPage()); +void Notebook::Controller::PopupSetSize(Gtk::ScrolledWindow &scroll, + int ¤t_x, + int ¤t_y) { + int textview_x = CurrentTextView().get_width(); + int textview_y = 150; + bool is_never_scroll_x = true; + bool is_never_scroll_y = true; + if (current_x > textview_x) { + current_x = textview_x; + is_never_scroll_x = false; + } + if (current_y > textview_y) { + current_y = textview_y; + is_never_scroll_y = false; + } + scroll.set_size_request(current_x, current_y); + if (!is_never_scroll_x && !is_never_scroll_y) { + scroll.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC, + Gtk::PolicyType::POLICY_AUTOMATIC); + } else if (!is_never_scroll_x && is_never_scroll_y) { + scroll.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC, + Gtk::PolicyType::POLICY_NEVER); + } else if (is_never_scroll_x && !is_never_scroll_y) { + scroll.set_policy(Gtk::PolicyType::POLICY_NEVER, + Gtk::PolicyType::POLICY_AUTOMATIC); + } } -Glib::ustring& Notebook::Controller::LastBufferState() { - if(BufferHistory().size() > 1) { - BufferHistory().pop_back(); - }else { - std::cout << "Reached end of history, can't undo any more" << std::endl; +void Notebook::Controller::FindPopupPosition(Gtk::TextView& textview, + int popup_x, + int popup_y, + int &x, + int &y) { + Gdk::Rectangle temp1, temp2; + textview.get_cursor_locations( + CurrentTextView(). + get_buffer()->get_insert()-> + get_iter(), temp1, temp2); + int textview_edge_x = 0; + int textview_edge_y = 0; + textview.buffer_to_window_coords( + Gtk::TextWindowType::TEXT_WINDOW_WIDGET, + temp1.get_x(), + temp1.get_y(), + x, y); + Glib::RefPtr gdkw = + CurrentTextView().get_window(Gtk::TextWindowType::TEXT_WINDOW_WIDGET); + gdkw->get_origin(textview_edge_x, textview_edge_y); + + x += textview_edge_x; + y += textview_edge_y; + if ((textview_edge_x-x)*-1 > textview.get_width()-popup_x) { + x -= popup_x; + if (x < textview_edge_x) x = textview_edge_x; + } + if ((textview_edge_y-y)*-1 > textview.get_height()-popup_y) { + y -= (popup_y+14) + 15; + if (x < textview_edge_y) y = textview_edge_y +15; } - return BufferHistory().back(); } -void Notebook::Controller::OnUndo() { - // PrintQue(); - // std::cout << "UNDOING SOMETHING TERRIBLE" << std::endl; - Glib::RefPtr buf = CurrentTextView().get_buffer(); - buf->set_text(LastBufferState()); - std::cout << "Undoing.."<< std::endl; - PrintQue(); +void Notebook::Controller:: OnSaveFile() { + if (text_vec_.at(CurrentPage())->is_saved()) { + std::ofstream file; + file.open (text_vec_.at(CurrentPage())->path()); + file << CurrentTextView().get_buffer()->get_text(); + file.close(); + } else { + std::string path = OnSaveFileAs(); + if (path != "") { + std::ofstream file; + file.open (path); + file << CurrentTextView().get_buffer()->get_text(); + file.close(); + text_vec_.at(CurrentPage())->set_file_path(path); + text_vec_.at(CurrentPage())->set_is_saved(true); + } + } +} + + +std::string Notebook::Controller::OnSaveFileAs(){ + Gtk::FileChooserDialog dialog("Please choose a file", + Gtk::FILE_CHOOSER_ACTION_SAVE); + dialog.set_transient_for(*window_); + dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); + dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("_Save", Gtk::RESPONSE_OK); + int result = dialog.run(); + switch (result) { + case(Gtk::RESPONSE_OK): { + std::string path = dialog.get_filename(); + unsigned pos = path.find_last_of("/\\"); + std::cout << path<< std::endl; + //notebook_.OnSaveFile(path); + return path; + break; + } + case(Gtk::RESPONSE_CANCEL): { + break; + } + default: { + std::cout << "Unexpected button clicked." << std::endl; + break; + } + } + return ""; } -void Notebook::Controller::PrintQue(){ - int size = BufferHistory().back().size(); - std::cout << "buffer size: "<< size << std::endl - << "buffer #: " << CurrentPage() << std::endl - << "historylength: "<< BufferHistory().size() << std::endl; - } -//TODO remove first history event after open file diff --git a/juci/notebook.h b/juci/notebook.h index d0a8fad..7784487 100644 --- a/juci/notebook.h +++ b/juci/notebook.h @@ -8,8 +8,9 @@ #include "directories.h" #include #include +#include #include -#include +#include "clangmm.h" namespace Notebook { class Model { @@ -30,7 +31,7 @@ namespace Notebook { }; class Controller { public: - Controller(Keybindings::Controller& keybindings, + Controller(Gtk::Window* window, Keybindings::Controller& keybindings, Source::Config& config, Directories::Config& dir_cfg); ~Controller(); @@ -40,6 +41,8 @@ namespace Notebook { Gtk::Box& entry_view(); Gtk::Notebook& Notebook(); void OnBufferChange(); + void BufferChangeHandler(Glib::RefPtr + buffer); void OnCloseCurrentPage(); std::string GetCursorWord(); void OnEditCopy(); @@ -50,40 +53,40 @@ namespace Notebook { void OnFileNewEmptyfile(); void OnFileNewHeaderFile(); void OnFileOpenFolder(); + void OnSaveFile(); void OnDirectoryNavigation(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column); void OnNewPage(std::string name); void OnOpenFile(std::string filename); void OnCreatePage(); bool ScrollEventCallback(GdkEventScroll* scroll_event); + void MapBuffers(std::map *buffers); + clang::Index* index() { return &index_; } int Pages(); - Directories::Controller& directories() { return directories_; } Gtk::Paned& view(); - - void GeneratePopup(std::vector items); - // Gtk::HBox& view(); - + bool GeneratePopup(int key); void Search(bool forward); const Source::Config& source_config() { return source_config_; } - + bool OnMouseRelease(GdkEventButton* button); + bool OnKeyRelease(GdkEventKey* key); + std::string OnSaveFileAs(); protected: - void BufferChangeHandler(Glib::RefPtr buffer); - - + void TextViewHandlers(Gtk::TextView& textview); + void PopupSelectHandler(Gtk::Dialog &popup, + Gtk::ListViewText &listview, + std::map + *items); private: - std::vector> history_; - const int kHistorySize = 30; - void NewBufferHistory(Glib::RefPtr buffer); - void RemoveBufferHistory(); - void UpdateHistory(); - void AppendBufferState(); - std::deque& BufferHistory(); - void PrintQue(); - Glib::ustring& LastBufferState(); - void OnUndo(); - void CreateKeybindings(Keybindings::Controller& keybindings); + void FindPopupPosition(Gtk::TextView& textview, + int popup_x, + int popup_y, + int &x, + int &y); + void PopupSetSize(Gtk::ScrolledWindow& scroll, + int ¤t_x, + int ¤t_y); Glib::RefPtr m_refBuilder; Glib::RefPtr refActionGroup; Source::Config source_config_; @@ -100,6 +103,10 @@ namespace Notebook { Gtk::TextIter search_match_end_; Gtk::TextIter search_match_start_; Glib::RefPtr refClipboard_; + bool ispopup; + Gtk::Dialog popup_; + Gtk::Window* window_; + clang::Index index_; }; // class controller } // namespace Notebook #endif // JUCI_NOTEBOOK_H_ diff --git a/juci/source.cc b/juci/source.cc index 2117b79..ea6a213 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -4,7 +4,7 @@ #include #include #include - +#include "notebook.h" #define log( var ) \ std::cout << "source.cc (" << __LINE__ << ") " << #var << std::endl @@ -102,16 +102,17 @@ Source::Model::Model(const Source::Config &config) : void Source::Model:: InitSyntaxHighlighting(const std::string &filepath, const std::string &project_path, - const std::string &text, + const std::map + &buffers, int start_offset, - int end_offset) { - set_file_path(filepath); + int end_offset, + clang::Index *index) { set_project_path(project_path); std::vector arguments = get_compilation_commands(); - tu_ = clang::TranslationUnit(true, + tu_ = clang::TranslationUnit(index, filepath, arguments, - text); + buffers); } // Source::View::UpdateLine @@ -123,7 +124,7 @@ OnLineEdit(const std::vector &locations, // Source::Model::UpdateLine int Source::Model:: -ReParse(const std::string &buffer) { +ReParse(const std::map &buffer) { return tu_.ReparseTranslationUnit(file_path(), buffer); } @@ -132,6 +133,42 @@ ReParse(const std::string &buffer) { // fired when a line in the buffer is edited void Source::Controller::OnLineEdit() { } +void Source::Controller:: +GetAutoCompleteSuggestions(int line_number, + int column, + std::vector + *suggestions) { + parsing.lock(); + std::map buffers; + notebook_->MapBuffers(&buffers); + model().GetAutoCompleteSuggestions(buffers, + line_number, + column, + suggestions); + parsing.unlock(); +} + +void Source::Model:: +GetAutoCompleteSuggestions(const std::map &buffers, + int line_number, + int column, + std::vector + *suggestions) { + clang::CodeCompleteResults results(&tu_, + file_path(), + buffers, + line_number, + column); + for (int i = 0; i < results.size(); i++) { + const vector chunks_ = results.get(i).get_chunks(); + std::vector chunks; + for (auto &chunk : chunks_) { + chunks.emplace_back(chunk); + } + suggestions->emplace_back(chunks); + } +} + // sets the filepath for this mvc void Source::Model:: set_file_path(const std::string &file_path) { @@ -228,9 +265,9 @@ HighlightToken(clang::Token *token, // Source::Controller::Controller() // Constructor for Controller -Source::Controller::Controller(const Source::Config &config) : - model_(config) { -} +Source::Controller::Controller(const Source::Config &config, + Notebook::Controller *notebook) : + model_(config), notebook_(notebook) { } // Source::Controller::view() // return shared_ptr to the view @@ -278,7 +315,7 @@ void Source::View::OnUpdateSyntax(const std::vector &ranges, Glib::RefPtr buffer = get_buffer(); buffer->remove_all_tags(buffer->begin(), buffer->end()); for (auto &range : ranges) { - string type = std::to_string(range.kind()); + std::string type = std::to_string(range.kind()); try { config.typetable().at(type); } catch (std::exception) { @@ -301,18 +338,22 @@ void Source::View::OnUpdateSyntax(const std::vector &ranges, } void Source::Controller::OnOpenFile(const string &filepath) { + set_file_path(filepath); sourcefile s(filepath); + std::map buffers; + notebook_->MapBuffers(&buffers); + buffers[filepath] = s.get_content(); buffer()->set_text(s.get_content()); int start_offset = buffer()->begin().get_offset(); int end_offset = buffer()->end().get_offset(); - if (check_extention(filepath)) { view().ApplyConfig(model().config()); model().InitSyntaxHighlighting(filepath, extract_file_path(filepath), - buffer()->get_text().raw(), + buffers, start_offset, - end_offset); + end_offset, + notebook_->index()); view().OnUpdateSyntax(model().ExtractTokens(start_offset, end_offset), model().config()); } @@ -323,7 +364,10 @@ void Source::Controller::OnOpenFile(const string &filepath) { if (parsing.try_lock()) { while (true) { const std::string raw = buffer()->get_text().raw(); - if (model().ReParse(raw) == 0 && + 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; @@ -338,7 +382,6 @@ void Source::Controller::OnOpenFile(const string &filepath) { } }); - buffer()->signal_begin_user_action().connect([this]() { if (go) { syntax.lock(); diff --git a/juci/source.h b/juci/source.h index 67b3d9a..cab4d5d 100644 --- a/juci/source.h +++ b/juci/source.h @@ -3,31 +3,34 @@ #include #include #include -#include #include "gtkmm.h" #include "clangmm.h" #include #include +#include -using std::string; +namespace Notebook { + class Controller; +} namespace Source { - class Config { public: Config(const Config &original); Config(); - const std::unordered_map& tagtable() const; - const std::unordered_map& typetable() const; - void SetTagTable(const std::unordered_map &tagtable); - void InsertTag(const string &key, const string &value); - void SetTypeTable(const std::unordered_map &tagtable); - void InsertType(const string &key, const string &value); + const std::unordered_map& tagtable() const; + const std::unordered_map& typetable() const; + void SetTagTable(const std::unordered_map + &tagtable); + void InsertTag(const std::string &key, const std::string &value); + void SetTypeTable(const std::unordered_map + &tagtable); + void InsertType(const std::string &key, const std::string &value); private: - std::unordered_map tagtable_; - std::unordered_map typetable_; - string background_; + std::unordered_map tagtable_; + std::unordered_map typetable_; + std::string background_; }; // class Config class Location { @@ -48,13 +51,6 @@ namespace Source { const Location& start() const { return start_; } const Location& end() const { return end_; } int kind() const { return kind_; } - void to_stream() const { - std::cout << "range: [" << start_.line_number()-1; - std::cout << ", " << end_.line_number()-1 << "] "; - std::cout << "<" << start_.column_offset()-1; - std::cout << ", " << end_.column_offset()-1 << ">"; - std::cout << std::endl; - } private: Location start_; Location end_; @@ -64,6 +60,7 @@ namespace Source { class View : public Gtk::TextView { public: View(); + virtual ~View() { } void ApplyConfig(const Config &config); void OnLineEdit(const std::vector &locations, const Config &config); @@ -71,57 +68,92 @@ namespace Source { const Config &config); private: - string GetLine(const Gtk::TextIter &begin); + std::string GetLine(const Gtk::TextIter &begin); }; // class View + class AutoCompleteChunk { + public: + explicit AutoCompleteChunk(const clang::CompletionChunk &chunk) : + chunk_(chunk.chunk()), kind_(chunk.kind()) { } + const std::string& chunk() const { return chunk_; } + const clang::CompletionChunkKind& kind() const { return kind_; } + private: + std::string chunk_; + enum clang::CompletionChunkKind kind_; + }; + + class AutoCompleteData { + public: + explicit AutoCompleteData(const std::vector &chunks) : + chunks_(chunks) { } + std::vector chunks_; + }; + class Model{ public: // constructor for Source::Model explicit Model(const Source::Config &config); // inits the syntax highligthing on file open void InitSyntaxHighlighting(const std::string &filepath, - const std::string &project_path, - const std::string &text, - int start_offset, - int end_offset); + const std::string &project_path, + const std::map + &buffers, + int start_offset, + int end_offset, + clang::Index *index); // sets the filepath for this mvc - void set_file_path(const string &file_path); + void set_file_path(const std::string &file_path); // sets the project path for this mvc - void set_project_path(const string &project_path); + void set_project_path(const std::string &project_path); // gets the file_path member - const string& file_path() const; + const std::string& file_path() const; // gets the project_path member - const string& project_path() const; + const std::string& project_path() const; // gets the config member const Config& config() const; + void GetAutoCompleteSuggestions(const std::map + &buffers, + int line_number, + int column, + std::vector + *suggestions); ~Model() { } - int ReParse(const std::string &buffer); + int ReParse(const std::map &buffers); std::vector ExtractTokens(int, int); private: Config config_; - string file_path_; - string project_path_; + std::string file_path_; + std::string project_path_; clang::TranslationUnit tu_; void HighlightToken(clang::Token *token, std::vector *source_ranges, int token_kind); void HighlightCursor(clang::Token *token, std::vector *source_ranges); - std::vector get_compilation_commands(); }; class Controller { public: - explicit Controller(const Source::Config &config); + Controller(const Source::Config &config, + Notebook::Controller *notebook); Controller(); View& view(); Model& model(); void OnNewEmptyFile(); - void OnOpenFile(const string &filename); + void OnOpenFile(const std::string &filename); + void GetAutoCompleteSuggestions(int line_number, + int column, + std::vector + *suggestions); Glib::RefPtr buffer(); + bool is_saved() { return is_saved_; } + std::string path() { return model().file_path(); } + void set_is_saved(bool isSaved) { is_saved_ = isSaved; } + void set_file_path(std::string path) { model().set_file_path(path); } + private: void OnLineEdit(); @@ -129,10 +161,12 @@ namespace Source { std::mutex syntax; std::mutex parsing; bool go = false; + bool is_saved_ = false; protected: View view_; Model model_; + Notebook::Controller *notebook_; }; // class Controller } // namespace Source #endif // JUCI_SOURCE_H_ diff --git a/juci/terminal.cc b/juci/terminal.cc index e96a21a..e512af0 100644 --- a/juci/terminal.cc +++ b/juci/terminal.cc @@ -1,6 +1,94 @@ #include "terminal.h" +#include +#include +Terminal::View::View(){ + scrolledwindow_.add(textview_); + scrolledwindow_.set_size_request(-1,150); + view_.add(scrolledwindow_); + textview_.set_editable(false); + //Pango::TabArray tabsize; + //tabsize.set_tab(200,Pango::TAB_LEFT, 200); + //textview_.set_tabs(tabsize); +} +Terminal::Controller::Controller() { + folder_command_ = ""; +} - +void Terminal::Controller::SetFolderCommand(std::string path) { + int pos = path.find_last_of("/\\"); + path.erase(path.begin()+pos,path.end()); + folder_command_ = "cd "+ path + "; "; +} + +void Terminal::Controller::CompileAndRun(std::string project_name) { + if (folder_command_=="") { + PrintMessage("juCi++ ERROR: Can not find project's CMakeList.txt\n"); + } else { + if (running.try_lock()) { + std::thread execute([=]() { + Terminal().get_buffer()->set_text(""); + ExecuteCommand("cmake ."); + if (ExistInConsole(cmake_sucsess)){ + ExecuteCommand("make"); + if (ExistInConsole(make_built)){ + if (FindExecutable(project_name)) { + ExecuteCommand("./"+project_name); + } else { + PrintMessage("juCi++ ERROR: Can not find Executable\n"); + } + } + } + }); + execute.detach(); + running.unlock(); + } + } +} + +void Terminal::Controller::PrintMessage(std::string message){ + Terminal().get_buffer()-> + insert(Terminal().get_buffer()-> end(),"> "+message); +} + +bool Terminal::Controller::FindExecutable(std::string executable) { + std::string build = Terminal().get_buffer()->get_text(); + double pos = build.find(make_built); + Gtk::TextIter start = Terminal().get_buffer()->get_iter_at_offset(pos); + Gtk::TextIter end = Terminal().get_buffer()->get_iter_at_offset(pos); + while (!end.ends_line()) { + end.forward_char(); + } + build = Terminal().get_buffer()->get_text(start, end); + pos = build.find_last_of(" "); + std::cout << "FINNER NY POS" << std::endl; + build = build.substr(pos+1); + std::cout <<"BUILD TARGET = "<< build << std::endl; + std::cout << "EXECUTABLE FILE = "<< executable << std::endl; + if(build != executable) return false; + return true; +} + +bool Terminal::Controller::ExistInConsole(std::string string) { + double pos = Terminal().get_buffer()-> + get_text().find(string); + if (pos == std::string::npos) return false; + return true; +} + +void Terminal::Controller::ExecuteCommand(std::string command) { + command = folder_command_+command; + std::cout << "EXECUTE COMMAND: "<< command << std::endl; + FILE* p = popen(command.c_str(), "r"); + if (p == NULL) { + PrintMessage("juCi++ ERROR: Failed to run command" + command + "\n"); + }else { + char buffer[1028]; + while (fgets(buffer, 1028, p) != NULL) { + PrintMessage(buffer); + } + pclose(p); + } +} diff --git a/juci/terminal.h b/juci/terminal.h index 83d0738..fe890fc 100644 --- a/juci/terminal.h +++ b/juci/terminal.h @@ -1,8 +1,7 @@ - -#ifndef JUCI_NOTEBOOK_H_ -#define JUCI_NOTEBOOK_H_ +#ifndef JUCI_TERMINAL_H_ +#define JUCI_TERMINAL_H_ -#include +#include #include "gtkmm.h" namespace Terminal { @@ -10,18 +9,34 @@ namespace Terminal { class View { public: View(); - //Gtk::HBox view() {return view_;} + Gtk::HBox& view() {return view_;} + Gtk::TextView& textview() {return textview_;} private: Gtk::HBox view_; - Gtk::TextBuffer buffer_; Gtk::TextView textview_; + Gtk::ScrolledWindow scrolledwindow_; }; // class view - class Controller { + class Controller { public: - - + Controller(); + Gtk::HBox& view() {return view_.view();} + Gtk::TextView& Terminal(){return view_.textview();} + void SetFolderCommand(std::string path); + void CompileAndRun(std::string project_name); + private: + void ExecuteCommand(std::string command); + bool OnButtonRealeaseEvent(GdkEventKey* key); + bool ExistInConsole(std::string string); + bool FindExecutable(std::string executable); + void PrintMessage(std::string message); + Terminal::View view_; + std::string folder_command_; + std::mutex running; + const std::string cmake_sucsess = "Build files have been written to:"; + const std::string make_built = "Built target"; + const std::string make_executable = "Linking CXX executable"; }; // class controller } // namespace Terminal -#endif // JUCI_NOTEBOOK_H_ +#endif // JUCI_TERMINAL_H_ diff --git a/juci/window.cc b/juci/window.cc index 1097e52..5177995 100644 --- a/juci/window.cc +++ b/juci/window.cc @@ -4,8 +4,8 @@ Window::Window() : window_box_(Gtk::ORIENTATION_VERTICAL), main_config_(), keybindings_(main_config_.keybindings_cfg()), - notebook_(keybindings(), main_config_.source_cfg(), main_config_.dir_cfg()), - menu_(keybindings()) { + notebook_(this,keybindings(), main_config_.source_cfg(), main_config_.dir_cfg()), + menu_(keybindings()) { set_title("juCi++"); set_default_size(600, 400); add(window_box_); @@ -26,6 +26,50 @@ Window::Window() : [this]() { OnFileOpenFolder(); }); + + keybindings_.action_group_menu()->add(Gtk::Action::create("FileSaveAs", + "Save as"), + Gtk::AccelKey(keybindings_.config_ + .key_map()["save_as"]), + [this]() { + notebook_.OnSaveFile(); + }); + + keybindings_.action_group_menu()->add(Gtk::Action::create("FileSave", + "Save"), + Gtk::AccelKey(keybindings_.config_ + .key_map()["save"]), + [this]() { + notebook_.OnSaveFile(); + }); + + keybindings_.action_group_menu()->add(Gtk::Action::create("ProjectCompileAndRun", + "Compile And Run"), + Gtk::AccelKey(keybindings_.config_ + .key_map()["compile_and_run"]), + [this]() { + terminal_. + SetFolderCommand("/home/gm/ClionProjects/testi/CM.txt"); + std::string p = notebook_.directories().get_project_name("/home/gm/ClionProjects/testi"); + terminal_.CompileAndRun(p); + }); + + keybindings_.action_group_menu()->add(Gtk::Action::create("ProjectCompile", + "Compile"), + Gtk::AccelKey(keybindings_.config_ + .key_map()["compile"]), + [this]() { + terminal_. + SetFolderCommand("/home/gm/ClionProjects/testi/CM.txt"); + std::string p = notebook_.directories().get_project_name("/home/gm/ClionProjects/testi"); + terminal_.CompileAndRun(p); + }); + + this->signal_button_release_event(). + connect(sigc::mem_fun(*this,&Window::OnMouseRelease),false); + terminal_.Terminal().signal_button_release_event(). + connect(sigc::mem_fun(*this,&Window::OnMouseRelease),false); + PluginApi::menu_ = &menu_; PluginApi::notebook_ = ¬ebook_; PluginApi::InitPlugins(); @@ -37,6 +81,7 @@ Window::Window() : window_box_.pack_start(menu_.view(), Gtk::PACK_SHRINK); window_box_.pack_start(notebook_.entry_view(), Gtk::PACK_SHRINK); window_box_.pack_start(notebook_.view()); + window_box_.pack_end(terminal_.view(),Gtk::PACK_SHRINK); show_all_children(); } // Window constructor @@ -62,6 +107,7 @@ void Window::OnFileOpenFolder() { std::cout << "Folder selected: " << dialog.get_filename() << std::endl; notebook_.directories().open_folder(dialog.get_filename()); + std::cout << dialog.get_filename()<< std::endl; break; } case(Gtk::RESPONSE_CANCEL): @@ -112,6 +158,7 @@ void Window::OnOpenFile() { case(Gtk::RESPONSE_OK): { std::cout << "Open clicked." << std::endl; std::string path = dialog.get_filename(); + std::cout << "File selected: " << path << std::endl; notebook_.OnOpenFile(path); break; @@ -126,3 +173,7 @@ void Window::OnOpenFile() { } } } +bool Window::OnMouseRelease(GdkEventButton *button){ + return notebook_.OnMouseRelease(button); +} + diff --git a/juci/window.h b/juci/window.h index a0b810f..e9c5424 100644 --- a/juci/window.h +++ b/juci/window.h @@ -3,6 +3,7 @@ #include "api.h" #include "config.h" +#include "terminal.h" #include @@ -10,8 +11,9 @@ class Window : public Gtk::Window { public: Window(); MainConfig& main_config() { return main_config_; } + // std::string OnSaveFileAs(); Gtk::Box window_box_; - + virtual ~Window() { } //private: @@ -19,8 +21,7 @@ public: Keybindings::Controller keybindings_; Menu::Controller menu_; Notebook::Controller notebook_; - - + Terminal::Controller terminal_; Keybindings::Controller& keybindings() { return keybindings_; } private: @@ -28,7 +29,8 @@ public: void OnWindowHide(); void OnOpenFile(); void OnFileOpenFolder(); - + + bool OnMouseRelease(GdkEventButton* button); }; #endif // JUCI_WINDOW_H