From e95c89ccbee4184e5d5853f8297b6548c955933f Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 30 Jun 2015 22:43:20 +0200 Subject: [PATCH 01/34] Added diagnostics; warning and error messages while writing code. --- juci/CMakeLists.txt | 2 ++ juci/notebook.cc | 1 + juci/source.cc | 51 +++++++++++++++++++++++++++++++- juci/source.h | 5 ++++ juci/tooltips.cc | 71 +++++++++++++++++++++++++++++++++++++++++++++ juci/tooltips.h | 42 +++++++++++++++++++++++++++ juci/window.cc | 1 + 7 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 juci/tooltips.cc create mode 100644 juci/tooltips.h diff --git a/juci/CMakeLists.txt b/juci/CMakeLists.txt index b7a518e..0fae989 100644 --- a/juci/CMakeLists.txt +++ b/juci/CMakeLists.txt @@ -125,6 +125,8 @@ add_executable(${project_name} directories.cc terminal.h terminal.cc + tooltips.h + tooltips.cc ) set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) diff --git a/juci/notebook.cc b/juci/notebook.cc index fa52666..6c0d90f 100644 --- a/juci/notebook.cc +++ b/juci/notebook.cc @@ -187,6 +187,7 @@ void Notebook::Controller::OnOpenFile(std::string path) { Notebook().set_current_page(Pages()-1); Notebook().set_focus_child(*text_vec_.back()->view); //Add star on tab label when the page is not saved: + //TODO: instead use Gtk::TextBuffer::set_modified and Gtk::TextBuffer::get_modified text_vec_.back()->buffer()->signal_changed().connect([this]() { if(text_vec_.at(CurrentPage())->is_saved) { std::string path=CurrentTextView().file_path; diff --git a/juci/source.cc b/juci/source.cc index 1275cca..13484d0 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -136,7 +136,7 @@ clang::Index Source::ClangView::clang_index(0, 0); Source::ClangView::ClangView(const Source::Config& config, const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): Source::View(config, file_path, project_path), terminal(terminal), -parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { +parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false), diagnostic_tooltips(*this) { override_font(Pango::FontDescription(config.font)); override_background_color(Gdk::RGBA(config.background)); for (auto &item : config.tags) { @@ -183,6 +183,7 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { update_syntax(extract_tokens(0, get_source_buffer()->get_text().size())); parsing_in_progress->done("done"); INFO("Syntax updated"); + update_diagnostics(); } else { parse_thread_go=true; @@ -216,6 +217,8 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { signal_key_press_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_press), false); signal_key_release_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_release), false); + signal_motion_notify_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_motion_notify_event), false); + get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangView::on_mark_set), false); } Source::ClangView::~ClangView() { @@ -346,6 +349,52 @@ void Source::ClangView::update_syntax(const std::vector &ranges) } } +void Source::ClangView::update_diagnostics() { + diagnostic_tooltips.clear(); + auto diagnostics=tu_->get_diagnostics(); + auto buffer=get_source_buffer(); + for(auto& diagnostic: diagnostics) { + if(diagnostic.path==file_path) { + auto start=buffer->get_iter_at_offset(diagnostic.start_location.offset); + auto end=buffer->get_iter_at_offset(diagnostic.end_location.offset); + diagnostic_tooltips.add(diagnostic.severity_spelling+": "+diagnostic.spelling, get_source_buffer()->create_mark(start), get_source_buffer()->create_mark(end)); + auto tag=buffer->create_tag(); + tag->property_underline()=Pango::Underline::UNDERLINE_ERROR; + if(diagnostic.severity<=CXDiagnostic_Warning) { + //TODO: get color from config.json + tag->set_property("underline-rgba", Gdk::RGBA("orange")); + } + else { + //TODO: get color from config.json + tag->set_property("underline-rgba", Gdk::RGBA("red")); + } + buffer->apply_tag(tag, start, end); + } + } + on_mark_set(get_buffer()->get_insert()->get_iter(), get_buffer()->get_mark("insert")); +} + +bool Source::ClangView::on_motion_notify_event(GdkEventMotion* event) { + Gdk::Rectangle rectangle(event->x, event->y, 1, 1); + diagnostic_tooltips.show(rectangle); + auto cursor=Gdk::Cursor::create(Gdk::CursorType::XTERM); + get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->set_cursor(cursor); + return false; +} + +void Source::ClangView::on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { + if(mark->get_name()=="insert") { + Gdk::Rectangle rectangle; + get_iter_location(iterator, rectangle); + int location_window_x, location_window_y; + buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_window_x, location_window_y); + rectangle.set_x(location_window_x-2); + rectangle.set_y(location_window_y); + rectangle.set_width(4); + diagnostic_tooltips.show(rectangle); + } +} + void Source::ClangView:: highlight_cursor(clang::Token *token, std::vector *source_ranges) { diff --git a/juci/source.h b/juci/source.h index d6ec5b1..492717e 100644 --- a/juci/source.h +++ b/juci/source.h @@ -11,6 +11,7 @@ #include #include "gtksourceviewmm.h" #include "terminal.h" +#include "tooltips.h" namespace Source { class Config { @@ -95,6 +96,10 @@ namespace Source { int reparse(const std::map &buffers); std::vector extract_tokens(int, int); void update_syntax(const std::vector &locations); + void update_diagnostics(); + Tooltips diagnostic_tooltips; + bool on_motion_notify_event(GdkEventMotion* event); + void on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); static clang::Index clang_index; std::map get_buffer_map() const; diff --git a/juci/tooltips.cc b/juci/tooltips.cc new file mode 100644 index 0000000..9f9ca50 --- /dev/null +++ b/juci/tooltips.cc @@ -0,0 +1,71 @@ +#include "tooltips.h" +#include + +Tooltip::Tooltip(Gtk::TextView& text_view, const std::string& label_text, +Glib::RefPtr start_mark, Glib::RefPtr end_mark, Gdk::Rectangle &tooltips_rectangle): +text_view(text_view), Gtk::Dialog("", (Gtk::Window&)*text_view.get_toplevel()), label(label_text), +start_mark(start_mark), end_mark(end_mark), tooltips_rectangle(tooltips_rectangle) { + get_content_area()->add(label); + property_decorated()=false; + set_accept_focus(false); +} + +void Tooltip::update() { + auto iter=start_mark->get_iter(); + auto end_iter=end_mark->get_iter(); + if(iter.get_offset()get_root_coords(text_rectangle.get_x(), text_rectangle.get_y(), root_x, root_y); + Gdk::Rectangle rectangle; + rectangle.set_x(root_x); + rectangle.set_y(root_y-tooltip_height); + rectangle.set_width(tooltip_width); + rectangle.set_height(tooltip_height); + + if(tooltips_rectangle.get_width()!=0) { + if(rectangle.intersects(tooltips_rectangle)) + rectangle.set_y(tooltips_rectangle.get_y()-tooltip_height); + tooltips_rectangle.join(rectangle); + } + else + tooltips_rectangle=rectangle; + + if(rectangle.get_y()<0) + rectangle.set_y(0); + move(rectangle.get_x(), rectangle.get_y()); +} + +void Tooltips::add(const std::string& text, Glib::RefPtr start_mark, Glib::RefPtr end_mark) { + tooltips.emplace_back(new Tooltip(text_view, text, start_mark, end_mark, tooltips_rectangle)); +} + +void Tooltips::show(const Gdk::Rectangle& rectangle) { + init_adjustments(); + for(auto& tooltip: tooltips) { + tooltip->update(); + if(rectangle.intersects(tooltip->text_rectangle)) { + tooltip->show_all(); + tooltip->adjust(); + } + else + tooltip->hide(); + } +} \ No newline at end of file diff --git a/juci/tooltips.h b/juci/tooltips.h new file mode 100644 index 0000000..9ddf4c8 --- /dev/null +++ b/juci/tooltips.h @@ -0,0 +1,42 @@ +#ifndef JUCI_TOOLTIPS_H_ +#define JUCI_TOOLTIPS_H_ +#include "gtkmm.h" +#include +#include + +class Tooltip : public Gtk::Dialog { +public: + Tooltip(Gtk::TextView& text_view, const std::string& label_text, Glib::RefPtr start_mark, Glib::RefPtr end_mark, Gdk::Rectangle &tooltips_rectangle); + + void update(); + void adjust(); + + Gtk::Label label; + Glib::RefPtr start_mark; + Glib::RefPtr end_mark; + Gdk::Rectangle text_rectangle; + +private: + Gtk::TextView& text_view; + Gdk::Rectangle &tooltips_rectangle; +}; + +class Tooltips { +public: + Tooltips(Gtk::TextView& text_view): text_view(text_view) {} + + void init_adjustments() {tooltips_rectangle=Gdk::Rectangle();} + + void clear() {tooltips.clear();} + + void add(const std::string& text, Glib::RefPtr start_mark, Glib::RefPtr end_mark); + + void show(const Gdk::Rectangle& rectangle); + + Gdk::Rectangle tooltips_rectangle; +private: + Gtk::TextView& text_view; + std::vector > tooltips; +}; + +#endif // JUCI_TOOLTIPS_H_ \ No newline at end of file diff --git a/juci/window.cc b/juci/window.cc index 6c54878..d784d23 100644 --- a/juci/window.cc +++ b/juci/window.cc @@ -14,6 +14,7 @@ Window::Window() : INFO("Create Window"); set_title("juCi++"); set_default_size(600, 400); + set_events(Gdk::POINTER_MOTION_MASK); add(window_box_); keybindings_.action_group_menu()->add(Gtk::Action::create("FileQuit", "Quit juCi++"), From 4a5eba77b8ce09695d423742ad7381a53b474730 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 30 Jun 2015 22:55:33 +0200 Subject: [PATCH 02/34] Added convenient Tooltips::show() and Tooltips::hide(). --- juci/tooltips.cc | 18 +++++++++++++++++- juci/tooltips.h | 4 +++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/juci/tooltips.cc b/juci/tooltips.cc index 9f9ca50..a137a20 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -68,4 +68,20 @@ void Tooltips::show(const Gdk::Rectangle& rectangle) { else tooltip->hide(); } -} \ No newline at end of file +} + +void Tooltips::show() { + init_adjustments(); + for(auto& tooltip: tooltips) { + tooltip->update(); + tooltip->show_all(); + tooltip->adjust(); + } +} + +void Tooltips::hide() { + init_adjustments(); + for(auto& tooltip: tooltips) { + tooltip->hide(); + } +} diff --git a/juci/tooltips.h b/juci/tooltips.h index 9ddf4c8..9593b4c 100644 --- a/juci/tooltips.h +++ b/juci/tooltips.h @@ -32,6 +32,8 @@ public: void add(const std::string& text, Glib::RefPtr start_mark, Glib::RefPtr end_mark); void show(const Gdk::Rectangle& rectangle); + void show(); + void hide(); Gdk::Rectangle tooltips_rectangle; private: @@ -39,4 +41,4 @@ private: std::vector > tooltips; }; -#endif // JUCI_TOOLTIPS_H_ \ No newline at end of file +#endif // JUCI_TOOLTIPS_H_ From c1aebf79021242f76b3abb49a723e8548f53dbfb Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 30 Jun 2015 23:01:37 +0200 Subject: [PATCH 03/34] Minor cleanup. --- juci/tooltips.cc | 5 ++--- juci/tooltips.h | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/juci/tooltips.cc b/juci/tooltips.cc index a137a20..acaf422 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -58,7 +58,7 @@ void Tooltips::add(const std::string& text, Glib::RefPtr } void Tooltips::show(const Gdk::Rectangle& rectangle) { - init_adjustments(); + tooltips_rectangle=Gdk::Rectangle(); for(auto& tooltip: tooltips) { tooltip->update(); if(rectangle.intersects(tooltip->text_rectangle)) { @@ -71,7 +71,7 @@ void Tooltips::show(const Gdk::Rectangle& rectangle) { } void Tooltips::show() { - init_adjustments(); + tooltips_rectangle=Gdk::Rectangle(); for(auto& tooltip: tooltips) { tooltip->update(); tooltip->show_all(); @@ -80,7 +80,6 @@ void Tooltips::show() { } void Tooltips::hide() { - init_adjustments(); for(auto& tooltip: tooltips) { tooltip->hide(); } diff --git a/juci/tooltips.h b/juci/tooltips.h index 9593b4c..2dbeb99 100644 --- a/juci/tooltips.h +++ b/juci/tooltips.h @@ -24,8 +24,6 @@ private: class Tooltips { public: Tooltips(Gtk::TextView& text_view): text_view(text_view) {} - - void init_adjustments() {tooltips_rectangle=Gdk::Rectangle();} void clear() {tooltips.clear();} From b109ebf3802f44f7ba00ea3018ab31de9aa3255d Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 1 Jul 2015 12:36:20 +0200 Subject: [PATCH 04/34] Fixed GLib-GObject-WARNING messages for older GTK+ versions without underline-rgba property. --- juci/source.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 13484d0..230a574 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -360,13 +360,17 @@ void Source::ClangView::update_diagnostics() { diagnostic_tooltips.add(diagnostic.severity_spelling+": "+diagnostic.spelling, get_source_buffer()->create_mark(start), get_source_buffer()->create_mark(end)); auto tag=buffer->create_tag(); tag->property_underline()=Pango::Underline::UNDERLINE_ERROR; - if(diagnostic.severity<=CXDiagnostic_Warning) { - //TODO: get color from config.json - tag->set_property("underline-rgba", Gdk::RGBA("orange")); - } - else { - //TODO: get color from config.json - tag->set_property("underline-rgba", Gdk::RGBA("red")); + auto tag_class=G_OBJECT_GET_CLASS(tag->gobj()); //For older GTK+ 3 versions: + auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); + if(param_spec!=NULL) { + if(diagnostic.severity<=CXDiagnostic_Warning) { + //TODO: get color from config.json + tag->set_property("underline-rgba", Gdk::RGBA("orange")); + } + else { + //TODO: get color from config.json + tag->set_property("underline-rgba", Gdk::RGBA("red")); + } } buffer->apply_tag(tag, start, end); } From 57cb7b4577cb1975c6776628ccfbecb1200732f8 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 1 Jul 2015 12:54:09 +0200 Subject: [PATCH 05/34] Small fix in Tooltips, can now show tooltips from several Tooltips-objects at once without overlap (see comments). --- juci/tooltips.cc | 32 +++++++++++++++++++------------- juci/tooltips.h | 9 ++++----- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/juci/tooltips.cc b/juci/tooltips.cc index acaf422..8002458 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -1,10 +1,11 @@ #include "tooltips.h" -#include + +Gdk::Rectangle Tooltips::tooltips_rectangle=Gdk::Rectangle(); Tooltip::Tooltip(Gtk::TextView& text_view, const std::string& label_text, -Glib::RefPtr start_mark, Glib::RefPtr end_mark, Gdk::Rectangle &tooltips_rectangle): +Glib::RefPtr start_mark, Glib::RefPtr end_mark): text_view(text_view), Gtk::Dialog("", (Gtk::Window&)*text_view.get_toplevel()), label(label_text), -start_mark(start_mark), end_mark(end_mark), tooltips_rectangle(tooltips_rectangle) { +start_mark(start_mark), end_mark(end_mark) { get_content_area()->add(label); property_decorated()=false; set_accept_focus(false); @@ -40,13 +41,13 @@ void Tooltip::adjust() { rectangle.set_width(tooltip_width); rectangle.set_height(tooltip_height); - if(tooltips_rectangle.get_width()!=0) { - if(rectangle.intersects(tooltips_rectangle)) - rectangle.set_y(tooltips_rectangle.get_y()-tooltip_height); - tooltips_rectangle.join(rectangle); + if(Tooltips::tooltips_rectangle.get_width()!=0) { + if(rectangle.intersects(Tooltips::tooltips_rectangle)) + rectangle.set_y(Tooltips::tooltips_rectangle.get_y()-tooltip_height); + Tooltips::tooltips_rectangle.join(rectangle); } else - tooltips_rectangle=rectangle; + Tooltips::tooltips_rectangle=rectangle; if(rectangle.get_y()<0) rectangle.set_y(0); @@ -54,11 +55,14 @@ void Tooltip::adjust() { } void Tooltips::add(const std::string& text, Glib::RefPtr start_mark, Glib::RefPtr end_mark) { - tooltips.emplace_back(new Tooltip(text_view, text, start_mark, end_mark, tooltips_rectangle)); + tooltips.emplace_back(new Tooltip(text_view, text, start_mark, end_mark)); } -void Tooltips::show(const Gdk::Rectangle& rectangle) { - tooltips_rectangle=Gdk::Rectangle(); +//If you want to show tooltips from several Tooltips-objects at once, you might want to set clear_tooltips_rectangle=true only on the first one. +//If not, they would overlap (clear_tooltips_rectangle=false to avoid this on the following Tooltips-objects) +void Tooltips::show(const Gdk::Rectangle& rectangle, bool clear_tooltips_rectangle) { + if(clear_tooltips_rectangle) + tooltips_rectangle=Gdk::Rectangle(); for(auto& tooltip: tooltips) { tooltip->update(); if(rectangle.intersects(tooltip->text_rectangle)) { @@ -70,8 +74,10 @@ void Tooltips::show(const Gdk::Rectangle& rectangle) { } } -void Tooltips::show() { - tooltips_rectangle=Gdk::Rectangle(); +//See Tooltips::show(const Gdk::Rectangle& rectangle, bool clear_tooltips_rectangle=true) +void Tooltips::show(bool clear_tooltips_rectangle) { + if(clear_tooltips_rectangle) + tooltips_rectangle=Gdk::Rectangle(); for(auto& tooltip: tooltips) { tooltip->update(); tooltip->show_all(); diff --git a/juci/tooltips.h b/juci/tooltips.h index 2dbeb99..9375801 100644 --- a/juci/tooltips.h +++ b/juci/tooltips.h @@ -6,7 +6,7 @@ class Tooltip : public Gtk::Dialog { public: - Tooltip(Gtk::TextView& text_view, const std::string& label_text, Glib::RefPtr start_mark, Glib::RefPtr end_mark, Gdk::Rectangle &tooltips_rectangle); + Tooltip(Gtk::TextView& text_view, const std::string& label_text, Glib::RefPtr start_mark, Glib::RefPtr end_mark); void update(); void adjust(); @@ -18,7 +18,6 @@ public: private: Gtk::TextView& text_view; - Gdk::Rectangle &tooltips_rectangle; }; class Tooltips { @@ -29,11 +28,11 @@ public: void add(const std::string& text, Glib::RefPtr start_mark, Glib::RefPtr end_mark); - void show(const Gdk::Rectangle& rectangle); - void show(); + void show(const Gdk::Rectangle& rectangle, bool clear_tooltips_rectangle=true); + void show(bool clear_tooltips_rectangle=true); void hide(); - Gdk::Rectangle tooltips_rectangle; + static Gdk::Rectangle tooltips_rectangle; private: Gtk::TextView& text_view; std::vector > tooltips; From f924a7f3f9e0f288a68ff9c2be6f4173b7c51927 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 1 Jul 2015 13:11:03 +0200 Subject: [PATCH 06/34] Second attempt at avoiding tooltip from stealing focus. --- juci/tooltips.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/juci/tooltips.cc b/juci/tooltips.cc index 8002458..5c2172e 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -72,6 +72,7 @@ void Tooltips::show(const Gdk::Rectangle& rectangle, bool clear_tooltips_rectang else tooltip->hide(); } + text_view.grab_focus(); } //See Tooltips::show(const Gdk::Rectangle& rectangle, bool clear_tooltips_rectangle=true) @@ -83,6 +84,7 @@ void Tooltips::show(bool clear_tooltips_rectangle) { tooltip->show_all(); tooltip->adjust(); } + text_view.grab_focus(); } void Tooltips::hide() { From ebd18156c59549e7915c393956b3728e8cd1a25e Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 1 Jul 2015 14:18:21 +0200 Subject: [PATCH 07/34] Removed overloading (accidental) of on_motion_notify_event and on_mark_set. --- juci/source.cc | 10 +++++----- juci/source.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 230a574..6b391ea 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -217,8 +217,8 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false), dia signal_key_press_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_press), false); signal_key_release_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_release), false); - signal_motion_notify_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_motion_notify_event), false); - get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangView::on_mark_set), false); + signal_motion_notify_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_motion_notify_event), false); + get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_mark_set), false); } Source::ClangView::~ClangView() { @@ -375,10 +375,10 @@ void Source::ClangView::update_diagnostics() { buffer->apply_tag(tag, start, end); } } - on_mark_set(get_buffer()->get_insert()->get_iter(), get_buffer()->get_mark("insert")); + clangview_on_mark_set(get_buffer()->get_insert()->get_iter(), get_buffer()->get_mark("insert")); } -bool Source::ClangView::on_motion_notify_event(GdkEventMotion* event) { +bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) { Gdk::Rectangle rectangle(event->x, event->y, 1, 1); diagnostic_tooltips.show(rectangle); auto cursor=Gdk::Cursor::create(Gdk::CursorType::XTERM); @@ -386,7 +386,7 @@ bool Source::ClangView::on_motion_notify_event(GdkEventMotion* event) { return false; } -void Source::ClangView::on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { +void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { if(mark->get_name()=="insert") { Gdk::Rectangle rectangle; get_iter_location(iterator, rectangle); diff --git a/juci/source.h b/juci/source.h index 492717e..a1caafe 100644 --- a/juci/source.h +++ b/juci/source.h @@ -98,8 +98,8 @@ namespace Source { void update_syntax(const std::vector &locations); void update_diagnostics(); Tooltips diagnostic_tooltips; - bool on_motion_notify_event(GdkEventMotion* event); - void on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); + bool clangview_on_motion_notify_event(GdkEventMotion* event); + void clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); static clang::Index clang_index; std::map get_buffer_map() const; From 1e2e531620c060759ea3e9d96902a9717001658c Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 1 Jul 2015 14:27:01 +0200 Subject: [PATCH 08/34] Minor cleanup. --- juci/source.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 6b391ea..c8e9960 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -381,8 +381,6 @@ void Source::ClangView::update_diagnostics() { bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) { Gdk::Rectangle rectangle(event->x, event->y, 1, 1); diagnostic_tooltips.show(rectangle); - auto cursor=Gdk::Cursor::create(Gdk::CursorType::XTERM); - get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->set_cursor(cursor); return false; } From 7bcdeae51621328d8617cbee5760cd476191c4d4 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 2 Jul 2015 15:29:05 +0200 Subject: [PATCH 09/34] Some cleanup, and added colors in tooltips. --- juci/config.json | 4 ++- juci/source.cc | 28 ++++++++++------ juci/tooltips.cc | 83 +++++++++++++++++++++++------------------------- juci/tooltips.h | 30 +++++++---------- 4 files changed, 71 insertions(+), 74 deletions(-) diff --git a/juci/config.json b/juci/config.json index 0d35a91..61d9721 100644 --- a/juci/config.json +++ b/juci/config.json @@ -8,7 +8,9 @@ "type": "#0066FF", "keyword": "blue", "comment": "grey", - "own": "pink" + "own": "pink", + "diagnostic_warning": "orange", + "diagnostic_error": "red" }, "syntax": { "43": "type", diff --git a/juci/source.cc b/juci/source.cc index c8e9960..688405a 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -136,7 +136,7 @@ clang::Index Source::ClangView::clang_index(0, 0); Source::ClangView::ClangView(const Source::Config& config, const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): Source::View(config, file_path, project_path), terminal(terminal), -parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false), diagnostic_tooltips(*this) { +parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { override_font(Pango::FontDescription(config.font)); override_background_color(Gdk::RGBA(config.background)); for (auto &item : config.tags) { @@ -357,20 +357,26 @@ void Source::ClangView::update_diagnostics() { if(diagnostic.path==file_path) { auto start=buffer->get_iter_at_offset(diagnostic.start_location.offset); auto end=buffer->get_iter_at_offset(diagnostic.end_location.offset); - diagnostic_tooltips.add(diagnostic.severity_spelling+": "+diagnostic.spelling, get_source_buffer()->create_mark(start), get_source_buffer()->create_mark(end)); + std::string diagnostic_tag_name; + if(diagnostic.severity<=CXDiagnostic_Warning) + diagnostic_tag_name="diagnostic_warning"; + else + diagnostic_tag_name="diagnostic_error"; + + auto tooltip_widget=std::make_shared(Gtk::TextBuffer::create(buffer->get_tag_table())); + tooltip_widget->set_editable(false); + tooltip_widget->get_buffer()->insert_with_tag(tooltip_widget->get_buffer()->get_insert()->get_iter(), diagnostic.severity_spelling, diagnostic_tag_name); + tooltip_widget->get_buffer()->insert_at_cursor(": "+diagnostic.spelling); + diagnostic_tooltips.emplace_back(tooltip_widget, *this, get_source_buffer()->create_mark(start), get_source_buffer()->create_mark(end)); + auto tag=buffer->create_tag(); tag->property_underline()=Pango::Underline::UNDERLINE_ERROR; auto tag_class=G_OBJECT_GET_CLASS(tag->gobj()); //For older GTK+ 3 versions: auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); if(param_spec!=NULL) { - if(diagnostic.severity<=CXDiagnostic_Warning) { - //TODO: get color from config.json - tag->set_property("underline-rgba", Gdk::RGBA("orange")); - } - else { - //TODO: get color from config.json - tag->set_property("underline-rgba", Gdk::RGBA("red")); - } + auto diagnostic_tag=buffer->get_tag_table()->lookup(diagnostic_tag_name); + if(diagnostic_tag!=0) + tag->set_property("underline-rgba", diagnostic_tag->property_foreground_rgba().get_value()); } buffer->apply_tag(tag, start, end); } @@ -380,6 +386,7 @@ void Source::ClangView::update_diagnostics() { bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) { Gdk::Rectangle rectangle(event->x, event->y, 1, 1); + diagnostic_tooltips.init(); diagnostic_tooltips.show(rectangle); return false; } @@ -393,6 +400,7 @@ void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& i rectangle.set_x(location_window_x-2); rectangle.set_y(location_window_y); rectangle.set_width(4); + diagnostic_tooltips.init(); diagnostic_tooltips.show(rectangle); } } diff --git a/juci/tooltips.cc b/juci/tooltips.cc index 5c2172e..8d063cb 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -1,94 +1,89 @@ #include "tooltips.h" +#include -Gdk::Rectangle Tooltips::tooltips_rectangle=Gdk::Rectangle(); +Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle(); -Tooltip::Tooltip(Gtk::TextView& text_view, const std::string& label_text, +Tooltip::Tooltip(std::shared_ptr widget, Gtk::TextView& text_view, Glib::RefPtr start_mark, Glib::RefPtr end_mark): -text_view(text_view), Gtk::Dialog("", (Gtk::Window&)*text_view.get_toplevel()), label(label_text), +widget(widget), text_view(text_view), Gtk::Dialog("", (Gtk::Window&)*text_view.get_toplevel()), start_mark(start_mark), end_mark(end_mark) { - get_content_area()->add(label); + get_content_area()->add(*widget); property_decorated()=false; set_accept_focus(false); + signal_realize().connect([this](){ + adjust(); //Fix for older GTK+ versions? + }); } void Tooltip::update() { auto iter=start_mark->get_iter(); auto end_iter=end_mark->get_iter(); if(iter.get_offset()get_root_coords(text_rectangle.get_x(), text_rectangle.get_y(), root_x, root_y); + text_view.get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(activation_rectangle.get_x(), activation_rectangle.get_y(), root_x, root_y); Gdk::Rectangle rectangle; rectangle.set_x(root_x); rectangle.set_y(root_y-tooltip_height); rectangle.set_width(tooltip_width); rectangle.set_height(tooltip_height); - if(Tooltips::tooltips_rectangle.get_width()!=0) { - if(rectangle.intersects(Tooltips::tooltips_rectangle)) - rectangle.set_y(Tooltips::tooltips_rectangle.get_y()-tooltip_height); - Tooltips::tooltips_rectangle.join(rectangle); + if(Tooltips::drawn_tooltips_rectangle.get_width()!=0) { + if(rectangle.intersects(Tooltips::drawn_tooltips_rectangle)) + rectangle.set_y(Tooltips::drawn_tooltips_rectangle.get_y()-tooltip_height); + Tooltips::drawn_tooltips_rectangle.join(rectangle); } else - Tooltips::tooltips_rectangle=rectangle; + Tooltips::drawn_tooltips_rectangle=rectangle; - if(rectangle.get_y()<0) - rectangle.set_y(0); move(rectangle.get_x(), rectangle.get_y()); + adjusted=true; } -void Tooltips::add(const std::string& text, Glib::RefPtr start_mark, Glib::RefPtr end_mark) { - tooltips.emplace_back(new Tooltip(text_view, text, start_mark, end_mark)); -} - -//If you want to show tooltips from several Tooltips-objects at once, you might want to set clear_tooltips_rectangle=true only on the first one. -//If not, they would overlap (clear_tooltips_rectangle=false to avoid this on the following Tooltips-objects) -void Tooltips::show(const Gdk::Rectangle& rectangle, bool clear_tooltips_rectangle) { - if(clear_tooltips_rectangle) - tooltips_rectangle=Gdk::Rectangle(); - for(auto& tooltip: tooltips) { - tooltip->update(); - if(rectangle.intersects(tooltip->text_rectangle)) { - tooltip->show_all(); - tooltip->adjust(); +void Tooltips::show(const Gdk::Rectangle& rectangle) { + for(auto& tooltip: *this) { + tooltip.update(); + if(rectangle.intersects(tooltip.activation_rectangle)) { + tooltip.show_all(); + if(tooltip.get_realized()) + tooltip.adjust(); } else - tooltip->hide(); + tooltip.hide(); } - text_view.grab_focus(); } -//See Tooltips::show(const Gdk::Rectangle& rectangle, bool clear_tooltips_rectangle=true) -void Tooltips::show(bool clear_tooltips_rectangle) { - if(clear_tooltips_rectangle) - tooltips_rectangle=Gdk::Rectangle(); - for(auto& tooltip: tooltips) { - tooltip->update(); - tooltip->show_all(); - tooltip->adjust(); +void Tooltips::show() { + for(auto& tooltip: *this) { + tooltip.update(); + tooltip.show_all(); + if(tooltip.get_realized()) + tooltip.adjust(); } - text_view.grab_focus(); } void Tooltips::hide() { - for(auto& tooltip: tooltips) { - tooltip->hide(); + for(auto& tooltip: *this) { + tooltip.hide(); } } diff --git a/juci/tooltips.h b/juci/tooltips.h index 9375801..b8d86ae 100644 --- a/juci/tooltips.h +++ b/juci/tooltips.h @@ -2,40 +2,32 @@ #define JUCI_TOOLTIPS_H_ #include "gtkmm.h" #include -#include +#include class Tooltip : public Gtk::Dialog { public: - Tooltip(Gtk::TextView& text_view, const std::string& label_text, Glib::RefPtr start_mark, Glib::RefPtr end_mark); + Tooltip(std::shared_ptr widget, Gtk::TextView& text_view, Glib::RefPtr start_mark, Glib::RefPtr end_mark); void update(); void adjust(); - Gtk::Label label; + Gdk::Rectangle activation_rectangle; + bool adjusted=false; +private: + std::shared_ptr widget; Glib::RefPtr start_mark; Glib::RefPtr end_mark; - Gdk::Rectangle text_rectangle; - -private: Gtk::TextView& text_view; }; -class Tooltips { +class Tooltips : public std::list { public: - Tooltips(Gtk::TextView& text_view): text_view(text_view) {} - - void clear() {tooltips.clear();} - - void add(const std::string& text, Glib::RefPtr start_mark, Glib::RefPtr end_mark); - - void show(const Gdk::Rectangle& rectangle, bool clear_tooltips_rectangle=true); - void show(bool clear_tooltips_rectangle=true); + void init() {drawn_tooltips_rectangle=Gdk::Rectangle();} + void show(const Gdk::Rectangle& rectangle); + void show(); void hide(); - static Gdk::Rectangle tooltips_rectangle; -private: - Gtk::TextView& text_view; - std::vector > tooltips; + static Gdk::Rectangle drawn_tooltips_rectangle; }; #endif // JUCI_TOOLTIPS_H_ From 4b07c5a5cbded3c35a4db46372af9e043d087a12 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 2 Jul 2015 16:28:48 +0200 Subject: [PATCH 10/34] Focus issue fixed. --- juci/tooltips.cc | 6 ++++-- juci/tooltips.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/juci/tooltips.cc b/juci/tooltips.cc index 8d063cb..8938830 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -5,11 +5,13 @@ Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle(); Tooltip::Tooltip(std::shared_ptr widget, Gtk::TextView& text_view, Glib::RefPtr start_mark, Glib::RefPtr end_mark): -widget(widget), text_view(text_view), Gtk::Dialog("", (Gtk::Window&)*text_view.get_toplevel()), +widget(widget), text_view(text_view), Gtk::Window(Gtk::WindowType::WINDOW_POPUP), start_mark(start_mark), end_mark(end_mark) { - get_content_area()->add(*widget); + add(*widget); property_decorated()=false; set_accept_focus(false); + set_skip_taskbar_hint(true); + set_default_size(0, 0); signal_realize().connect([this](){ adjust(); //Fix for older GTK+ versions? }); diff --git a/juci/tooltips.h b/juci/tooltips.h index b8d86ae..5f13b14 100644 --- a/juci/tooltips.h +++ b/juci/tooltips.h @@ -4,7 +4,7 @@ #include #include -class Tooltip : public Gtk::Dialog { +class Tooltip : public Gtk::Window { public: Tooltip(std::shared_ptr widget, Gtk::TextView& text_view, Glib::RefPtr start_mark, Glib::RefPtr end_mark); From f45343514873c963c5401c736b64f0aa0b494030 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 2 Jul 2015 19:03:59 +0200 Subject: [PATCH 11/34] Minor improvement to tooltips, less eager now too. --- juci/source.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 688405a..2d2af80 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -366,7 +366,8 @@ void Source::ClangView::update_diagnostics() { auto tooltip_widget=std::make_shared(Gtk::TextBuffer::create(buffer->get_tag_table())); tooltip_widget->set_editable(false); tooltip_widget->get_buffer()->insert_with_tag(tooltip_widget->get_buffer()->get_insert()->get_iter(), diagnostic.severity_spelling, diagnostic_tag_name); - tooltip_widget->get_buffer()->insert_at_cursor(": "+diagnostic.spelling); + tooltip_widget->get_buffer()->insert_at_cursor(": \n"+diagnostic.spelling); + //TODO: Insert newlines in tooltip_widget->get_buffer() (use 80 chars, then newline?) diagnostic_tooltips.emplace_back(tooltip_widget, *this, get_source_buffer()->create_mark(start), get_source_buffer()->create_mark(end)); auto tag=buffer->create_tag(); @@ -381,7 +382,6 @@ void Source::ClangView::update_diagnostics() { buffer->apply_tag(tag, start, end); } } - clangview_on_mark_set(get_buffer()->get_insert()->get_iter(), get_buffer()->get_mark("insert")); } bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) { From 097bfc65dc699867bd121f3b885f7157378c8631 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 3 Jul 2015 09:32:43 +0200 Subject: [PATCH 12/34] Fixed tooltip class. --- juci/source.cc | 2 +- juci/tooltips.cc | 25 +++++++++---------------- juci/tooltips.h | 6 +++--- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 2d2af80..1c1215f 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -367,7 +367,7 @@ void Source::ClangView::update_diagnostics() { tooltip_widget->set_editable(false); tooltip_widget->get_buffer()->insert_with_tag(tooltip_widget->get_buffer()->get_insert()->get_iter(), diagnostic.severity_spelling, diagnostic_tag_name); tooltip_widget->get_buffer()->insert_at_cursor(": \n"+diagnostic.spelling); - //TODO: Insert newlines in tooltip_widget->get_buffer() (use 80 chars, then newline?) + //TODO: Insert newlines to diagnostic.spelling (use 80 chars, then newline?) diagnostic_tooltips.emplace_back(tooltip_widget, *this, get_source_buffer()->create_mark(start), get_source_buffer()->create_mark(end)); auto tag=buffer->create_tag(); diff --git a/juci/tooltips.cc b/juci/tooltips.cc index 8938830..5e77726 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -3,18 +3,19 @@ Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle(); -Tooltip::Tooltip(std::shared_ptr widget, Gtk::TextView& text_view, +Tooltip::Tooltip(std::shared_ptr tooltip_widget, Gtk::TextView& text_view, Glib::RefPtr start_mark, Glib::RefPtr end_mark): -widget(widget), text_view(text_view), Gtk::Window(Gtk::WindowType::WINDOW_POPUP), +tooltip_widget(tooltip_widget), text_view(text_view), Gtk::Window(Gtk::WindowType::WINDOW_POPUP), start_mark(start_mark), end_mark(end_mark) { - add(*widget); + add(*tooltip_widget); property_decorated()=false; set_accept_focus(false); set_skip_taskbar_hint(true); set_default_size(0, 0); - signal_realize().connect([this](){ - adjust(); //Fix for older GTK+ versions? - }); + + auto layout=Pango::Layout::create(tooltip_widget->get_pango_context()); + layout->set_text(tooltip_widget->get_buffer()->get_text()); + layout->get_pixel_size(tooltip_width, tooltip_height); } void Tooltip::update() { @@ -34,14 +35,9 @@ void Tooltip::update() { text_view.buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, activation_rectangle.get_x(), activation_rectangle.get_y(), location_window_x, location_window_y); activation_rectangle.set_x(location_window_x); activation_rectangle.set_y(location_window_y); - adjusted=false; } void Tooltip::adjust() { - if(adjusted) - return; - int tooltip_width, tooltip_height; - get_size(tooltip_width, tooltip_height); int root_x, root_y; text_view.get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(activation_rectangle.get_x(), activation_rectangle.get_y(), root_x, root_y); Gdk::Rectangle rectangle; @@ -59,16 +55,14 @@ void Tooltip::adjust() { Tooltips::drawn_tooltips_rectangle=rectangle; move(rectangle.get_x(), rectangle.get_y()); - adjusted=true; } void Tooltips::show(const Gdk::Rectangle& rectangle) { for(auto& tooltip: *this) { tooltip.update(); if(rectangle.intersects(tooltip.activation_rectangle)) { + tooltip.adjust(); tooltip.show_all(); - if(tooltip.get_realized()) - tooltip.adjust(); } else tooltip.hide(); @@ -78,9 +72,8 @@ void Tooltips::show(const Gdk::Rectangle& rectangle) { void Tooltips::show() { for(auto& tooltip: *this) { tooltip.update(); + tooltip.adjust(); tooltip.show_all(); - if(tooltip.get_realized()) - tooltip.adjust(); } } diff --git a/juci/tooltips.h b/juci/tooltips.h index 5f13b14..94b2c69 100644 --- a/juci/tooltips.h +++ b/juci/tooltips.h @@ -6,18 +6,18 @@ class Tooltip : public Gtk::Window { public: - Tooltip(std::shared_ptr widget, Gtk::TextView& text_view, Glib::RefPtr start_mark, Glib::RefPtr end_mark); + Tooltip(std::shared_ptr tooltip_widget, Gtk::TextView& text_view, Glib::RefPtr start_mark, Glib::RefPtr end_mark); void update(); void adjust(); Gdk::Rectangle activation_rectangle; - bool adjusted=false; private: - std::shared_ptr widget; + std::shared_ptr tooltip_widget; Glib::RefPtr start_mark; Glib::RefPtr end_mark; Gtk::TextView& text_view; + int tooltip_width, tooltip_height; }; class Tooltips : public std::list { From 655a30023a9707d43b432ba2f478c092e7bb73b3 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 3 Jul 2015 22:32:58 +0200 Subject: [PATCH 13/34] Type info. --- juci/source.cc | 59 +++++++++++++++++++++++++++++++++++++----------- juci/source.h | 2 ++ juci/tooltips.cc | 50 +++++++++++++++++++++++++--------------- juci/tooltips.h | 9 +++++--- 4 files changed, 86 insertions(+), 34 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 1c1215f..c5010d2 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -307,7 +307,9 @@ extract_tokens(int start_offset, int end_offset) { clang::SourceLocation end(tu_.get(), file_path, end_offset); clang::SourceRange range(&start, &end); clang::Tokens tokens(tu_.get(), &range); - std::vector tks = tokens.tokens(); + tokens.get_token_types(tu_.get()); + std::vector& tks = tokens.tokens(); + update_types(tks); for (auto &token : tks) { switch (token.kind()) { case 0: highlight_cursor(&token, &ranges); break; // PunctuationToken @@ -352,34 +354,63 @@ void Source::ClangView::update_syntax(const std::vector &ranges) void Source::ClangView::update_diagnostics() { diagnostic_tooltips.clear(); auto diagnostics=tu_->get_diagnostics(); - auto buffer=get_source_buffer(); for(auto& diagnostic: diagnostics) { if(diagnostic.path==file_path) { - auto start=buffer->get_iter_at_offset(diagnostic.start_location.offset); - auto end=buffer->get_iter_at_offset(diagnostic.end_location.offset); + auto start=get_buffer()->get_iter_at_offset(diagnostic.start_location.offset); + auto end=get_buffer()->get_iter_at_offset(diagnostic.end_location.offset); std::string diagnostic_tag_name; if(diagnostic.severity<=CXDiagnostic_Warning) diagnostic_tag_name="diagnostic_warning"; else diagnostic_tag_name="diagnostic_error"; - auto tooltip_widget=std::make_shared(Gtk::TextBuffer::create(buffer->get_tag_table())); - tooltip_widget->set_editable(false); - tooltip_widget->get_buffer()->insert_with_tag(tooltip_widget->get_buffer()->get_insert()->get_iter(), diagnostic.severity_spelling, diagnostic_tag_name); - tooltip_widget->get_buffer()->insert_at_cursor(": \n"+diagnostic.spelling); - //TODO: Insert newlines to diagnostic.spelling (use 80 chars, then newline?) - diagnostic_tooltips.emplace_back(tooltip_widget, *this, get_source_buffer()->create_mark(start), get_source_buffer()->create_mark(end)); + std::string spelling=diagnostic.spelling; + std::string severity_spelling=diagnostic.severity_spelling; + auto get_tooltip_buffer=[this, spelling, severity_spelling, diagnostic_tag_name]() { + auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), severity_spelling, diagnostic_tag_name); + tooltip_buffer->insert_at_cursor(":\n"+spelling); + //TODO: Insert newlines to diagnostic.spelling (use 80 chars, then newline?) + return tooltip_buffer; + }; + diagnostic_tooltips.emplace_back(get_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); - auto tag=buffer->create_tag(); + auto tag=get_buffer()->create_tag(); tag->property_underline()=Pango::Underline::UNDERLINE_ERROR; auto tag_class=G_OBJECT_GET_CLASS(tag->gobj()); //For older GTK+ 3 versions: auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); if(param_spec!=NULL) { - auto diagnostic_tag=buffer->get_tag_table()->lookup(diagnostic_tag_name); + auto diagnostic_tag=get_buffer()->get_tag_table()->lookup(diagnostic_tag_name); if(diagnostic_tag!=0) tag->set_property("underline-rgba", diagnostic_tag->property_foreground_rgba().get_value()); } - buffer->apply_tag(tag, start, end); + get_buffer()->apply_tag(tag, start, end); + } + } +} + +void Source::ClangView::update_types(std::vector& tokens) { + type_tooltips.clear(); + for(auto& token: tokens) { + if(token.type!="") { + clang::SourceRange range(tu_.get(), &token); + clang::SourceLocation start(&range, true); + clang::SourceLocation end(&range, false); + std::string path; + unsigned start_offset, end_offset; + start.get_location_info(&path, NULL, NULL, &start_offset); + end.get_location_info(NULL, NULL, NULL, &end_offset); + if(path==file_path) { + auto start=get_buffer()->get_iter_at_offset(start_offset); + auto end=get_buffer()->get_iter_at_offset(end_offset); + auto get_tooltip_buffer=[this, token]() { + auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); + tooltip_buffer->insert_at_cursor("Type: "+token.type); + return tooltip_buffer; + }; + + type_tooltips.emplace_back(get_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); + } } } } @@ -387,6 +418,7 @@ void Source::ClangView::update_diagnostics() { bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) { Gdk::Rectangle rectangle(event->x, event->y, 1, 1); diagnostic_tooltips.init(); + type_tooltips.show(rectangle); diagnostic_tooltips.show(rectangle); return false; } @@ -401,6 +433,7 @@ void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& i rectangle.set_y(location_window_y); rectangle.set_width(4); diagnostic_tooltips.init(); + type_tooltips.show(rectangle); diagnostic_tooltips.show(rectangle); } } diff --git a/juci/source.h b/juci/source.h index a1caafe..1d8dc44 100644 --- a/juci/source.h +++ b/juci/source.h @@ -97,7 +97,9 @@ namespace Source { std::vector extract_tokens(int, int); void update_syntax(const std::vector &locations); void update_diagnostics(); + void update_types(std::vector& tokens); Tooltips diagnostic_tooltips; + Tooltips type_tooltips; bool clangview_on_motion_notify_event(GdkEventMotion* event); void clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); diff --git a/juci/tooltips.cc b/juci/tooltips.cc index 5e77726..3676d4d 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -3,19 +3,14 @@ Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle(); -Tooltip::Tooltip(std::shared_ptr tooltip_widget, Gtk::TextView& text_view, +Tooltip::Tooltip(std::function()> get_buffer, Gtk::TextView& text_view, Glib::RefPtr start_mark, Glib::RefPtr end_mark): -tooltip_widget(tooltip_widget), text_view(text_view), Gtk::Window(Gtk::WindowType::WINDOW_POPUP), -start_mark(start_mark), end_mark(end_mark) { - add(*tooltip_widget); - property_decorated()=false; - set_accept_focus(false); - set_skip_taskbar_hint(true); - set_default_size(0, 0); - - auto layout=Pango::Layout::create(tooltip_widget->get_pango_context()); - layout->set_text(tooltip_widget->get_buffer()->get_text()); - layout->get_pixel_size(tooltip_width, tooltip_height); +get_buffer(get_buffer), text_view(text_view), +start_mark(start_mark), end_mark(end_mark) {} + +Tooltip::~Tooltip() { + text_view.get_buffer()->delete_mark(start_mark); + text_view.get_buffer()->delete_mark(end_mark); } void Tooltip::update() { @@ -38,6 +33,24 @@ void Tooltip::update() { } void Tooltip::adjust() { + if(!window) { + //init window + window=std::unique_ptr(new Gtk::Window(Gtk::WindowType::WINDOW_POPUP)); + + window->property_decorated()=false; + window->set_accept_focus(false); + window->set_skip_taskbar_hint(true); + window->set_default_size(0, 0); + + tooltip_widget=std::unique_ptr(new Gtk::TextView(this->get_buffer())); + tooltip_widget->set_editable(false); + window->add(*tooltip_widget); + + auto layout=Pango::Layout::create(tooltip_widget->get_pango_context()); + layout->set_text(tooltip_widget->get_buffer()->get_text()); + layout->get_pixel_size(tooltip_width, tooltip_height); + } + int root_x, root_y; text_view.get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(activation_rectangle.get_x(), activation_rectangle.get_y(), root_x, root_y); Gdk::Rectangle rectangle; @@ -54,7 +67,7 @@ void Tooltip::adjust() { else Tooltips::drawn_tooltips_rectangle=rectangle; - move(rectangle.get_x(), rectangle.get_y()); + window->move(rectangle.get_x(), rectangle.get_y()); } void Tooltips::show(const Gdk::Rectangle& rectangle) { @@ -62,10 +75,10 @@ void Tooltips::show(const Gdk::Rectangle& rectangle) { tooltip.update(); if(rectangle.intersects(tooltip.activation_rectangle)) { tooltip.adjust(); - tooltip.show_all(); + tooltip.window->show_all(); } - else - tooltip.hide(); + else if(tooltip.window) + tooltip.window->hide(); } } @@ -73,12 +86,13 @@ void Tooltips::show() { for(auto& tooltip: *this) { tooltip.update(); tooltip.adjust(); - tooltip.show_all(); + tooltip.window->show_all(); } } void Tooltips::hide() { for(auto& tooltip: *this) { - tooltip.hide(); + if(tooltip.window) + tooltip.window->hide(); } } diff --git a/juci/tooltips.h b/juci/tooltips.h index 94b2c69..decaff4 100644 --- a/juci/tooltips.h +++ b/juci/tooltips.h @@ -4,16 +4,19 @@ #include #include -class Tooltip : public Gtk::Window { +class Tooltip { public: - Tooltip(std::shared_ptr tooltip_widget, Gtk::TextView& text_view, Glib::RefPtr start_mark, Glib::RefPtr end_mark); + Tooltip(std::function()> get_buffer, Gtk::TextView& text_view, Glib::RefPtr start_mark, Glib::RefPtr end_mark); + ~Tooltip(); void update(); void adjust(); Gdk::Rectangle activation_rectangle; + std::unique_ptr window; private: - std::shared_ptr tooltip_widget; + std::function()> get_buffer; + std::unique_ptr tooltip_widget; Glib::RefPtr start_mark; Glib::RefPtr end_mark; Gtk::TextView& text_view; From 6e99d4bcc99c80f4521eae4af8529b3d9b005c7a Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 4 Jul 2015 09:58:45 +0200 Subject: [PATCH 14/34] Minor fixes to tooltip, now hides more often. --- juci/selectiondialog.cc | 2 ++ juci/source.cc | 7 +++++++ juci/source.h | 1 + juci/tooltips.cc | 7 +++++++ juci/tooltips.h | 2 ++ juci/window.cc | 2 +- 6 files changed, 20 insertions(+), 1 deletion(-) diff --git a/juci/selectiondialog.cc b/juci/selectiondialog.cc index 8eca51d..28a45c1 100644 --- a/juci/selectiondialog.cc +++ b/juci/selectiondialog.cc @@ -2,6 +2,8 @@ SelectionDialog::SelectionDialog(Gtk::TextView& text_view): Gtk::Dialog(), text_view(text_view), list_view_text(1, false, Gtk::SelectionMode::SELECTION_SINGLE) { + property_decorated()=false; + set_skip_taskbar_hint(true); scrolled_window.set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_NEVER); list_view_text.set_enable_search(true); list_view_text.set_headers_visible(false); diff --git a/juci/source.cc b/juci/source.cc index c5010d2..f75fb72 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -218,6 +218,7 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { signal_key_press_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_press), false); signal_key_release_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_release), false); signal_motion_notify_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_motion_notify_event), false); + signal_focus_out_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_focus_out_event), false); get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_mark_set), false); } @@ -438,6 +439,12 @@ void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& i } } +bool Source::ClangView::clangview_on_focus_out_event(GdkEventFocus* event) { + diagnostic_tooltips.hide(); + type_tooltips.hide(); + return false; +} + void Source::ClangView:: highlight_cursor(clang::Token *token, std::vector *source_ranges) { diff --git a/juci/source.h b/juci/source.h index 1d8dc44..03c4db5 100644 --- a/juci/source.h +++ b/juci/source.h @@ -102,6 +102,7 @@ namespace Source { Tooltips type_tooltips; bool clangview_on_motion_notify_event(GdkEventMotion* event); void clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); + bool clangview_on_focus_out_event(GdkEventFocus* event); static clang::Index clang_index; std::map get_buffer_map() const; diff --git a/juci/tooltips.cc b/juci/tooltips.cc index 3676d4d..d06fdaa 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -37,6 +37,8 @@ void Tooltip::adjust() { //init window window=std::unique_ptr(new Gtk::Window(Gtk::WindowType::WINDOW_POPUP)); + window->set_events(Gdk::POINTER_MOTION_MASK); + window->signal_motion_notify_event().connect(sigc::mem_fun(*this, &Tooltip::tooltip_on_motion_notify_event), false); window->property_decorated()=false; window->set_accept_focus(false); window->set_skip_taskbar_hint(true); @@ -70,6 +72,11 @@ void Tooltip::adjust() { window->move(rectangle.get_x(), rectangle.get_y()); } +bool Tooltip::tooltip_on_motion_notify_event(GdkEventMotion* event) { + window->hide(); + return false; +} + void Tooltips::show(const Gdk::Rectangle& rectangle) { for(auto& tooltip: *this) { tooltip.update(); diff --git a/juci/tooltips.h b/juci/tooltips.h index decaff4..9189622 100644 --- a/juci/tooltips.h +++ b/juci/tooltips.h @@ -15,6 +15,8 @@ public: Gdk::Rectangle activation_rectangle; std::unique_ptr window; private: + bool tooltip_on_motion_notify_event(GdkEventMotion* event); + std::function()> get_buffer; std::unique_ptr tooltip_widget; Glib::RefPtr start_mark; diff --git a/juci/window.cc b/juci/window.cc index d784d23..0494c5d 100644 --- a/juci/window.cc +++ b/juci/window.cc @@ -14,7 +14,7 @@ Window::Window() : INFO("Create Window"); set_title("juCi++"); set_default_size(600, 400); - set_events(Gdk::POINTER_MOTION_MASK); + set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK); add(window_box_); keybindings_.action_group_menu()->add(Gtk::Action::create("FileQuit", "Quit juCi++"), From f4c1a2481cce9faa9297db635dc90338fc826bc7 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 5 Jul 2015 13:13:30 +0200 Subject: [PATCH 15/34] Added singleton.*, at the moment only Source::Config made singleton. Tooltips now have yellow background. Also some cleanup. --- juci/CMakeLists.txt | 2 ++ juci/config.cc | 26 ++++++++------- juci/config.h | 2 +- juci/config.json | 1 + juci/notebook.cc | 6 ++-- juci/notebook.h | 2 -- juci/singletons.cc | 3 ++ juci/singletons.h | 20 ++++++++++++ juci/source.cc | 80 +++++++++++++++++++++++---------------------- juci/source.h | 14 ++++---- juci/tooltips.cc | 4 ++- juci/window.cc | 51 ++++++++++++++--------------- juci/window.h | 12 +++---- 13 files changed, 124 insertions(+), 99 deletions(-) create mode 100644 juci/singletons.cc create mode 100644 juci/singletons.h diff --git a/juci/CMakeLists.txt b/juci/CMakeLists.txt index 0fae989..b8474db 100644 --- a/juci/CMakeLists.txt +++ b/juci/CMakeLists.txt @@ -127,6 +127,8 @@ add_executable(${project_name} terminal.cc tooltips.h tooltips.cc + singletons.h + singletons.cc ) set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) diff --git a/juci/config.cc b/juci/config.cc index 22418eb..6024824 100644 --- a/juci/config.cc +++ b/juci/config.cc @@ -2,7 +2,7 @@ #include "logging.h" MainConfig::MainConfig() : - keybindings_cfg(), source_cfg() { + keybindings_cfg() { INFO("Reading config file"); boost::property_tree::json_parser::read_json("config.json", cfg_); INFO("Config file read"); @@ -13,6 +13,7 @@ MainConfig::MainConfig() : } void MainConfig::GenerateSource() { + auto source_cfg=Singletons::Config::source(); DEBUG("Fetching source cfg"); // boost::property_tree::ptree auto source_json = cfg_.get_child("source"); @@ -22,30 +23,33 @@ void MainConfig::GenerateSource() { auto visual_json = source_json.get_child("visual"); for (auto &i : visual_json) { if (i.first == "background") { - source_cfg.background = i.second.get_value(); + source_cfg->background = i.second.get_value(); + } + if (i.first == "background_tooltips") { + source_cfg->background_tooltips = i.second.get_value(); } if (i.first == "show_line_numbers") { - source_cfg.show_line_numbers = i.second.get_value() == "1" ? true : false; + source_cfg->show_line_numbers = i.second.get_value() == "1" ? true : false; } if (i.first == "highlight_current_line") { - source_cfg.highlight_current_line = i.second.get_value() == "1" ? true : false; + source_cfg->highlight_current_line = i.second.get_value() == "1" ? true : false; } if (i.first == "font") { - source_cfg.font = i.second.get_value(); + source_cfg->font = i.second.get_value(); } } - source_cfg.tab_size = source_json.get("tab_size"); - for (unsigned c = 0; c < source_cfg.tab_size; c++) { - source_cfg.tab+=" "; + source_cfg->tab_size = source_json.get("tab_size"); + for (unsigned c = 0; c < source_cfg->tab_size; c++) { + source_cfg->tab+=" "; } for (auto &i : colors_json) { - source_cfg.tags[i.first]=i.second.get_value(); + source_cfg->tags[i.first]=i.second.get_value(); } for (auto &i : syntax_json) { - source_cfg.types[i.first]=i.second.get_value(); + source_cfg->types[i.first]=i.second.get_value(); } for (auto &i : extensions_json) { - source_cfg.extensions.emplace_back(i.second.get_value()); + source_cfg->extensions.emplace_back(i.second.get_value()); } DEBUG("Source cfg fetched"); } diff --git a/juci/config.h b/juci/config.h index bbe03cf..c6913fc 100644 --- a/juci/config.h +++ b/juci/config.h @@ -4,6 +4,7 @@ #include #include #include +#include "singletons.h" #include "keybindings.h" #include "source.h" #include "directories.h" @@ -11,7 +12,6 @@ class MainConfig { public: - Source::Config source_cfg; Terminal::Config terminal_cfg; Keybindings::Config keybindings_cfg; Directories::Config dir_cfg; diff --git a/juci/config.json b/juci/config.json index 61d9721..a831e64 100644 --- a/juci/config.json +++ b/juci/config.json @@ -34,6 +34,7 @@ ], "visual": { "background": "white", + "background_tooltips": "yellow", "font": "Monospace", "show_line_numbers": 1, "highlight_current_line": 1 diff --git a/juci/notebook.cc b/juci/notebook.cc index 6c0d90f..1398225 100644 --- a/juci/notebook.cc +++ b/juci/notebook.cc @@ -11,11 +11,9 @@ Notebook::View::View() { Notebook::Controller::Controller(Keybindings::Controller& keybindings, Terminal::Controller& terminal, - Source::Config& source_cfg, Directories::Config& dir_cfg) : terminal(terminal), - directories(dir_cfg), - source_config(source_cfg) { + directories(dir_cfg) { INFO("Create notebook"); refClipboard_ = Gtk::Clipboard::get(); view.pack1(directories.widget(), true, true); @@ -173,7 +171,7 @@ Notebook::Controller::~Controller() { void Notebook::Controller::OnOpenFile(std::string path) { INFO("Notebook open file"); INFO("Notebook create page"); - text_vec_.emplace_back(new Source::Controller(source_config, path, project_path, terminal)); + text_vec_.emplace_back(new Source::Controller(path, project_path, terminal)); scrolledtext_vec_.push_back(new Gtk::ScrolledWindow()); editor_vec_.push_back(new Gtk::HBox()); scrolledtext_vec_.back()->add(*text_vec_.back()->view); diff --git a/juci/notebook.h b/juci/notebook.h index 5aba1bf..8ff76b1 100644 --- a/juci/notebook.h +++ b/juci/notebook.h @@ -24,7 +24,6 @@ namespace Notebook { public: Controller(Keybindings::Controller& keybindings, Terminal::Controller& terminal, - Source::Config& config, Directories::Config& dir_cfg); ~Controller(); Source::View& CurrentTextView(); @@ -51,7 +50,6 @@ namespace Notebook { Glib::RefPtr m_refBuilder; Glib::RefPtr refActionGroup; Terminal::Controller& terminal; - Source::Config& source_config; std::vector scrolledtext_vec_; std::vector editor_vec_; diff --git a/juci/singletons.cc b/juci/singletons.cc new file mode 100644 index 0000000..eaa2909 --- /dev/null +++ b/juci/singletons.cc @@ -0,0 +1,3 @@ +#include "singletons.h" + +std::unique_ptr Singletons::Config::source_=std::unique_ptr(new Source::Config()); diff --git a/juci/singletons.h b/juci/singletons.h new file mode 100644 index 0000000..6098094 --- /dev/null +++ b/juci/singletons.h @@ -0,0 +1,20 @@ +#ifndef JUCI_SINGLETONS_H_ +#define JUCI_SINGLETONS_H_ + +#include "keybindings.h" +#include "source.h" +#include "directories.h" +#include "terminal.h" + +namespace Singletons { + class Config { + public: + static Source::Config *source() { + return source_.get(); + } + private: + static std::unique_ptr source_; + }; +} + +#endif // JUCI_SINGLETONS_H_ diff --git a/juci/source.cc b/juci/source.cc index f75fb72..4e10d05 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -7,6 +7,7 @@ #include #include #include "selectiondialog.h" +#include "singletons.h" bool Source::Config::legal_extension(std::string e) const { std::transform(e.begin(), e.end(),e.begin(), ::tolower); @@ -21,17 +22,23 @@ bool Source::Config::legal_extension(std::string e) const { ////////////// //// View //// ////////////// -Source::View::View(const Source::Config& config, const std::string& file_path, const std::string& project_path): -config(config), file_path(file_path), project_path(project_path) { +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(config.show_line_numbers); - set_highlight_current_line(config.highlight_current_line); + set_show_line_numbers(Singletons::Config::source()->show_line_numbers); + set_highlight_current_line(Singletons::Config::source()->highlight_current_line); sourcefile s(file_path); get_source_buffer()->get_undo_manager()->begin_not_undoable_action(); get_source_buffer()->set_text(s.get_content()); get_source_buffer()->get_undo_manager()->end_not_undoable_action(); search_start = search_end = this->get_buffer()->end(); + + override_font(Pango::FontDescription(Singletons::Config::source()->font)); + override_background_color(Gdk::RGBA(Singletons::Config::source()->background)); + for (auto &item : Singletons::Config::source()->tags) { + get_source_buffer()->create_tag(item.first)->property_foreground() = item.second; + } } string Source::View::get_line(size_t line_number) { @@ -52,7 +59,8 @@ string Source::View::get_line_before_insert() { //Basic indentation bool Source::View::on_key_press(GdkEventKey* key) { - const std::regex spaces_regex(std::string("^(")+config.tab_char+"*).*$"); + auto config=Singletons::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) { int line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); @@ -83,7 +91,7 @@ bool Source::View::on_key_press(GdkEventKey* key) { int line_end=selection_end.get_line(); for(int line=line_start;line<=line_end;line++) { Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line); - get_source_buffer()->insert(line_it, config.tab); + get_source_buffer()->insert(line_it, config->tab); } return true; } @@ -96,7 +104,7 @@ bool Source::View::on_key_press(GdkEventKey* key) { for(int line_nr=line_start;line_nr<=line_end;line_nr++) { string line=get_line(line_nr); - if(!(line.size()>=config.tab_size && line.substr(0, config.tab_size)==config.tab)) + if(!(line.size()>=config->tab_size && line.substr(0, config->tab_size)==config->tab)) return true; } @@ -104,7 +112,7 @@ bool Source::View::on_key_press(GdkEventKey* key) { Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr); Gtk::TextIter line_plus_it=line_it; - for(unsigned c=0;ctab_size;c++) line_plus_it++; get_source_buffer()->erase(line_it, line_plus_it); } @@ -119,7 +127,7 @@ bool Source::View::on_key_press(GdkEventKey* key) { string previous_line=get_line(line_nr-1); smatch sm; if(std::regex_match(previous_line, sm, spaces_regex)) { - if(line==sm[1] || line==(std::string(sm[1])+config.tab) || (line+config.tab==sm[1])) { + if(line==sm[1] || line==(std::string(sm[1])+config->tab) || (line+config->tab==sm[1])) { Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr); get_source_buffer()->erase(line_it, insert_it); } @@ -134,15 +142,9 @@ bool Source::View::on_key_press(GdkEventKey* key) { ////////////////// clang::Index Source::ClangView::clang_index(0, 0); -Source::ClangView::ClangView(const Source::Config& config, const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): -Source::View(config, file_path, project_path), terminal(terminal), -parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { - override_font(Pango::FontDescription(config.font)); - override_background_color(Gdk::RGBA(config.background)); - for (auto &item : config.tags) { - get_source_buffer()->create_tag(item.first)->property_foreground() = item.second; - } - +Source::ClangView::ClangView(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): +Source::View(file_path, project_path), terminal(terminal), +parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { int start_offset = get_source_buffer()->begin().get_offset(); int end_offset = get_source_buffer()->end().get_offset(); auto buffer_map=get_buffer_map(); @@ -332,7 +334,7 @@ void Source::ClangView::update_syntax(const std::vector &ranges) for (auto &range : ranges) { std::string type = std::to_string(range.kind); try { - config.types.at(type); + Singletons::Config::source()->types.at(type); } catch (std::exception) { continue; } @@ -347,7 +349,7 @@ void Source::ClangView::update_syntax(const std::vector &ranges) buffer->get_iter_at_line_offset(linum_start, begin); Gtk::TextIter end_iter = buffer->get_iter_at_line_offset(linum_end, end); - buffer->apply_tag_by_name(config.types.at(type), + buffer->apply_tag_by_name(Singletons::Config::source()->types.at(type), begin_iter, end_iter); } } @@ -550,10 +552,11 @@ bool Source::ClangView::on_key_release(GdkEventKey* key) { //Clang indentation //TODO: replace indentation methods with a better implementation or maybe use libclang bool Source::ClangView::on_key_press(GdkEventKey* key) { - 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_no_para_statement_regex(std::string("^(")+config.tab_char+"*)(else|try|do) *$"); - const std::regex spaces_regex(std::string("^(")+config.tab_char+"*).*$"); + auto config=Singletons::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) *\\(.*[^;}] *$"); + const std::regex no_bracket_no_para_statement_regex(std::string("^(")+config->tab_char+"*)(else|try|do) *$"); + const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$"); //Indent depending on if/else/etc and brackets if(key->keyval==GDK_KEY_Return && key->state==0) { @@ -565,35 +568,35 @@ bool Source::ClangView::on_key_press(GdkEventKey* key) { string next_line=get_line(line_nr+1); std::smatch sm2; if(std::regex_match(next_line, sm2, spaces_regex)) { - if(sm2[1].str()==sm[1].str()+config.tab) { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config.tab); + if(sm2[1].str()==sm[1].str()+config->tab) { + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); scroll_to(get_source_buffer()->get_insert()); return true; } } } - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config.tab+"\n"+sm[1].str()+"}"); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab+"\n"+sm[1].str()+"}"); auto insert_it = get_source_buffer()->get_insert()->get_iter(); - for(size_t c=0;ctab_size+sm[1].str().size();c++) insert_it--; scroll_to(get_source_buffer()->get_insert()); get_source_buffer()->place_cursor(insert_it); return true; } else if(std::regex_match(line, sm, no_bracket_statement_regex)) { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config.tab); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); scroll_to(get_source_buffer()->get_insert()); return true; } else if(std::regex_match(line, sm, no_bracket_no_para_statement_regex)) { - get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config.tab); + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); scroll_to(get_source_buffer()->get_insert()); return true; } else if(std::regex_match(line, sm, spaces_regex)) { std::smatch sm2; size_t line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); - if(line_nr>0 && sm[1].str().size()>=config.tab_size) { + if(line_nr>0 && sm[1].str().size()>=config->tab_size) { 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)) { @@ -613,15 +616,15 @@ bool Source::ClangView::on_key_press(GdkEventKey* key) { //Indent left when writing } on a new line else if(key->keyval==GDK_KEY_braceright) { string line=get_line_before_insert(); - if(line.size()>=config.tab_size) { + if(line.size()>=config->tab_size) { for(auto c: line) { - if(c!=config.tab_char) + if(c!=config->tab_char) return false; } Gtk::TextIter insert_it = get_source_buffer()->get_insert()->get_iter(); Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(insert_it.get_line()); Gtk::TextIter line_plus_it=line_it; - for(unsigned c=0;ctab_size;c++) line_plus_it++; get_source_buffer()->erase(line_it, line_plus_it); @@ -638,15 +641,14 @@ bool Source::ClangView::on_key_press(GdkEventKey* key) { // Source::Controller::Controller() // Constructor for Controller -Source::Controller::Controller(const Source::Config &config, - const std::string& file_path, std::string project_path, Terminal::Controller& terminal) { +Source::Controller::Controller(const std::string& file_path, std::string project_path, Terminal::Controller& terminal) { if(project_path=="") { project_path=boost::filesystem::path(file_path).parent_path().string(); } - if (config.legal_extension(file_path.substr(file_path.find_last_of(".") + 1))) - view=std::unique_ptr(new ClangView(config, file_path, project_path, terminal)); + if (Singletons::Config::source()->legal_extension(file_path.substr(file_path.find_last_of(".") + 1))) + view=std::unique_ptr(new ClangView(file_path, project_path, terminal)); else - view=std::unique_ptr(new GenericView(config, file_path, project_path)); + view=std::unique_ptr(new GenericView(file_path, project_path)); INFO("Source Controller with childs constructed"); } diff --git a/juci/source.h b/juci/source.h index 03c4db5..e9a1ac3 100644 --- a/juci/source.h +++ b/juci/source.h @@ -19,7 +19,7 @@ namespace Source { bool legal_extension(std::string e) const ; unsigned tab_size; bool show_line_numbers, highlight_current_line; - std::string tab, background, font; + std::string tab, background, background_tooltips, font; char tab_char=' '; std::vector extensions; std::unordered_map tags, types; @@ -59,21 +59,20 @@ namespace Source { class View : public Gsv::View { public: - View(const Source::Config& config, 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_before_insert(); std::string file_path; std::string project_path; Gtk::TextIter search_start, search_end; protected: - const Source::Config& config; bool on_key_press(GdkEventKey* key); }; // class View class GenericView : public View { public: - GenericView(const Source::Config& config, const std::string& file_path, const std::string& project_path): - View(config, file_path, project_path) { + GenericView(const std::string& file_path, const std::string& project_path): + View(file_path, project_path) { signal_key_press_event().connect(sigc::mem_fun(*this, &Source::GenericView::on_key_press), false); } private: @@ -84,7 +83,7 @@ namespace Source { class ClangView : public View { public: - ClangView(const Source::Config& config, const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal); + ClangView(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal); ~ClangView(); // inits the syntax highligthing on file open void init_syntax_highlighting(const std::map @@ -132,8 +131,7 @@ namespace Source { class Controller { public: - Controller(const Source::Config &config, - const std::string& file_path, std::string project_path, Terminal::Controller& terminal); + Controller(const std::string& file_path, std::string project_path, Terminal::Controller& terminal); Glib::RefPtr buffer(); bool is_saved = true; diff --git a/juci/tooltips.cc b/juci/tooltips.cc index d06fdaa..130e4cf 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -1,5 +1,5 @@ #include "tooltips.h" -#include +#include "singletons.h" Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle(); @@ -46,11 +46,13 @@ void Tooltip::adjust() { tooltip_widget=std::unique_ptr(new Gtk::TextView(this->get_buffer())); tooltip_widget->set_editable(false); + tooltip_widget->override_background_color(Gdk::RGBA(Singletons::Config::source()->background_tooltips)); window->add(*tooltip_widget); auto layout=Pango::Layout::create(tooltip_widget->get_pango_context()); layout->set_text(tooltip_widget->get_buffer()->get_text()); layout->get_pixel_size(tooltip_width, tooltip_height); + tooltip_height+=2; } int root_x, root_y; diff --git a/juci/window.cc b/juci/window.cc index 0494c5d..72b3ed2 100644 --- a/juci/window.cc +++ b/juci/window.cc @@ -3,65 +3,64 @@ Window::Window() : window_box_(Gtk::ORIENTATION_VERTICAL), - main_config_(), - keybindings_(main_config_.keybindings_cfg), - terminal(main_config_.terminal_cfg), - notebook(keybindings(), terminal, - main_config_.source_cfg, - main_config_.dir_cfg), - menu_(keybindings()), - api_(menu_, notebook) { + main_config(), + keybindings(main_config.keybindings_cfg), + terminal(main_config.terminal_cfg), + notebook(keybindings, terminal, + main_config.dir_cfg), + menu(keybindings), + api(menu, notebook) { INFO("Create Window"); set_title("juCi++"); set_default_size(600, 400); set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK); add(window_box_); - keybindings_.action_group_menu()->add(Gtk::Action::create("FileQuit", + keybindings.action_group_menu()->add(Gtk::Action::create("FileQuit", "Quit juCi++"), - Gtk::AccelKey(keybindings_.config_ + Gtk::AccelKey(keybindings.config_ .key_map()["quit"]), [this]() { OnWindowHide(); }); - keybindings_.action_group_menu()->add(Gtk::Action::create("FileOpenFile", + keybindings.action_group_menu()->add(Gtk::Action::create("FileOpenFile", "Open file"), - Gtk::AccelKey(keybindings_.config_ + Gtk::AccelKey(keybindings.config_ .key_map()["open_file"]), [this]() { OnOpenFile(); }); - keybindings_.action_group_menu()->add(Gtk::Action::create("FileOpenFolder", + keybindings.action_group_menu()->add(Gtk::Action::create("FileOpenFolder", "Open folder"), - Gtk::AccelKey(keybindings_.config_ + Gtk::AccelKey(keybindings.config_ .key_map()["open_folder"]), [this]() { OnFileOpenFolder(); }); - keybindings_. + keybindings. action_group_menu()-> add(Gtk::Action::create("FileSaveAs", "Save as"), - Gtk::AccelKey(keybindings_.config_ + Gtk::AccelKey(keybindings.config_ .key_map()["save_as"]), [this]() { SaveFileAs(); }); - keybindings_. + keybindings. action_group_menu()-> add(Gtk::Action::create("FileSave", "Save"), - Gtk::AccelKey(keybindings_.config_ + Gtk::AccelKey(keybindings.config_ .key_map()["save"]), [this]() { SaveFile(); }); - keybindings_. + keybindings. action_group_menu()-> add(Gtk::Action::create("ProjectCompileAndRun", "Compile And Run"), - Gtk::AccelKey(keybindings_.config_ + Gtk::AccelKey(keybindings.config_ .key_map()["compile_and_run"]), [this]() { SaveFile(); @@ -83,11 +82,11 @@ Window::Window() : } }); - keybindings_. + keybindings. action_group_menu()-> add(Gtk::Action::create("ProjectCompile", "Compile"), - Gtk::AccelKey(keybindings_.config_ + Gtk::AccelKey(keybindings.config_ .key_map()["compile"]), [this]() { SaveFile(); @@ -106,11 +105,11 @@ Window::Window() : } }); - add_accel_group(keybindings_.ui_manager_menu()->get_accel_group()); - add_accel_group(keybindings_.ui_manager_hidden()->get_accel_group()); - keybindings_.BuildMenu(); + add_accel_group(keybindings.ui_manager_menu()->get_accel_group()); + add_accel_group(keybindings.ui_manager_hidden()->get_accel_group()); + keybindings.BuildMenu(); - window_box_.pack_start(menu_.view(), Gtk::PACK_SHRINK); + window_box_.pack_start(menu.view(), Gtk::PACK_SHRINK); window_box_.pack_start(notebook.entry, Gtk::PACK_SHRINK); paned_.set_position(300); diff --git a/juci/window.h b/juci/window.h index dd63e6a..782029a 100644 --- a/juci/window.h +++ b/juci/window.h @@ -10,19 +10,17 @@ class Window : public Gtk::Window { public: Window(); - MainConfig& main_config() { return main_config_; } // std::string OnSaveFileAs(); Gtk::Box window_box_; virtual ~Window() { } - MainConfig main_config_; - Keybindings::Controller keybindings_; - Menu::Controller menu_; + MainConfig main_config; + Keybindings::Controller keybindings; + Menu::Controller menu; Notebook::Controller notebook; Terminal::Controller terminal; - PluginApi api_; - - Keybindings::Controller& keybindings() { return keybindings_; } + PluginApi api; + private: std::mutex running; Gtk::VPaned paned_; From 19494683316669f62bfbade5170a68df1d785d45 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 5 Jul 2015 14:06:38 +0200 Subject: [PATCH 16/34] Tokens now stored in Source::ClangView, leads to cleaner and faster tooltips. --- juci/source.cc | 59 ++++++++++++++++++++++++-------------------------- juci/source.h | 5 +++-- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 4e10d05..c20da63 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -241,7 +241,7 @@ init_syntax_highlighting(const std::map int end_offset, clang::Index *index) { std::vector arguments = get_compilation_commands(); - tu_ = std::unique_ptr(new clang::TranslationUnit(index, + clang_tu = std::unique_ptr(new clang::TranslationUnit(index, file_path, arguments, buffers)); @@ -256,7 +256,7 @@ get_buffer_map() const { int Source::ClangView:: reparse(const std::map &buffer) { - return tu_->ReparseTranslationUnit(file_path, buffer); + return clang_tu->ReparseTranslationUnit(file_path, buffer); } std::vector Source::ClangView:: @@ -267,7 +267,7 @@ get_autocomplete_suggestions(int line_number, int column) { buffer_map[file_path]=get_source_buffer()->get_text(get_source_buffer()->begin(), get_source_buffer()->get_insert()->get_iter()); buffer_map[file_path]+="\n"; parsing_mutex.lock(); - clang::CodeCompleteResults results(tu_.get(), + clang::CodeCompleteResults results(clang_tu.get(), file_path, buffer_map, line_number, @@ -306,14 +306,12 @@ get_compilation_commands() { std::vector Source::ClangView:: extract_tokens(int start_offset, int end_offset) { std::vector ranges; - clang::SourceLocation start(tu_.get(), file_path, start_offset); - clang::SourceLocation end(tu_.get(), file_path, end_offset); + clang::SourceLocation start(clang_tu.get(), file_path, start_offset); + clang::SourceLocation end(clang_tu.get(), file_path, end_offset); clang::SourceRange range(&start, &end); - clang::Tokens tokens(tu_.get(), &range); - tokens.get_token_types(tu_.get()); - std::vector& tks = tokens.tokens(); - update_types(tks); - for (auto &token : tks) { + clang_tokens=std::unique_ptr(new clang::Tokens(clang_tu.get(), &range)); + update_types(); + for (auto &token : *clang_tokens) { switch (token.kind()) { case 0: highlight_cursor(&token, &ranges); break; // PunctuationToken case 1: highlight_token(&token, &ranges, 702); break; // KeywordToken @@ -356,24 +354,22 @@ void Source::ClangView::update_syntax(const std::vector &ranges) void Source::ClangView::update_diagnostics() { diagnostic_tooltips.clear(); - auto diagnostics=tu_->get_diagnostics(); - for(auto& diagnostic: diagnostics) { - if(diagnostic.path==file_path) { - auto start=get_buffer()->get_iter_at_offset(diagnostic.start_location.offset); - auto end=get_buffer()->get_iter_at_offset(diagnostic.end_location.offset); + clang_tu->update_diagnostics(); + for(size_t c=0;cdiagnostics.size();c++) { + if(clang_tu->diagnostics[c].path==file_path) { + auto start=get_buffer()->get_iter_at_offset(clang_tu->diagnostics[c].start_location.offset); + auto end=get_buffer()->get_iter_at_offset(clang_tu->diagnostics[c].end_location.offset); std::string diagnostic_tag_name; - if(diagnostic.severity<=CXDiagnostic_Warning) + if(clang_tu->diagnostics[c].severity<=CXDiagnostic_Warning) diagnostic_tag_name="diagnostic_warning"; else diagnostic_tag_name="diagnostic_error"; - std::string spelling=diagnostic.spelling; - std::string severity_spelling=diagnostic.severity_spelling; - auto get_tooltip_buffer=[this, spelling, severity_spelling, diagnostic_tag_name]() { + auto get_tooltip_buffer=[this, c, diagnostic_tag_name]() { auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); - tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), severity_spelling, diagnostic_tag_name); - tooltip_buffer->insert_at_cursor(":\n"+spelling); - //TODO: Insert newlines to diagnostic.spelling (use 80 chars, then newline?) + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), clang_tu->diagnostics[c].severity_spelling, diagnostic_tag_name); + tooltip_buffer->insert_at_cursor(":\n"+clang_tu->diagnostics[c].spelling); + //TODO: Insert newlines to clang_tu->diagnostics[c].spelling (use 80 chars, then newline?) return tooltip_buffer; }; diagnostic_tooltips.emplace_back(get_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); @@ -392,11 +388,12 @@ void Source::ClangView::update_diagnostics() { } } -void Source::ClangView::update_types(std::vector& tokens) { +void Source::ClangView::update_types() { type_tooltips.clear(); - for(auto& token: tokens) { - if(token.type!="") { - clang::SourceRange range(tu_.get(), &token); + clang_tokens->update_types(clang_tu.get()); + for(size_t c=0;csize();c++) { + if((*clang_tokens)[c].type!="") { + clang::SourceRange range(clang_tu.get(), &((*clang_tokens)[c])); clang::SourceLocation start(&range, true); clang::SourceLocation end(&range, false); std::string path; @@ -406,9 +403,9 @@ void Source::ClangView::update_types(std::vector& tokens) { if(path==file_path) { auto start=get_buffer()->get_iter_at_offset(start_offset); auto end=get_buffer()->get_iter_at_offset(end_offset); - auto get_tooltip_buffer=[this, token]() { + auto get_tooltip_buffer=[this, c]() { auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); - tooltip_buffer->insert_at_cursor("Type: "+token.type); + tooltip_buffer->insert_at_cursor("Type: "+(*clang_tokens)[c].type); return tooltip_buffer; }; @@ -450,8 +447,8 @@ bool Source::ClangView::clangview_on_focus_out_event(GdkEventFocus* event) { void Source::ClangView:: highlight_cursor(clang::Token *token, std::vector *source_ranges) { - clang::SourceLocation location = token->get_source_location(tu_.get()); - clang::Cursor cursor(tu_.get(), &location); + clang::SourceLocation location = token->get_source_location(clang_tu.get()); + clang::Cursor cursor(clang_tu.get(), &location); clang::SourceRange range(&cursor); clang::SourceLocation begin(&range, true); clang::SourceLocation end(&range, false); @@ -467,7 +464,7 @@ void Source::ClangView:: highlight_token(clang::Token *token, std::vector *source_ranges, int token_kind) { - clang::SourceRange range = token->get_source_range(tu_.get()); + clang::SourceRange range = token->get_source_range(clang_tu.get()); unsigned begin_line_num, begin_offset, end_line_num, end_offset; clang::SourceLocation begin(&range, true); clang::SourceLocation end(&range, false); diff --git a/juci/source.h b/juci/source.h index e9a1ac3..fc50aea 100644 --- a/juci/source.h +++ b/juci/source.h @@ -96,7 +96,7 @@ namespace Source { std::vector extract_tokens(int, int); void update_syntax(const std::vector &locations); void update_diagnostics(); - void update_types(std::vector& tokens); + void update_types(); Tooltips diagnostic_tooltips; Tooltips type_tooltips; bool clangview_on_motion_notify_event(GdkEventMotion* event); @@ -107,7 +107,8 @@ namespace Source { std::map get_buffer_map() const; std::mutex parsing_mutex; private: - std::unique_ptr tu_; //use unique_ptr since it is not initialized in constructor + std::unique_ptr clang_tu; + std::unique_ptr clang_tokens; void highlight_token(clang::Token *token, std::vector *source_ranges, int token_kind); From d3fe9b0b2ffd828430bec07cd4d476358c4d3381 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 5 Jul 2015 19:43:35 +0200 Subject: [PATCH 17/34] Brief comments added to type info. --- juci/source.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/juci/source.cc b/juci/source.cc index c20da63..0cd4c8c 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -406,6 +406,9 @@ void Source::ClangView::update_types() { auto get_tooltip_buffer=[this, c]() { auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); tooltip_buffer->insert_at_cursor("Type: "+(*clang_tokens)[c].type); + auto brief_comment=clang_tokens->get_brief_comment(c); + if(brief_comment!="") + tooltip_buffer->insert_at_cursor("\n\n"+brief_comment); return tooltip_buffer; }; From 81a8a80a7fe56562c611231fbb3487866b5dfeda Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 5 Jul 2015 21:07:15 +0200 Subject: [PATCH 18/34] Fixed a segmentation fault/assertion error when trying to read from deleted cursors/toktens. --- juci/source.cc | 14 +++++++++----- juci/source.h | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 0cd4c8c..bdfef3c 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -183,9 +183,11 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { if(parse_thread_mapped) { INFO("Updating syntax"); update_syntax(extract_tokens(0, get_source_buffer()->get_text().size())); + update_diagnostics(); + update_types(); parsing_in_progress->done("done"); INFO("Syntax updated"); - update_diagnostics(); + clang_tokens_ready=true; } else { parse_thread_go=true; @@ -214,6 +216,7 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { get_source_buffer()->signal_changed().connect([this]() { parse_thread_mapped=false; + clang_tokens_ready=false; parse_thread_go=true; }); @@ -310,7 +313,6 @@ extract_tokens(int start_offset, int end_offset) { clang::SourceLocation end(clang_tu.get(), file_path, end_offset); clang::SourceRange range(&start, &end); clang_tokens=std::unique_ptr(new clang::Tokens(clang_tu.get(), &range)); - update_types(); for (auto &token : *clang_tokens) { switch (token.kind()) { case 0: highlight_cursor(&token, &ranges); break; // PunctuationToken @@ -406,9 +408,11 @@ void Source::ClangView::update_types() { auto get_tooltip_buffer=[this, c]() { auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); tooltip_buffer->insert_at_cursor("Type: "+(*clang_tokens)[c].type); - auto brief_comment=clang_tokens->get_brief_comment(c); - if(brief_comment!="") - tooltip_buffer->insert_at_cursor("\n\n"+brief_comment); + if(clang_tokens_ready) { + auto brief_comment=clang_tokens->get_brief_comment(c); + if(brief_comment!="") + tooltip_buffer->insert_at_cursor("\n\n"+brief_comment); + } return tooltip_buffer; }; diff --git a/juci/source.h b/juci/source.h index fc50aea..702bcfc 100644 --- a/juci/source.h +++ b/juci/source.h @@ -109,6 +109,7 @@ namespace Source { private: std::unique_ptr clang_tu; std::unique_ptr clang_tokens; + bool clang_tokens_ready=false; void highlight_token(clang::Token *token, std::vector *source_ranges, int token_kind); From f13ca76ad3ef701846643b91ae9cad6b3ca7386b Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 5 Jul 2015 21:44:40 +0200 Subject: [PATCH 19/34] Small cleanup, and fixed potential segmentation/assertion fault. Tooltips now also get hidden when using mouse scroll. --- juci/source.cc | 62 ++++++++++++++++++++++++++++++++------------------ juci/source.h | 3 ++- juci/window.cc | 2 +- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index bdfef3c..cc78445 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -185,9 +185,9 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { update_syntax(extract_tokens(0, get_source_buffer()->get_text().size())); update_diagnostics(); update_types(); + clang_updated=true; parsing_in_progress->done("done"); INFO("Syntax updated"); - clang_tokens_ready=true; } else { parse_thread_go=true; @@ -216,7 +216,7 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { get_source_buffer()->signal_changed().connect([this]() { parse_thread_mapped=false; - clang_tokens_ready=false; + clang_updated=false; parse_thread_go=true; }); @@ -224,6 +224,7 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { signal_key_release_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_release), false); signal_motion_notify_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_motion_notify_event), false); signal_focus_out_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_focus_out_event), false); + signal_scroll_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_scroll_event), false); get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_mark_set), false); } @@ -408,11 +409,9 @@ void Source::ClangView::update_types() { auto get_tooltip_buffer=[this, c]() { auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); tooltip_buffer->insert_at_cursor("Type: "+(*clang_tokens)[c].type); - if(clang_tokens_ready) { - auto brief_comment=clang_tokens->get_brief_comment(c); - if(brief_comment!="") - tooltip_buffer->insert_at_cursor("\n\n"+brief_comment); - } + auto brief_comment=clang_tokens->get_brief_comment(c); + if(brief_comment!="") + tooltip_buffer->insert_at_cursor("\n\n"+brief_comment); return tooltip_buffer; }; @@ -423,34 +422,53 @@ void Source::ClangView::update_types() { } bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) { - Gdk::Rectangle rectangle(event->x, event->y, 1, 1); - diagnostic_tooltips.init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); + if(clang_updated) { + Gdk::Rectangle rectangle(event->x, event->y, 1, 1); + diagnostic_tooltips.init(); + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + else { + type_tooltips.hide(); + diagnostic_tooltips.hide(); + } + return false; } void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { if(mark->get_name()=="insert") { - Gdk::Rectangle rectangle; - get_iter_location(iterator, rectangle); - int location_window_x, location_window_y; - buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_window_x, location_window_y); - rectangle.set_x(location_window_x-2); - rectangle.set_y(location_window_y); - rectangle.set_width(4); - diagnostic_tooltips.init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); + if(clang_updated) { + Gdk::Rectangle rectangle; + get_iter_location(iterator, rectangle); + int location_window_x, location_window_y; + buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_window_x, location_window_y); + rectangle.set_x(location_window_x-2); + rectangle.set_y(location_window_y); + rectangle.set_width(4); + diagnostic_tooltips.init(); + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + else { + type_tooltips.hide(); + diagnostic_tooltips.hide(); + } } } bool Source::ClangView::clangview_on_focus_out_event(GdkEventFocus* event) { - diagnostic_tooltips.hide(); type_tooltips.hide(); + diagnostic_tooltips.hide(); return false; } +bool Source::ClangView::clangview_on_scroll_event(GdkEventScroll* event) { + type_tooltips.hide(); + diagnostic_tooltips.hide(); + return false; +} + void Source::ClangView:: highlight_cursor(clang::Token *token, std::vector *source_ranges) { diff --git a/juci/source.h b/juci/source.h index 702bcfc..0a4f084 100644 --- a/juci/source.h +++ b/juci/source.h @@ -102,6 +102,7 @@ namespace Source { bool clangview_on_motion_notify_event(GdkEventMotion* event); void clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); bool clangview_on_focus_out_event(GdkEventFocus* event); + bool clangview_on_scroll_event(GdkEventScroll* event); static clang::Index clang_index; std::map get_buffer_map() const; @@ -109,7 +110,7 @@ namespace Source { private: std::unique_ptr clang_tu; std::unique_ptr clang_tokens; - bool clang_tokens_ready=false; + bool clang_updated=false; void highlight_token(clang::Token *token, std::vector *source_ranges, int token_kind); diff --git a/juci/window.cc b/juci/window.cc index 72b3ed2..e281538 100644 --- a/juci/window.cc +++ b/juci/window.cc @@ -13,7 +13,7 @@ Window::Window() : INFO("Create Window"); set_title("juCi++"); set_default_size(600, 400); - set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK); + set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK); add(window_box_); keybindings.action_group_menu()->add(Gtk::Action::create("FileQuit", "Quit juCi++"), From 0aa2b45b37ef764925d30cb4afbe7881431512c5 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 6 Jul 2015 10:24:04 +0200 Subject: [PATCH 20/34] Added slight delay on tooltips when moving cursor. --- juci/source.cc | 41 +++++++++++++++++++++++++---------------- juci/source.h | 4 +++- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index cc78445..3fff1b6 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -9,6 +9,10 @@ #include "selectiondialog.h" #include "singletons.h" +namespace sigc { + SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE +} + bool Source::Config::legal_extension(std::string e) const { std::transform(e.begin(), e.end(),e.begin(), ::tolower); if (find(extensions.begin(), extensions.end(), e) != extensions.end()) { @@ -422,6 +426,7 @@ void Source::ClangView::update_types() { } bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) { + on_mark_set_timeout_connection.disconnect(); if(clang_updated) { Gdk::Rectangle rectangle(event->x, event->y, 1, 1); diagnostic_tooltips.init(); @@ -438,32 +443,36 @@ bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { if(mark->get_name()=="insert") { - if(clang_updated) { - Gdk::Rectangle rectangle; - get_iter_location(iterator, rectangle); - int location_window_x, location_window_y; - buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_window_x, location_window_y); - rectangle.set_x(location_window_x-2); - rectangle.set_y(location_window_y); - rectangle.set_width(4); - diagnostic_tooltips.init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); - } - else { - type_tooltips.hide(); - diagnostic_tooltips.hide(); - } + on_mark_set_timeout_connection.disconnect(); + on_mark_set_timeout_connection=Glib::signal_timeout().connect([this]() { + if(clang_updated) { + Gdk::Rectangle rectangle; + get_iter_location(get_buffer()->get_insert()->get_iter(), rectangle); + int location_window_x, location_window_y; + buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_window_x, location_window_y); + rectangle.set_x(location_window_x-2); + rectangle.set_y(location_window_y); + rectangle.set_width(4); + diagnostic_tooltips.init(); + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + return false; + }, 500); + type_tooltips.hide(); + diagnostic_tooltips.hide(); } } bool Source::ClangView::clangview_on_focus_out_event(GdkEventFocus* event) { + on_mark_set_timeout_connection.disconnect(); type_tooltips.hide(); diagnostic_tooltips.hide(); return false; } bool Source::ClangView::clangview_on_scroll_event(GdkEventScroll* event) { + on_mark_set_timeout_connection.disconnect(); type_tooltips.hide(); diagnostic_tooltips.hide(); return false; diff --git a/juci/source.h b/juci/source.h index 0a4f084..ceafe11 100644 --- a/juci/source.h +++ b/juci/source.h @@ -85,6 +85,7 @@ namespace Source { public: ClangView(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal); ~ClangView(); + private: // inits the syntax highligthing on file open void init_syntax_highlighting(const std::map &buffers, @@ -101,13 +102,14 @@ namespace Source { Tooltips type_tooltips; bool clangview_on_motion_notify_event(GdkEventMotion* event); void clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); + sigc::connection on_mark_set_timeout_connection; bool clangview_on_focus_out_event(GdkEventFocus* event); bool clangview_on_scroll_event(GdkEventScroll* event); static clang::Index clang_index; std::map get_buffer_map() const; std::mutex parsing_mutex; - private: + std::unique_ptr clang_tu; std::unique_ptr clang_tokens; bool clang_updated=false; From 54a1e7c90dd04f382fd317f0be01188ca317ba30 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 7 Jul 2015 23:15:58 +0200 Subject: [PATCH 21/34] Made new selectiondialog for code-completion. Might be in need of some smaller fixes. Max width set to halv of width of sourceview. --- juci/selectiondialog.cc | 229 ++++++++++++++++++++++++++++------------ juci/selectiondialog.h | 25 +++-- juci/source.cc | 27 +++-- juci/source.h | 2 + 4 files changed, 198 insertions(+), 85 deletions(-) diff --git a/juci/selectiondialog.cc b/juci/selectiondialog.cc index 28a45c1..d812b20 100644 --- a/juci/selectiondialog.cc +++ b/juci/selectiondialog.cc @@ -1,87 +1,180 @@ #include "selectiondialog.h" +#include +using namespace std; -SelectionDialog::SelectionDialog(Gtk::TextView& text_view): Gtk::Dialog(), text_view(text_view), - list_view_text(1, false, Gtk::SelectionMode::SELECTION_SINGLE) { - property_decorated()=false; - set_skip_taskbar_hint(true); - scrolled_window.set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_NEVER); - 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); +SelectionDialog::SelectionDialog(Gtk::TextView& text_view): text_view(text_view) { + } -void SelectionDialog::show(const std::map& rows) { - for (auto &i : rows) { - list_view_text.append(i.first); - } - scrolled_window.add(list_view_text); - get_vbox()->pack_start(scrolled_window); - set_transient_for((Gtk::Window&)(*text_view.get_toplevel())); - show_all(); - int popup_x = get_width(); - int popup_y = rows.size() * 20; - adjust(popup_x, popup_y); +void SelectionDialog::show() { + if(rows.size()==0) + return; + + window=std::unique_ptr(new Gtk::Window(Gtk::WindowType::WINDOW_POPUP)); + scrolled_window=std::unique_ptr(new Gtk::ScrolledWindow()); + list_view_text=std::unique_ptr(new Gtk::ListViewText(1, false, Gtk::SelectionMode::SELECTION_SINGLE)); - list_view_text.signal_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*) { - if(on_select) - on_select(list_view_text); - response(Gtk::RESPONSE_DELETE_EVENT); + window->set_default_size(0, 0); + 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_search_entry(search_entry); + list_view_text->set_hover_selection(true); + 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_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*) { + if(shown) { + select(); + } + }); + list_view_text->signal_realize().connect([this](){ + resize(); }); - signal_focus_out_event().connect(sigc::mem_fun(*this, &SelectionDialog::close), false); + if(start_mark) + text_view.get_buffer()->delete_mark(start_mark); + start_mark=text_view.get_buffer()->create_mark(text_view.get_buffer()->get_insert()->get_iter()); + start_offset=start_mark->get_iter().get_offset(); + list_view_text->clear_items(); + for (auto &i : rows) { + list_view_text->append(i.first); + } - run(); + scrolled_window->add(*list_view_text); + window->add(*scrolled_window); + + if(rows.size()>0) { + list_view_text->get_selection()->select(*list_view_text->get_model()->children().begin()); + list_view_text->scroll_to_row(list_view_text->get_selection()->get_selected_rows()[0]); + } + + move(); + + window->show_all(); + shown=true; } -bool SelectionDialog::close(GdkEventFocus*) { - response(Gtk::RESPONSE_DELETE_EVENT); - return true; +void SelectionDialog::hide() { + window->hide(); + shown=false; } -void SelectionDialog::adjust(int current_x, int current_y) { - INFO("SelectionDialog set size"); - int view_x = text_view.get_width(); - int view_y = 150; - bool is_never_scroll_x = true; - bool is_never_scroll_y = true; - if (current_x > view_x) { - current_x = view_x; - is_never_scroll_x = false; +void SelectionDialog::select(bool hide_window) { + auto selected=list_view_text->get_selected(); + if(selected.size()>0) { + std::string select = rows.at(list_view_text->get_text(selected[0])); + text_view.get_buffer()->erase(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); + text_view.get_buffer()->insert(start_mark->get_iter(), select); } - if (current_y > view_y) { - current_y = view_y; - is_never_scroll_y = false; + if(hide_window) { + hide(); } - scrolled_window.set_size_request(current_x, current_y); - if (!is_never_scroll_x && !is_never_scroll_y) { - scrolled_window.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC, Gtk::PolicyType::POLICY_AUTOMATIC); - } else if (!is_never_scroll_x && is_never_scroll_y) { - scrolled_window.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC, Gtk::PolicyType::POLICY_NEVER); - } else if (is_never_scroll_x && !is_never_scroll_y) { - scrolled_window.set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_AUTOMATIC); +} + +bool SelectionDialog::on_key_release(GdkEventKey* key) { + if(key->keyval==GDK_KEY_Down || key->keyval==GDK_KEY_Up) + return false; + + if(start_offset>text_view.get_buffer()->get_insert()->get_iter().get_offset()) { + hide(); + } + else { + auto text=text_view.get_buffer()->get_text(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); + if(text.size()>0) { + search_entry.set_text(text); + list_view_text->set_search_entry(search_entry); + } } - INFO("SelectionDialog set position"); - Gdk::Rectangle temp1, temp2; - text_view.get_cursor_locations(text_view.get_buffer()->get_insert()->get_iter(), temp1, temp2); - int view_edge_x = 0; - int view_edge_y = 0; - int x, y; - text_view.buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_WIDGET, - temp1.get_x(), temp1.get_y(), x, y); - Glib::RefPtr gdkw = text_view.get_window(Gtk::TextWindowType::TEXT_WINDOW_WIDGET); - gdkw->get_origin(view_edge_x, view_edge_y); + return false; +} - x += view_edge_x; - y += view_edge_y; - if ((view_edge_x-x)*-1 > text_view.get_width()-current_x) { - x -= current_x; - if (x < view_edge_x) x = view_edge_x; +bool SelectionDialog::on_key_press(GdkEventKey* key) { + if(key->keyval>=GDK_KEY_0 && key->keyval<=GDK_KEY_9) + return false; + if(key->keyval>=GDK_KEY_A && key->keyval<=GDK_KEY_Z) + return false; + if(key->keyval>=GDK_KEY_a && key->keyval<=GDK_KEY_z) + return false; + if(key->keyval==GDK_KEY_Shift_L || key->keyval==GDK_KEY_Shift_R || key->keyval==GDK_KEY_Alt_L || key->keyval==GDK_KEY_Alt_R || key->keyval==GDK_KEY_Control_L || key->keyval==GDK_KEY_Control_R || key->keyval==GDK_KEY_Meta_L || key->keyval==GDK_KEY_Meta_R) + return false; + if(key->keyval==GDK_KEY_underscore) + return false; + if(key->keyval==GDK_KEY_BackSpace) + return false; + if(key->keyval==GDK_KEY_Down) { + auto it=list_view_text->get_selection()->get_selected(); + if(it) { + it++; + if(it) { + list_view_text->get_selection()->select(it); + list_view_text->scroll_to_row(list_view_text->get_selection()->get_selected_rows()[0]); + } + } + select(false); + return true; + } + if(key->keyval==GDK_KEY_Up) { + auto it=list_view_text->get_selection()->get_selected(); + if(it) { + it--; + if(it) { + list_view_text->get_selection()->select(it); + list_view_text->scroll_to_row(list_view_text->get_selection()->get_selected_rows()[0]); + } + } + select(false); + return true; } - if ((view_edge_y-y)*-1 > text_view.get_height()-current_y) { - y -= (current_y+14) + 15; - if (x < view_edge_y) y = view_edge_y +15; + if(key->keyval==GDK_KEY_Return) { + select(); + return true; } - move(x, y+15); -} \ No newline at end of file + if(key->keyval==GDK_KEY_ISO_Left_Tab || key->keyval==GDK_KEY_Tab) { + select(); + return true; + } + hide(); + return false; +} + +void SelectionDialog::move() { + INFO("SelectionDialog set position"); + Gdk::Rectangle rectangle; + text_view.get_iter_location(start_mark->get_iter(), rectangle); + int buffer_x=rectangle.get_x(); + int buffer_y=rectangle.get_y()+rectangle.get_height(); + int window_x, window_y; + text_view.buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, buffer_x, buffer_y, window_x, window_y); + int root_x, root_y; + text_view.get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(window_x, window_y, root_x, root_y); + window->move(root_x, root_y+1); //TODO: replace 1 with some margin +} + +void SelectionDialog::resize() { + INFO("SelectionDialog set size"); + + if(list_view_text->get_realized()) { + int row_width=0, row_height; + Gdk::Rectangle rect; + list_view_text->get_cell_area(list_view_text->get_model()->get_path(list_view_text->get_model()->children().begin()), *(list_view_text->get_column(0)), rect); + row_width=rect.get_width(); + row_height=rect.get_height(); + + row_width+=rect.get_x()*2; //TODO: Add correct margin x and y + row_height+=rect.get_y()*2; + + if(row_width>text_view.get_width()/2) + row_width=text_view.get_width()/2; + else + scrolled_window->set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_AUTOMATIC); + + int window_height=std::min(row_height*(int)rows.size(), row_height*10); + window->resize(row_width, window_height); + } +} diff --git a/juci/selectiondialog.h b/juci/selectiondialog.h index f8479ce..e13bc95 100644 --- a/juci/selectiondialog.h +++ b/juci/selectiondialog.h @@ -3,22 +3,31 @@ #include "gtkmm.h" #include "logging.h" -#include "source.h" -class SelectionDialog : public Gtk::Dialog { +class SelectionDialog { public: SelectionDialog(Gtk::TextView& text_view); - void show(const std::map& rows); + void show(); + void hide(); bool close(GdkEventFocus*); + void select(bool hide_window=true); + void move(); + bool on_key_release(GdkEventKey* key); + bool on_key_press(GdkEventKey* key); - std::function on_select; - + std::map rows; + + bool shown=false; + Gtk::Entry search_entry; + Glib::RefPtr start_mark; + int start_offset; private: - void adjust(int current_x, int current_y); + void resize(); Gtk::TextView& text_view; - Gtk::ScrolledWindow scrolled_window; - Gtk::ListViewText list_view_text; + std::unique_ptr window; + std::unique_ptr scrolled_window; + std::unique_ptr list_view_text; }; #endif // JUCI_SELECTIONDIALOG_H_ \ No newline at end of file diff --git a/juci/source.cc b/juci/source.cc index 3fff1b6..f0009de 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -6,7 +6,6 @@ #include "logging.h" #include #include -#include "selectiondialog.h" #include "singletons.h" namespace sigc { @@ -147,7 +146,7 @@ bool Source::View::on_key_press(GdkEventKey* key) { clang::Index Source::ClangView::clang_index(0, 0); Source::ClangView::ClangView(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): -Source::View(file_path, project_path), terminal(terminal), +Source::View(file_path, project_path), terminal(terminal), selection_dialog(*this), parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { int start_offset = get_source_buffer()->begin().get_offset(); int end_offset = get_source_buffer()->end().get_offset(); @@ -443,6 +442,9 @@ bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { if(mark->get_name()=="insert") { + if(selection_dialog.shown) { + selection_dialog.hide(); + } on_mark_set_timeout_connection.disconnect(); on_mark_set_timeout_connection=Glib::signal_timeout().connect([this]() { if(clang_updated) { @@ -472,6 +474,9 @@ bool Source::ClangView::clangview_on_focus_out_event(GdkEventFocus* event) { } bool Source::ClangView::clangview_on_scroll_event(GdkEventScroll* event) { + if(selection_dialog.shown) + selection_dialog.move(); + on_mark_set_timeout_connection.disconnect(); type_tooltips.hide(); diagnostic_tooltips.hide(); @@ -511,6 +516,11 @@ highlight_token(clang::Token *token, } bool Source::ClangView::on_key_release(GdkEventKey* key) { + if(selection_dialog.shown) { + if(selection_dialog.on_key_release(key)) + return true; + } + INFO("Source::ClangView::on_key_release getting iters"); // Get function to fill popup with suggests item vector under is for testing Gtk::TextIter beg = get_source_buffer()->get_insert()->get_iter(); @@ -569,13 +579,8 @@ bool Source::ClangView::on_key_release(GdkEventKey* key) { if (rows.empty()) { rows["No suggestions found..."] = ""; } - - SelectionDialog selection_dialog(*this); - selection_dialog.on_select=[this, &rows](Gtk::ListViewText& list_view_text){ - std::string selected = rows.at(list_view_text.get_text(list_view_text.get_selected()[0])); - get_source_buffer()->insert_at_cursor(selected); - }; - selection_dialog.show(rows); + selection_dialog.rows=std::move(rows); + selection_dialog.show(); return true; } @@ -583,6 +588,10 @@ bool Source::ClangView::on_key_release(GdkEventKey* key) { //Clang indentation //TODO: replace indentation methods with a better implementation or maybe use libclang bool Source::ClangView::on_key_press(GdkEventKey* key) { + if(selection_dialog.shown) { + if(selection_dialog.on_key_press(key)) + return true; + } auto config=Singletons::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) *\\(.*[^;}] *$"); diff --git a/juci/source.h b/juci/source.h index ceafe11..f06d23b 100644 --- a/juci/source.h +++ b/juci/source.h @@ -12,6 +12,7 @@ #include "gtksourceviewmm.h" #include "terminal.h" #include "tooltips.h" +#include "selectiondialog.h" namespace Source { class Config { @@ -93,6 +94,7 @@ namespace Source { int end_offset, clang::Index *index); std::vector get_autocomplete_suggestions(int line_number, int column); + SelectionDialog selection_dialog; int reparse(const std::map &buffers); std::vector extract_tokens(int, int); void update_syntax(const std::vector &locations); From 11468432faf8df690ed54b5187df261278b3ede0 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 8 Jul 2015 11:38:29 +0200 Subject: [PATCH 22/34] Parameters are now marked as selected after using autocomplete. --- juci/config.cc | 11 +++++++---- juci/config.json | 1 + juci/selectiondialog.cc | 18 +++++++++++++++++- juci/source.cc | 5 +++++ juci/source.h | 2 +- 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/juci/config.cc b/juci/config.cc index 6024824..9fa2a69 100644 --- a/juci/config.cc +++ b/juci/config.cc @@ -25,16 +25,19 @@ void MainConfig::GenerateSource() { if (i.first == "background") { source_cfg->background = i.second.get_value(); } - if (i.first == "background_tooltips") { + else if (i.first == "background_selected") { + source_cfg->background_selected = i.second.get_value(); + } + else if (i.first == "background_tooltips") { source_cfg->background_tooltips = i.second.get_value(); } - if (i.first == "show_line_numbers") { + else if (i.first == "show_line_numbers") { source_cfg->show_line_numbers = i.second.get_value() == "1" ? true : false; } - if (i.first == "highlight_current_line") { + else if (i.first == "highlight_current_line") { source_cfg->highlight_current_line = i.second.get_value() == "1" ? true : false; } - if (i.first == "font") { + else if (i.first == "font") { source_cfg->font = i.second.get_value(); } } diff --git a/juci/config.json b/juci/config.json index a831e64..42effbb 100644 --- a/juci/config.json +++ b/juci/config.json @@ -34,6 +34,7 @@ ], "visual": { "background": "white", + "background_selected": "blue", "background_tooltips": "yellow", "font": "Monospace", "show_line_numbers": 1, diff --git a/juci/selectiondialog.cc b/juci/selectiondialog.cc index d812b20..00ca3f6 100644 --- a/juci/selectiondialog.cc +++ b/juci/selectiondialog.cc @@ -1,4 +1,5 @@ #include "selectiondialog.h" +#include #include using namespace std; @@ -66,13 +67,28 @@ void SelectionDialog::hide() { void SelectionDialog::select(bool hide_window) { auto selected=list_view_text->get_selected(); + std::string select; if(selected.size()>0) { - std::string select = rows.at(list_view_text->get_text(selected[0])); + select = rows.at(list_view_text->get_text(selected[0])); text_view.get_buffer()->erase(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); text_view.get_buffer()->insert(start_mark->get_iter(), select); } if(hide_window) { hide(); + char find_char=select.back(); + if(find_char==')' || find_char=='>') { + if(find_char==')') + find_char='('; + else + find_char='<'; + size_t pos=select.find(find_char); + if(pos!=std::string::npos) { + auto start_offset=start_mark->get_iter().get_offset()+pos+1; + auto end_offset=start_mark->get_iter().get_offset()+select.size()-1; + if(start_offset!=end_offset) + text_view.get_buffer()->select_range(text_view.get_buffer()->get_iter_at_offset(start_offset), text_view.get_buffer()->get_iter_at_offset(end_offset)); + } + } } } diff --git a/juci/source.cc b/juci/source.cc index f0009de..10d637f 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -38,7 +38,9 @@ file_path(file_path), project_path(project_path) { search_start = search_end = this->get_buffer()->end(); override_font(Pango::FontDescription(Singletons::Config::source()->font)); + override_background_color(Gdk::RGBA(Singletons::Config::source()->background)); + override_background_color(Gdk::RGBA(Singletons::Config::source()->background_selected), Gtk::StateFlags::STATE_FLAG_SELECTED); for (auto &item : Singletons::Config::source()->tags) { get_source_buffer()->create_tag(item.first)->property_foreground() = item.second; } @@ -441,6 +443,9 @@ bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) } void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { + if(get_buffer()->get_has_selection() && mark->get_name()=="selection_bound") + on_mark_set_timeout_connection.disconnect(); + if(mark->get_name()=="insert") { if(selection_dialog.shown) { selection_dialog.hide(); diff --git a/juci/source.h b/juci/source.h index f06d23b..bd4cb62 100644 --- a/juci/source.h +++ b/juci/source.h @@ -20,7 +20,7 @@ namespace Source { bool legal_extension(std::string e) const ; unsigned tab_size; bool show_line_numbers, highlight_current_line; - std::string tab, background, background_tooltips, font; + std::string tab, background, background_selected, background_tooltips, font; char tab_char=' '; std::vector extensions; std::unordered_map tags, types; From 459cfe4823f697f8c3b660ecaa69d01580889d53 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 8 Jul 2015 16:10:14 +0200 Subject: [PATCH 23/34] Autocomplete no longer freezes the application while loading. --- juci/source.cc | 103 ++++++++++++++++++++++++++++++++----------------- juci/source.h | 6 ++- 2 files changed, 73 insertions(+), 36 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 10d637f..f75182f 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -186,13 +186,16 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { parsing_in_progress=this->terminal.print_in_progress("Parsing "+file_path); parse_done.connect([this](){ if(parse_thread_mapped) { - INFO("Updating syntax"); - update_syntax(extract_tokens(0, get_source_buffer()->get_text().size())); - update_diagnostics(); - update_types(); - clang_updated=true; + if(parsing_mutex.try_lock()) { + INFO("Updating syntax"); + update_syntax(extract_tokens(0, get_source_buffer()->get_text().size())); + update_diagnostics(); + update_types(); + clang_updated=true; + parsing_mutex.unlock(); + INFO("Syntax updated"); + } parsing_in_progress->done("done"); - INFO("Syntax updated"); } else { parse_thread_go=true; @@ -219,7 +222,13 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { } }); + autocomplete_done.connect([this](){ + if(autocomplete_done_function) + autocomplete_done_function(); + }); + get_source_buffer()->signal_changed().connect([this]() { + autocomplete_cancel=true; parse_thread_mapped=false; clang_updated=false; parse_thread_go=true; @@ -269,13 +278,9 @@ reparse(const std::map &buffer) { } std::vector Source::ClangView:: -get_autocomplete_suggestions(int line_number, int column) { +get_autocomplete_suggestions(int line_number, int column, std::map& buffer_map) { INFO("Getting auto complete suggestions"); std::vector suggestions; - std::map buffer_map; - buffer_map[file_path]=get_source_buffer()->get_text(get_source_buffer()->begin(), get_source_buffer()->get_insert()->get_iter()); - buffer_map[file_path]+="\n"; - parsing_mutex.lock(); clang::CodeCompleteResults results(clang_tu.get(), file_path, buffer_map, @@ -289,7 +294,6 @@ get_autocomplete_suggestions(int line_number, int column) { } suggestions.emplace_back(chunks); } - parsing_mutex.unlock(); DEBUG("Number of suggestions"); DEBUG_VAR(suggestions.size()); return suggestions; @@ -561,33 +565,62 @@ bool Source::ClangView::on_key_release(GdkEventKey* key) { } else { return false; } - INFO("Source::ClangView::on_key_release getting autocompletions"); - std::vector acdata=get_autocomplete_suggestions(beg.get_line()+1, - beg.get_line_offset()+2); - std::map rows; - 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; + if(!autocomplete_running) { + autocomplete_running=true; + autocomplete_cancel=false; + INFO("Source::ClangView::on_key_release getting autocompletions"); + std::shared_ptr > ac_data=std::make_shared >(); + autocomplete_done_function=[this, ac_data](){ + if(!autocomplete_cancel) { + std::map rows; + for (auto &data : *ac_data) { + 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; + } + } + if (ss.str().length() > 0) { // if length is 0 the result is empty + rows[ss.str() + " --> " + return_value] = ss.str(); + } + } + if (rows.empty()) { + rows["No suggestions found..."] = ""; + } + selection_dialog.rows=std::move(rows); + selection_dialog.show(); } - } - if (ss.str().length() > 0) { // if length is 0 the result is empty - rows[ss.str() + " --> " + return_value] = ss.str(); - } + autocomplete_running=false; + }; + + std::shared_ptr > buffer_map=std::make_shared >(); + (*buffer_map)[file_path]=get_buffer()->get_text(get_buffer()->begin(), get_buffer()->get_insert()->get_iter()); + (*buffer_map)[file_path]+="\n"; + auto line_nr=beg.get_line()+1; + auto column_nr=beg.get_line_offset()+2; + std::thread autocomplete_thread([this, ac_data, line_nr, column_nr, buffer_map](){ + parsing_mutex.lock(); + *ac_data=move(get_autocomplete_suggestions(line_nr, column_nr, *buffer_map)); + + autocomplete_done(); + parsing_mutex.unlock(); + }); + + autocomplete_thread.detach(); } - if (rows.empty()) { - rows["No suggestions found..."] = ""; + else { + std::map rows; + rows["Autocomplete already running, try again."] = ""; + selection_dialog.rows=std::move(rows); + selection_dialog.show(); } - selection_dialog.rows=std::move(rows); - selection_dialog.show(); - return true; + return false; } //Clang indentation diff --git a/juci/source.h b/juci/source.h index bd4cb62..e65b34a 100644 --- a/juci/source.h +++ b/juci/source.h @@ -93,7 +93,7 @@ namespace Source { int start_offset, int end_offset, clang::Index *index); - std::vector get_autocomplete_suggestions(int line_number, int column); + std::vector get_autocomplete_suggestions(int line_number, int column, std::map& buffer_map); SelectionDialog selection_dialog; int reparse(const std::map &buffers); std::vector extract_tokens(int, int); @@ -126,6 +126,10 @@ namespace Source { Terminal::Controller& terminal; std::shared_ptr parsing_in_progress; + Glib::Dispatcher autocomplete_done; + std::function autocomplete_done_function; + bool autocomplete_running=false; + bool autocomplete_cancel=false; Glib::Dispatcher parse_done; Glib::Dispatcher parse_start; std::thread parse_thread; From a89c76c4d704a4ea9240772cbc9d60e9bf73d6e3 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 8 Jul 2015 16:49:59 +0200 Subject: [PATCH 24/34] Small fix to autocompletion. --- juci/source.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/juci/source.cc b/juci/source.cc index f75182f..6df1ca3 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -451,6 +451,7 @@ void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& i on_mark_set_timeout_connection.disconnect(); if(mark->get_name()=="insert") { + autocomplete_cancel=true; if(selection_dialog.shown) { selection_dialog.hide(); } @@ -606,7 +607,6 @@ bool Source::ClangView::on_key_release(GdkEventKey* key) { std::thread autocomplete_thread([this, ac_data, line_nr, column_nr, buffer_map](){ parsing_mutex.lock(); *ac_data=move(get_autocomplete_suggestions(line_nr, column_nr, *buffer_map)); - autocomplete_done(); parsing_mutex.unlock(); }); From 23e1a5992db022d6e96aa57bbc3ec4d8d1a3c53e Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 8 Jul 2015 17:29:42 +0200 Subject: [PATCH 25/34] Minor fix to SelectionDialog. --- juci/selectiondialog.cc | 28 ++++++++++++++-------------- juci/selectiondialog.h | 8 +++++--- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/juci/selectiondialog.cc b/juci/selectiondialog.cc index 00ca3f6..6a703ad 100644 --- a/juci/selectiondialog.cc +++ b/juci/selectiondialog.cc @@ -58,6 +58,7 @@ void SelectionDialog::show() { window->show_all(); shown=true; + selected=false; } void SelectionDialog::hide() { @@ -66,6 +67,7 @@ void SelectionDialog::hide() { } void SelectionDialog::select(bool hide_window) { + selected=true; auto selected=list_view_text->get_selected(); std::string select; if(selected.size()>0) { @@ -111,18 +113,20 @@ bool SelectionDialog::on_key_release(GdkEventKey* key) { } bool SelectionDialog::on_key_press(GdkEventKey* key) { - if(key->keyval>=GDK_KEY_0 && key->keyval<=GDK_KEY_9) - return false; - if(key->keyval>=GDK_KEY_A && key->keyval<=GDK_KEY_Z) - return false; - if(key->keyval>=GDK_KEY_a && key->keyval<=GDK_KEY_z) + if((key->keyval>=GDK_KEY_0 && key->keyval<=GDK_KEY_9) || + (key->keyval>=GDK_KEY_A && key->keyval<=GDK_KEY_Z) || + (key->keyval>=GDK_KEY_a && key->keyval<=GDK_KEY_z) || + key->keyval==GDK_KEY_underscore || key->keyval==GDK_KEY_BackSpace) { + if(selected) { + text_view.get_buffer()->erase(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); + selected=false; + if(key->keyval==GDK_KEY_BackSpace) + return true; + } return false; + } if(key->keyval==GDK_KEY_Shift_L || key->keyval==GDK_KEY_Shift_R || key->keyval==GDK_KEY_Alt_L || key->keyval==GDK_KEY_Alt_R || key->keyval==GDK_KEY_Control_L || key->keyval==GDK_KEY_Control_R || key->keyval==GDK_KEY_Meta_L || key->keyval==GDK_KEY_Meta_R) return false; - if(key->keyval==GDK_KEY_underscore) - return false; - if(key->keyval==GDK_KEY_BackSpace) - return false; if(key->keyval==GDK_KEY_Down) { auto it=list_view_text->get_selection()->get_selected(); if(it) { @@ -147,11 +151,7 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { select(false); return true; } - if(key->keyval==GDK_KEY_Return) { - select(); - return true; - } - if(key->keyval==GDK_KEY_ISO_Left_Tab || key->keyval==GDK_KEY_Tab) { + if(key->keyval==GDK_KEY_Return || key->keyval==GDK_KEY_ISO_Left_Tab || key->keyval==GDK_KEY_Tab) { select(); return true; } diff --git a/juci/selectiondialog.h b/juci/selectiondialog.h index e13bc95..eb979e9 100644 --- a/juci/selectiondialog.h +++ b/juci/selectiondialog.h @@ -10,7 +10,6 @@ public: void show(); void hide(); bool close(GdkEventFocus*); - void select(bool hide_window=true); void move(); bool on_key_release(GdkEventKey* key); bool on_key_press(GdkEventKey* key); @@ -18,11 +17,14 @@ public: std::map rows; bool shown=false; +private: + void resize(); + void select(bool hide_window=true); + Gtk::Entry search_entry; Glib::RefPtr start_mark; int start_offset; -private: - void resize(); + bool selected; Gtk::TextView& text_view; std::unique_ptr window; From 2ec8ff15d73ad80396df879020ea704a71e9bcfe Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 9 Jul 2015 15:31:26 +0200 Subject: [PATCH 26/34] Added comments to autocompletion. Try with gtkmm objects. --- juci/selectiondialog.cc | 40 +++++++++++++++++++++++++++++++++------- juci/selectiondialog.h | 7 +++++-- juci/source.cc | 27 ++++++++++++++++----------- juci/source.h | 1 + juci/tooltips.cc | 26 ++++++++++++++------------ juci/tooltips.h | 6 +++--- 6 files changed, 72 insertions(+), 35 deletions(-) diff --git a/juci/selectiondialog.cc b/juci/selectiondialog.cc index 6a703ad..7d333ca 100644 --- a/juci/selectiondialog.cc +++ b/juci/selectiondialog.cc @@ -1,7 +1,5 @@ #include "selectiondialog.h" #include -#include -using namespace std; SelectionDialog::SelectionDialog(Gtk::TextView& text_view): text_view(text_view) { @@ -33,6 +31,9 @@ void SelectionDialog::show() { select(); } }); + list_view_text->signal_cursor_changed().connect([this](){ + cursor_changed(); + }); list_view_text->signal_realize().connect([this](){ resize(); }); @@ -69,24 +70,26 @@ void SelectionDialog::hide() { void SelectionDialog::select(bool hide_window) { selected=true; auto selected=list_view_text->get_selected(); - std::string select; + std::pair select; if(selected.size()>0) { select = rows.at(list_view_text->get_text(selected[0])); text_view.get_buffer()->erase(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); - text_view.get_buffer()->insert(start_mark->get_iter(), select); + text_view.get_buffer()->insert(start_mark->get_iter(), select.first); } if(hide_window) { + if(tooltips) + tooltips->hide(); hide(); - char find_char=select.back(); + char find_char=select.first.back(); if(find_char==')' || find_char=='>') { if(find_char==')') find_char='('; else find_char='<'; - size_t pos=select.find(find_char); + size_t pos=select.first.find(find_char); if(pos!=std::string::npos) { auto start_offset=start_mark->get_iter().get_offset()+pos+1; - auto end_offset=start_mark->get_iter().get_offset()+select.size()-1; + auto end_offset=start_mark->get_iter().get_offset()+select.first.size()-1; if(start_offset!=end_offset) text_view.get_buffer()->select_range(text_view.get_buffer()->get_iter_at_offset(start_offset), text_view.get_buffer()->get_iter_at_offset(end_offset)); } @@ -137,6 +140,7 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { } } select(false); + cursor_changed(); return true; } if(key->keyval==GDK_KEY_Up) { @@ -149,6 +153,7 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { } } select(false); + cursor_changed(); return true; } if(key->keyval==GDK_KEY_Return || key->keyval==GDK_KEY_ISO_Left_Tab || key->keyval==GDK_KEY_Tab) { @@ -159,6 +164,27 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { return false; } +void SelectionDialog::cursor_changed() { + if(tooltips) + tooltips->hide(); + auto selected=list_view_text->get_selected(); + if(selected.size()>0) { + auto select = rows.at(list_view_text->get_text(selected[0])); + if(select.second.size()>0) { + tooltips=std::unique_ptr(new Tooltips()); + auto tooltip_text=select.second; + auto get_tooltip_buffer=[this, tooltip_text]() { + auto tooltip_buffer=Gtk::TextBuffer::create(text_view.get_buffer()->get_tag_table()); + //TODO: Insert newlines to tooltip_text (use 80 chars, then newline?) + tooltip_buffer->insert_at_cursor(tooltip_text); + return tooltip_buffer; + }; + tooltips->emplace_back(get_tooltip_buffer, text_view, text_view.get_buffer()->create_mark(start_mark->get_iter()), text_view.get_buffer()->create_mark(text_view.get_buffer()->get_insert()->get_iter())); + tooltips->show(true); + } + } +} + void SelectionDialog::move() { INFO("SelectionDialog set position"); Gdk::Rectangle rectangle; diff --git a/juci/selectiondialog.h b/juci/selectiondialog.h index eb979e9..ec27d9b 100644 --- a/juci/selectiondialog.h +++ b/juci/selectiondialog.h @@ -3,6 +3,7 @@ #include "gtkmm.h" #include "logging.h" +#include "tooltips.h" class SelectionDialog { public: @@ -14,12 +15,13 @@ public: bool on_key_release(GdkEventKey* key); bool on_key_press(GdkEventKey* key); - std::map rows; + std::map > rows; bool shown=false; private: void resize(); - void select(bool hide_window=true); + void select(bool hide_window=true); + void cursor_changed(); Gtk::Entry search_entry; Glib::RefPtr start_mark; @@ -30,6 +32,7 @@ private: std::unique_ptr window; std::unique_ptr scrolled_window; std::unique_ptr list_view_text; + std::unique_ptr tooltips; }; #endif // JUCI_SELECTIONDIALOG_H_ \ No newline at end of file diff --git a/juci/source.cc b/juci/source.cc index 6df1ca3..9ff1a95 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -287,12 +287,16 @@ get_autocomplete_suggestions(int line_number, int column, std::map chunks_ = results.get(i).get_chunks(); - std::vector chunks; - for (auto &chunk : chunks_) { - chunks.emplace_back(chunk); + auto result=results.get(i); + const vector chunks_ = result.get_chunks(); + if(chunks_.size()>0) { + std::vector chunks; + for (auto &chunk : chunks_) { + chunks.emplace_back(chunk); + } + suggestions.emplace_back(chunks); + suggestions.back().brief_comments=result.get_brief_comments(); } - suggestions.emplace_back(chunks); } DEBUG("Number of suggestions"); DEBUG_VAR(suggestions.size()); @@ -418,7 +422,7 @@ void Source::ClangView::update_types() { auto get_tooltip_buffer=[this, c]() { auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); tooltip_buffer->insert_at_cursor("Type: "+(*clang_tokens)[c].type); - auto brief_comment=clang_tokens->get_brief_comment(c); + auto brief_comment=clang_tokens->get_brief_comments(c); if(brief_comment!="") tooltip_buffer->insert_at_cursor("\n\n"+brief_comment); return tooltip_buffer; @@ -573,7 +577,7 @@ bool Source::ClangView::on_key_release(GdkEventKey* key) { std::shared_ptr > ac_data=std::make_shared >(); autocomplete_done_function=[this, ac_data](){ if(!autocomplete_cancel) { - std::map rows; + std::map > rows; for (auto &data : *ac_data) { std::stringstream ss; std::string return_value; @@ -587,11 +591,12 @@ bool Source::ClangView::on_key_release(GdkEventKey* key) { } } if (ss.str().length() > 0) { // if length is 0 the result is empty - rows[ss.str() + " --> " + return_value] = ss.str(); + auto pair=std::pair(ss.str(), data.brief_comments); + rows[ss.str() + " --> " + return_value] = pair; } } if (rows.empty()) { - rows["No suggestions found..."] = ""; + rows["No suggestions found..."] = std::pair(); } selection_dialog.rows=std::move(rows); selection_dialog.show(); @@ -614,8 +619,8 @@ bool Source::ClangView::on_key_release(GdkEventKey* key) { autocomplete_thread.detach(); } else { - std::map rows; - rows["Autocomplete already running, try again."] = ""; + std::map > rows; + rows["Autocomplete already running, try again."] = std::pair("", ""); selection_dialog.rows=std::move(rows); selection_dialog.show(); } diff --git a/juci/source.h b/juci/source.h index e65b34a..1cc82de 100644 --- a/juci/source.h +++ b/juci/source.h @@ -56,6 +56,7 @@ namespace Source { explicit AutoCompleteData(const std::vector &chunks) : chunks(chunks) { } std::vector chunks; + std::string brief_comments; }; class View : public Gsv::View { diff --git a/juci/tooltips.cc b/juci/tooltips.cc index 130e4cf..01d05f5 100644 --- a/juci/tooltips.cc +++ b/juci/tooltips.cc @@ -16,8 +16,8 @@ Tooltip::~Tooltip() { void Tooltip::update() { auto iter=start_mark->get_iter(); auto end_iter=end_mark->get_iter(); + text_view.get_iter_location(iter, activation_rectangle); if(iter.get_offset()(new Gtk::Window(Gtk::WindowType::WINDOW_POPUP)); @@ -63,13 +63,15 @@ void Tooltip::adjust() { rectangle.set_width(tooltip_width); rectangle.set_height(tooltip_height); - if(Tooltips::drawn_tooltips_rectangle.get_width()!=0) { - if(rectangle.intersects(Tooltips::drawn_tooltips_rectangle)) - rectangle.set_y(Tooltips::drawn_tooltips_rectangle.get_y()-tooltip_height); - Tooltips::drawn_tooltips_rectangle.join(rectangle); + if(!disregard_drawn) { + if(Tooltips::drawn_tooltips_rectangle.get_width()!=0) { + if(rectangle.intersects(Tooltips::drawn_tooltips_rectangle)) + rectangle.set_y(Tooltips::drawn_tooltips_rectangle.get_y()-tooltip_height); + Tooltips::drawn_tooltips_rectangle.join(rectangle); + } + else + Tooltips::drawn_tooltips_rectangle=rectangle; } - else - Tooltips::drawn_tooltips_rectangle=rectangle; window->move(rectangle.get_x(), rectangle.get_y()); } @@ -79,11 +81,11 @@ bool Tooltip::tooltip_on_motion_notify_event(GdkEventMotion* event) { return false; } -void Tooltips::show(const Gdk::Rectangle& rectangle) { +void Tooltips::show(const Gdk::Rectangle& rectangle, bool disregard_drawn) { for(auto& tooltip: *this) { tooltip.update(); if(rectangle.intersects(tooltip.activation_rectangle)) { - tooltip.adjust(); + tooltip.adjust(disregard_drawn); tooltip.window->show_all(); } else if(tooltip.window) @@ -91,10 +93,10 @@ void Tooltips::show(const Gdk::Rectangle& rectangle) { } } -void Tooltips::show() { +void Tooltips::show(bool disregard_drawn) { for(auto& tooltip: *this) { tooltip.update(); - tooltip.adjust(); + tooltip.adjust(disregard_drawn); tooltip.window->show_all(); } } diff --git a/juci/tooltips.h b/juci/tooltips.h index 9189622..4bd4466 100644 --- a/juci/tooltips.h +++ b/juci/tooltips.h @@ -10,7 +10,7 @@ public: ~Tooltip(); void update(); - void adjust(); + void adjust(bool disregard_drawn=false); Gdk::Rectangle activation_rectangle; std::unique_ptr window; @@ -28,8 +28,8 @@ private: class Tooltips : public std::list { public: void init() {drawn_tooltips_rectangle=Gdk::Rectangle();} - void show(const Gdk::Rectangle& rectangle); - void show(); + void show(const Gdk::Rectangle& rectangle, bool disregard_drawn=false); + void show(bool disregard_drawn=false); void hide(); static Gdk::Rectangle drawn_tooltips_rectangle; From e368e9653b38e5e48a9473c99a47c669f4f12682 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 10 Jul 2015 11:54:14 +0200 Subject: [PATCH 27/34] Reparsing now when buffer has not changed in 1 sec. Some cleanup as well. --- juci/selectiondialog.cc | 7 ++-- juci/source.cc | 79 ++++++++++++++++++++++------------------- juci/source.h | 16 +++++---- 3 files changed, 54 insertions(+), 48 deletions(-) diff --git a/juci/selectiondialog.cc b/juci/selectiondialog.cc index 7d333ca..c96d7c7 100644 --- a/juci/selectiondialog.cc +++ b/juci/selectiondialog.cc @@ -11,7 +11,7 @@ void SelectionDialog::show() { window=std::unique_ptr(new Gtk::Window(Gtk::WindowType::WINDOW_POPUP)); scrolled_window=std::unique_ptr(new Gtk::ScrolledWindow()); - list_view_text=std::unique_ptr(new Gtk::ListViewText(1, false, Gtk::SelectionMode::SELECTION_SINGLE)); + list_view_text=std::unique_ptr(new Gtk::ListViewText(1, false, Gtk::SelectionMode::SELECTION_BROWSE)); window->set_default_size(0, 0); window->property_decorated()=false; @@ -22,7 +22,7 @@ void SelectionDialog::show() { list_view_text->set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_NATURAL); list_view_text->set_activate_on_single_click(true); list_view_text->set_search_entry(search_entry); - list_view_text->set_hover_selection(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 @@ -108,7 +108,6 @@ bool SelectionDialog::on_key_release(GdkEventKey* key) { auto text=text_view.get_buffer()->get_text(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); if(text.size()>0) { search_entry.set_text(text); - list_view_text->set_search_entry(search_entry); } } @@ -173,7 +172,7 @@ void SelectionDialog::cursor_changed() { if(select.second.size()>0) { tooltips=std::unique_ptr(new Tooltips()); auto tooltip_text=select.second; - auto get_tooltip_buffer=[this, tooltip_text]() { + auto get_tooltip_buffer=[this, tooltip_text]() { auto tooltip_buffer=Gtk::TextBuffer::create(text_view.get_buffer()->get_tag_table()); //TODO: Insert newlines to tooltip_text (use 80 chars, then newline?) tooltip_buffer->insert_at_cursor(tooltip_text); diff --git a/juci/source.cc b/juci/source.cc index 9ff1a95..c44c44c 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -170,7 +170,7 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { start_offset, end_offset, &ClangView::clang_index); - update_syntax(extract_tokens(0, get_source_buffer()->get_text().size())); //TODO: replace get_source_buffer()->get_text().size() + update_syntax(); //GTK-calls must happen in main thread, so the parse_thread //sends signals to the main thread that it is to call the following functions: @@ -188,10 +188,10 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { if(parse_thread_mapped) { if(parsing_mutex.try_lock()) { INFO("Updating syntax"); - update_syntax(extract_tokens(0, get_source_buffer()->get_text().size())); + update_syntax(); update_diagnostics(); update_types(); - clang_updated=true; + clang_readable=true; parsing_mutex.unlock(); INFO("Syntax updated"); } @@ -221,17 +221,20 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { } } }); - - autocomplete_done.connect([this](){ - if(autocomplete_done_function) - autocomplete_done_function(); - }); - + get_source_buffer()->signal_changed().connect([this]() { - autocomplete_cancel=true; + cancel_show_autocomplete=true; parse_thread_mapped=false; - clang_updated=false; - parse_thread_go=true; + delayed_reparse_connection.disconnect(); + if(!selection_dialog.shown) { + delayed_reparse_connection=Glib::signal_timeout().connect([this]() { + clang_readable=false; + parse_thread_go=true; + return false; + }, 1000); + } + type_tooltips.hide(); + diagnostic_tooltips.hide(); }); signal_key_press_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_press), false); @@ -263,6 +266,10 @@ init_syntax_highlighting(const std::map file_path, arguments, buffers)); + clang::SourceLocation start(clang_tu.get(), file_path, 0); + clang::SourceLocation end(clang_tu.get(), file_path, buffers.find(file_path)->second.size()-1); + clang::SourceRange range(&start, &end); + clang_tokens=std::unique_ptr(new clang::Tokens(clang_tu.get(), &range)); } std::map Source::ClangView:: @@ -274,7 +281,12 @@ get_buffer_map() const { int Source::ClangView:: reparse(const std::map &buffer) { - return clang_tu->ReparseTranslationUnit(file_path, buffer); + int status = clang_tu->ReparseTranslationUnit(file_path, buffer); + clang::SourceLocation start(clang_tu.get(), file_path, 0); + clang::SourceLocation end(clang_tu.get(), file_path, parse_thread_buffer_map.find(file_path)->second.size()-1); + clang::SourceRange range(&start, &end); + clang_tokens=std::unique_ptr(new clang::Tokens(clang_tu.get(), &range)); + return status; } std::vector Source::ClangView:: @@ -320,13 +332,8 @@ get_compilation_commands() { return arguments; } -std::vector Source::ClangView:: -extract_tokens(int start_offset, int end_offset) { +void Source::ClangView::update_syntax() { std::vector ranges; - clang::SourceLocation start(clang_tu.get(), file_path, start_offset); - clang::SourceLocation end(clang_tu.get(), file_path, end_offset); - clang::SourceRange range(&start, &end); - clang_tokens=std::unique_ptr(new clang::Tokens(clang_tu.get(), &range)); for (auto &token : *clang_tokens) { switch (token.kind()) { case 0: highlight_cursor(&token, &ranges); break; // PunctuationToken @@ -336,10 +343,6 @@ extract_tokens(int start_offset, int end_offset) { case 4: highlight_token(&token, &ranges, 705); break; // CommentToken } } - return ranges; -} - -void Source::ClangView::update_syntax(const std::vector &ranges) { if (ranges.empty() || ranges.size() == 0) { return; } @@ -424,7 +427,7 @@ void Source::ClangView::update_types() { tooltip_buffer->insert_at_cursor("Type: "+(*clang_tokens)[c].type); auto brief_comment=clang_tokens->get_brief_comments(c); if(brief_comment!="") - tooltip_buffer->insert_at_cursor("\n\n"+brief_comment); + tooltip_buffer->insert_at_cursor("\n\n"+brief_comment+"."); return tooltip_buffer; }; @@ -435,8 +438,8 @@ void Source::ClangView::update_types() { } bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) { - on_mark_set_timeout_connection.disconnect(); - if(clang_updated) { + delayed_tooltips_connection.disconnect(); + if(clang_readable) { Gdk::Rectangle rectangle(event->x, event->y, 1, 1); diagnostic_tooltips.init(); type_tooltips.show(rectangle); @@ -452,16 +455,16 @@ bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { if(get_buffer()->get_has_selection() && mark->get_name()=="selection_bound") - on_mark_set_timeout_connection.disconnect(); + delayed_tooltips_connection.disconnect(); if(mark->get_name()=="insert") { - autocomplete_cancel=true; + cancel_show_autocomplete=true; if(selection_dialog.shown) { selection_dialog.hide(); } - on_mark_set_timeout_connection.disconnect(); - on_mark_set_timeout_connection=Glib::signal_timeout().connect([this]() { - if(clang_updated) { + delayed_tooltips_connection.disconnect(); + delayed_tooltips_connection=Glib::signal_timeout().connect([this]() { + if(clang_readable) { Gdk::Rectangle rectangle; get_iter_location(get_buffer()->get_insert()->get_iter(), rectangle); int location_window_x, location_window_y; @@ -481,7 +484,7 @@ void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& i } bool Source::ClangView::clangview_on_focus_out_event(GdkEventFocus* event) { - on_mark_set_timeout_connection.disconnect(); + delayed_tooltips_connection.disconnect(); type_tooltips.hide(); diagnostic_tooltips.hide(); return false; @@ -491,7 +494,7 @@ bool Source::ClangView::clangview_on_scroll_event(GdkEventScroll* event) { if(selection_dialog.shown) selection_dialog.move(); - on_mark_set_timeout_connection.disconnect(); + delayed_tooltips_connection.disconnect(); type_tooltips.hide(); diagnostic_tooltips.hide(); return false; @@ -570,13 +573,15 @@ bool Source::ClangView::on_key_release(GdkEventKey* key) { } else { return false; } + delayed_reparse_connection.disconnect(); if(!autocomplete_running) { autocomplete_running=true; - autocomplete_cancel=false; + cancel_show_autocomplete=false; INFO("Source::ClangView::on_key_release getting autocompletions"); std::shared_ptr > ac_data=std::make_shared >(); - autocomplete_done_function=[this, ac_data](){ - if(!autocomplete_cancel) { + autocomplete_done_connection.disconnect(); + autocomplete_done_connection=autocomplete_done.connect([this, ac_data](){ + if(!cancel_show_autocomplete) { std::map > rows; for (auto &data : *ac_data) { std::stringstream ss; @@ -602,7 +607,7 @@ bool Source::ClangView::on_key_release(GdkEventKey* key) { selection_dialog.show(); } autocomplete_running=false; - }; + }); std::shared_ptr > buffer_map=std::make_shared >(); (*buffer_map)[file_path]=get_buffer()->get_text(get_buffer()->begin(), get_buffer()->get_insert()->get_iter()); diff --git a/juci/source.h b/juci/source.h index 1cc82de..f9aab45 100644 --- a/juci/source.h +++ b/juci/source.h @@ -96,16 +96,16 @@ namespace Source { clang::Index *index); std::vector get_autocomplete_suggestions(int line_number, int column, std::map& buffer_map); SelectionDialog selection_dialog; + int reparse(const std::map &buffers); - std::vector extract_tokens(int, int); - void update_syntax(const std::vector &locations); + void update_syntax(); void update_diagnostics(); void update_types(); Tooltips diagnostic_tooltips; Tooltips type_tooltips; bool clangview_on_motion_notify_event(GdkEventMotion* event); void clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); - sigc::connection on_mark_set_timeout_connection; + sigc::connection delayed_tooltips_connection; bool clangview_on_focus_out_event(GdkEventFocus* event); bool clangview_on_scroll_event(GdkEventScroll* event); @@ -115,7 +115,7 @@ namespace Source { std::unique_ptr clang_tu; std::unique_ptr clang_tokens; - bool clang_updated=false; + bool clang_readable=false; void highlight_token(clang::Token *token, std::vector *source_ranges, int token_kind); @@ -125,12 +125,14 @@ namespace Source { bool on_key_press(GdkEventKey* key); bool on_key_release(GdkEventKey* key); Terminal::Controller& terminal; - std::shared_ptr parsing_in_progress; Glib::Dispatcher autocomplete_done; - std::function autocomplete_done_function; + sigc::connection autocomplete_done_connection; + + sigc::connection delayed_reparse_connection; + std::shared_ptr parsing_in_progress; bool autocomplete_running=false; - bool autocomplete_cancel=false; + bool cancel_show_autocomplete=false; Glib::Dispatcher parse_done; Glib::Dispatcher parse_start; std::thread parse_thread; From c0a193484cd7baac0c0e88c0b19408b4f0ba83b5 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 10 Jul 2015 13:36:28 +0200 Subject: [PATCH 28/34] Minor cleanup. --- juci/selectiondialog.cc | 5 +---- juci/source.cc | 11 ++--------- juci/source.h | 12 ++---------- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/juci/selectiondialog.cc b/juci/selectiondialog.cc index c96d7c7..02a2c4c 100644 --- a/juci/selectiondialog.cc +++ b/juci/selectiondialog.cc @@ -1,9 +1,6 @@ #include "selectiondialog.h" -#include -SelectionDialog::SelectionDialog(Gtk::TextView& text_view): text_view(text_view) { - -} +SelectionDialog::SelectionDialog(Gtk::TextView& text_view): text_view(text_view) {} void SelectionDialog::show() { if(rows.size()==0) diff --git a/juci/source.cc b/juci/source.cc index c44c44c..4de235f 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -300,15 +300,8 @@ get_autocomplete_suggestions(int line_number, int column, std::map chunks_ = result.get_chunks(); - if(chunks_.size()>0) { - std::vector chunks; - for (auto &chunk : chunks_) { - chunks.emplace_back(chunk); - } - suggestions.emplace_back(chunks); - suggestions.back().brief_comments=result.get_brief_comments(); - } + suggestions.emplace_back(result.get_chunks()); + suggestions.back().brief_comments=result.get_brief_comments(); } DEBUG("Number of suggestions"); DEBUG_VAR(suggestions.size()); diff --git a/juci/source.h b/juci/source.h index f9aab45..2f9182b 100644 --- a/juci/source.h +++ b/juci/source.h @@ -43,19 +43,11 @@ namespace Source { int kind; }; - class AutoCompleteChunk { - public: - explicit AutoCompleteChunk(const clang::CompletionChunk &clang_chunk) : - chunk(clang_chunk.chunk()), kind(clang_chunk.kind()) { } - std::string chunk; - enum clang::CompletionChunkKind kind; - }; - class AutoCompleteData { public: - explicit AutoCompleteData(const std::vector &chunks) : + explicit AutoCompleteData(const std::vector &chunks) : chunks(chunks) { } - std::vector chunks; + std::vector chunks; std::string brief_comments; }; From 6a672c108686e667017e0f944260a150d3ee5771 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 11 Jul 2015 17:39:37 +0200 Subject: [PATCH 29/34] More flexible autocomplete, now pops up selectiondialog even after entering chars after ., -> and ::. Also some cleanup. Placed autocompletion in seperate class ClangViewAutocomplete. --- juci/selectiondialog.cc | 71 ++++++---- juci/selectiondialog.h | 6 +- juci/source.cc | 294 ++++++++++++++++++++-------------------- juci/source.h | 52 +++---- 4 files changed, 219 insertions(+), 204 deletions(-) diff --git a/juci/selectiondialog.cc b/juci/selectiondialog.cc index 02a2c4c..8edb13d 100644 --- a/juci/selectiondialog.cc +++ b/juci/selectiondialog.cc @@ -18,26 +18,22 @@ void SelectionDialog::show() { 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_search_entry(search_entry); 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 + last_selected=-1; + list_view_text->signal_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*) { if(shown) { select(); } }); - list_view_text->signal_cursor_changed().connect([this](){ - cursor_changed(); - }); + list_view_text->signal_cursor_changed().connect(sigc::mem_fun(*this, &SelectionDialog::cursor_changed), true); list_view_text->signal_realize().connect([this](){ resize(); }); - if(start_mark) - text_view.get_buffer()->delete_mark(start_mark); - start_mark=text_view.get_buffer()->create_mark(text_view.get_buffer()->get_insert()->get_iter()); start_offset=start_mark->get_iter().get_offset(); list_view_text->clear_items(); for (auto &i : rows) { @@ -56,16 +52,23 @@ void SelectionDialog::show() { window->show_all(); shown=true; - selected=false; + row_in_entry=false; + auto text=text_view.get_buffer()->get_text(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); + if(text.size()>0) { + search_entry.set_text(text); + list_view_text->set_search_entry(search_entry); + } } void SelectionDialog::hide() { - window->hide(); + window->hide(); shown=false; + if(tooltips) + tooltips->hide(); } void SelectionDialog::select(bool hide_window) { - selected=true; + row_in_entry=true; auto selected=list_view_text->get_selected(); std::pair select; if(selected.size()>0) { @@ -74,8 +77,6 @@ void SelectionDialog::select(bool hide_window) { text_view.get_buffer()->insert(start_mark->get_iter(), select.first); } if(hide_window) { - if(tooltips) - tooltips->hide(); hide(); char find_char=select.first.back(); if(find_char==')' || find_char=='>') { @@ -105,9 +106,10 @@ bool SelectionDialog::on_key_release(GdkEventKey* key) { auto text=text_view.get_buffer()->get_text(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); if(text.size()>0) { search_entry.set_text(text); + list_view_text->set_search_entry(search_entry); } + cursor_changed(); } - return false; } @@ -116,11 +118,12 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { (key->keyval>=GDK_KEY_A && key->keyval<=GDK_KEY_Z) || (key->keyval>=GDK_KEY_a && key->keyval<=GDK_KEY_z) || key->keyval==GDK_KEY_underscore || key->keyval==GDK_KEY_BackSpace) { - if(selected) { + if(row_in_entry) { text_view.get_buffer()->erase(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); - selected=false; - if(key->keyval==GDK_KEY_BackSpace) + row_in_entry=false; + if(key->keyval==GDK_KEY_BackSpace) { return true; + } } return false; } @@ -161,24 +164,32 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { } void SelectionDialog::cursor_changed() { - if(tooltips) - tooltips->hide(); auto selected=list_view_text->get_selected(); if(selected.size()>0) { - auto select = rows.at(list_view_text->get_text(selected[0])); - if(select.second.size()>0) { - tooltips=std::unique_ptr(new Tooltips()); - auto tooltip_text=select.second; - auto get_tooltip_buffer=[this, tooltip_text]() { - auto tooltip_buffer=Gtk::TextBuffer::create(text_view.get_buffer()->get_tag_table()); - //TODO: Insert newlines to tooltip_text (use 80 chars, then newline?) - tooltip_buffer->insert_at_cursor(tooltip_text); - return tooltip_buffer; - }; - tooltips->emplace_back(get_tooltip_buffer, text_view, text_view.get_buffer()->create_mark(start_mark->get_iter()), text_view.get_buffer()->create_mark(text_view.get_buffer()->get_insert()->get_iter())); - tooltips->show(true); + if(selected[0]!=last_selected || last_selected==-1) { + if(tooltips) + tooltips->hide(); + auto row = rows.at(list_view_text->get_text(selected[0])); + if(row.second.size()>0) { + tooltips=std::unique_ptr(new Tooltips()); + auto tooltip_text=row.second; + auto get_tooltip_buffer=[this, tooltip_text]() { + auto tooltip_buffer=Gtk::TextBuffer::create(text_view.get_buffer()->get_tag_table()); + //TODO: Insert newlines to tooltip_text (use 80 chars, then newline?) + tooltip_buffer->insert_at_cursor(tooltip_text); + return tooltip_buffer; + }; + tooltips->emplace_back(get_tooltip_buffer, text_view, text_view.get_buffer()->create_mark(start_mark->get_iter()), text_view.get_buffer()->create_mark(text_view.get_buffer()->get_insert()->get_iter())); + tooltips->show(true); + } } } + else if(tooltips) + tooltips->hide(); + if(selected.size()>0) + last_selected=selected[0]; + else + last_selected=-1; } void SelectionDialog::move() { diff --git a/juci/selectiondialog.h b/juci/selectiondialog.h index ec27d9b..32d5e27 100644 --- a/juci/selectiondialog.h +++ b/juci/selectiondialog.h @@ -16,23 +16,23 @@ public: bool on_key_press(GdkEventKey* key); std::map > rows; - bool shown=false; + Glib::RefPtr start_mark; private: void resize(); void select(bool hide_window=true); void cursor_changed(); Gtk::Entry search_entry; - Glib::RefPtr start_mark; int start_offset; - bool selected; + bool row_in_entry; Gtk::TextView& text_view; std::unique_ptr window; std::unique_ptr scrolled_window; std::unique_ptr list_view_text; std::unique_ptr tooltips; + int last_selected; }; #endif // JUCI_SELECTIONDIALOG_H_ \ No newline at end of file diff --git a/juci/source.cc b/juci/source.cc index 4de235f..cc3cf0a 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -63,7 +63,7 @@ string Source::View::get_line_before_insert() { } //Basic indentation -bool Source::View::on_key_press(GdkEventKey* key) { +bool Source::View::on_key_press_event(GdkEventKey* key) { auto config=Singletons::Config::source(); const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$"); //Indent as in next or previous line @@ -139,7 +139,7 @@ bool Source::View::on_key_press(GdkEventKey* key) { } } } - return false; + return Gsv::View::on_key_press_event(key); } ////////////////// @@ -148,7 +148,7 @@ bool Source::View::on_key_press(GdkEventKey* key) { clang::Index Source::ClangView::clang_index(0, 0); Source::ClangView::ClangView(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): -Source::View(file_path, project_path), terminal(terminal), selection_dialog(*this), +Source::View(file_path, project_path), terminal(terminal), parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { int start_offset = get_source_buffer()->begin().get_offset(); int end_offset = get_source_buffer()->end().get_offset(); @@ -223,22 +223,17 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { }); get_source_buffer()->signal_changed().connect([this]() { - cancel_show_autocomplete=true; parse_thread_mapped=false; delayed_reparse_connection.disconnect(); - if(!selection_dialog.shown) { - delayed_reparse_connection=Glib::signal_timeout().connect([this]() { - clang_readable=false; - parse_thread_go=true; - return false; - }, 1000); - } + delayed_reparse_connection=Glib::signal_timeout().connect([this]() { + clang_readable=false; + parse_thread_go=true; + return false; + }, 1000); type_tooltips.hide(); diagnostic_tooltips.hide(); }); - signal_key_press_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_press), false); - signal_key_release_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_release), false); signal_motion_notify_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_motion_notify_event), false); signal_focus_out_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_focus_out_event), false); signal_scroll_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_scroll_event), false); @@ -289,25 +284,6 @@ reparse(const std::map &buffer) { return status; } -std::vector Source::ClangView:: -get_autocomplete_suggestions(int line_number, int column, std::map& buffer_map) { - INFO("Getting auto complete suggestions"); - std::vector suggestions; - clang::CodeCompleteResults results(clang_tu.get(), - file_path, - buffer_map, - line_number, - column-1); - for (int i = 0; i < results.size(); i++) { - auto result=results.get(i); - suggestions.emplace_back(result.get_chunks()); - suggestions.back().brief_comments=result.get_brief_comments(); - } - DEBUG("Number of suggestions"); - DEBUG_VAR(suggestions.size()); - return suggestions; -} - std::vector Source::ClangView:: get_compilation_commands() { clang::CompilationDatabase db(project_path); @@ -451,10 +427,6 @@ void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& i delayed_tooltips_connection.disconnect(); if(mark->get_name()=="insert") { - cancel_show_autocomplete=true; - if(selection_dialog.shown) { - selection_dialog.hide(); - } delayed_tooltips_connection.disconnect(); delayed_tooltips_connection=Glib::signal_timeout().connect([this]() { if(clang_readable) { @@ -484,9 +456,6 @@ bool Source::ClangView::clangview_on_focus_out_event(GdkEventFocus* event) { } bool Source::ClangView::clangview_on_scroll_event(GdkEventScroll* event) { - if(selection_dialog.shown) - selection_dialog.move(); - delayed_tooltips_connection.disconnect(); type_tooltips.hide(); diagnostic_tooltips.hide(); @@ -525,114 +494,9 @@ highlight_token(clang::Token *token, end_offset), token_kind); } -bool Source::ClangView::on_key_release(GdkEventKey* key) { - if(selection_dialog.shown) { - if(selection_dialog.on_key_release(key)) - return true; - } - - INFO("Source::ClangView::on_key_release getting iters"); - // Get function to fill popup with suggests item vector under is for testing - Gtk::TextIter beg = get_source_buffer()->get_insert()->get_iter(); - Gtk::TextIter end = get_source_buffer()->get_insert()->get_iter(); - Gtk::TextIter tmp = get_source_buffer()->get_insert()->get_iter(); - Gtk::TextIter tmp1 = get_source_buffer()->get_insert()->get_iter(); - Gtk::TextIter line = get_source_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); - INFO("Source::ClangView::on_key_release checking key->keyval"); - if (illegal_chars) { - return false; - } - std::string c = get_source_buffer()->get_text(end, beg); - switch (key->keyval) { - 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; - } - delayed_reparse_connection.disconnect(); - if(!autocomplete_running) { - autocomplete_running=true; - cancel_show_autocomplete=false; - INFO("Source::ClangView::on_key_release getting autocompletions"); - std::shared_ptr > ac_data=std::make_shared >(); - autocomplete_done_connection.disconnect(); - autocomplete_done_connection=autocomplete_done.connect([this, ac_data](){ - if(!cancel_show_autocomplete) { - std::map > rows; - for (auto &data : *ac_data) { - 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; - } - } - if (ss.str().length() > 0) { // if length is 0 the result is empty - auto pair=std::pair(ss.str(), data.brief_comments); - rows[ss.str() + " --> " + return_value] = pair; - } - } - if (rows.empty()) { - rows["No suggestions found..."] = std::pair(); - } - selection_dialog.rows=std::move(rows); - selection_dialog.show(); - } - autocomplete_running=false; - }); - - std::shared_ptr > buffer_map=std::make_shared >(); - (*buffer_map)[file_path]=get_buffer()->get_text(get_buffer()->begin(), get_buffer()->get_insert()->get_iter()); - (*buffer_map)[file_path]+="\n"; - auto line_nr=beg.get_line()+1; - auto column_nr=beg.get_line_offset()+2; - std::thread autocomplete_thread([this, ac_data, line_nr, column_nr, buffer_map](){ - parsing_mutex.lock(); - *ac_data=move(get_autocomplete_suggestions(line_nr, column_nr, *buffer_map)); - autocomplete_done(); - parsing_mutex.unlock(); - }); - - autocomplete_thread.detach(); - } - else { - std::map > rows; - rows["Autocomplete already running, try again."] = std::pair("", ""); - selection_dialog.rows=std::move(rows); - selection_dialog.show(); - } - - return false; -} - //Clang indentation //TODO: replace indentation methods with a better implementation or maybe use libclang -bool Source::ClangView::on_key_press(GdkEventKey* key) { - if(selection_dialog.shown) { - if(selection_dialog.on_key_press(key)) - return true; - } +bool Source::ClangView::on_key_press_event(GdkEventKey* key) { auto config=Singletons::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) *\\(.*[^;}] *$"); @@ -713,7 +577,143 @@ bool Source::ClangView::on_key_press(GdkEventKey* key) { return false; } - return Source::View::on_key_press(key); + return Source::View::on_key_press_event(key); +} + +////////////////////////////// +//// ClangViewAutocomplete /// +////////////////////////////// + +Source::ClangViewAutocomplete::ClangViewAutocomplete(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): +Source::ClangView(file_path, project_path, terminal), selection_dialog(*this) { + get_buffer()->signal_changed().connect([this](){ + if(!selection_dialog.shown) { + auto insert=get_buffer()->get_insert(); + auto iter=insert->get_iter(); + int line_nr=iter.get_line(); + auto line_iter=get_buffer()->get_iter_at_line(line_nr); + std::string line=get_buffer()->get_text(line_iter, iter); + const std::regex method("^(.*)(->|\\.|::)([a-zA-Z0-9_]*)$"); + std::smatch sm; + if(std::regex_match(line, sm, method)) { + if(sm[1].str().find("//")==std::string::npos) { + if(last_keyval=='.' || last_keyval=='>' || last_keyval==':') { + if(sm[3]=="" && !autocomplete_running) { + start_autocomplete(); + } + } + } + } + else if(autocomplete_running) + cancel_show_autocomplete=true; + } + }); + get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark){ + if(mark->get_name()=="insert") { + cancel_show_autocomplete=true; + if(selection_dialog.shown) { + selection_dialog.hide(); + } + } + }); + signal_scroll_event().connect([this](GdkEventScroll* event){ + if(selection_dialog.shown) + selection_dialog.move(); + return false; + }, false); + signal_key_release_event().connect([this](GdkEventKey* key){ + if(selection_dialog.shown) { + if(selection_dialog.on_key_release(key)) + return true; + } + + return false; + }, false); +} + +bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { + if(selection_dialog.shown) { + delayed_reparse_connection.disconnect(); + if(selection_dialog.on_key_press(key)) + return true; + } + last_keyval=key->keyval; + return ClangView::on_key_press_event(key); +} +void Source::ClangViewAutocomplete::start_autocomplete() { + delayed_reparse_connection.disconnect(); + if(!autocomplete_running) { + autocomplete_running=true; + cancel_show_autocomplete=false; + INFO("Source::ClangView::on_key_release getting autocompletions"); + std::shared_ptr > ac_data=std::make_shared >(); + if(selection_dialog.start_mark) + get_buffer()->delete_mark(selection_dialog.start_mark); + selection_dialog.start_mark=get_buffer()->create_mark(get_buffer()->get_insert()->get_iter()); + autocomplete_done_connection.disconnect(); + autocomplete_done_connection=autocomplete_done.connect([this, ac_data](){ + if(!cancel_show_autocomplete) { + std::map > rows; + for (auto &data : *ac_data) { + 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; + } + } + if (ss.str().length() > 0) { // if length is 0 the result is empty + auto pair=std::pair(ss.str(), data.brief_comments); + rows[ss.str() + " --> " + return_value] = pair; + } + } + if (rows.empty()) { + rows["No suggestions found..."] = std::pair(); + } + selection_dialog.rows=std::move(rows); + selection_dialog.show(); + } + autocomplete_running=false; + }); + + std::shared_ptr > buffer_map=std::make_shared >(); + (*buffer_map)[this->file_path]=get_buffer()->get_text(get_buffer()->begin(), get_buffer()->get_insert()->get_iter()); + (*buffer_map)[this->file_path]+="\n"; + auto iter = get_source_buffer()->get_insert()->get_iter(); + auto line_nr=iter.get_line()+1; + auto column_nr=iter.get_line_offset()+2; + std::thread autocomplete_thread([this, ac_data, line_nr, column_nr, buffer_map](){ + parsing_mutex.lock(); + *ac_data=move(get_autocomplete_suggestions(line_nr, column_nr, *buffer_map)); + autocomplete_done(); + parsing_mutex.unlock(); + }); + + autocomplete_thread.detach(); + } +} + +std::vector Source::ClangViewAutocomplete:: +get_autocomplete_suggestions(int line_number, int column, std::map& buffer_map) { + INFO("Getting auto complete suggestions"); + std::vector suggestions; + clang::CodeCompleteResults results(clang_tu.get(), + file_path, + buffer_map, + line_number, + column-1); + for (int i = 0; i < results.size(); i++) { + auto result=results.get(i); + suggestions.emplace_back(result.get_chunks()); + suggestions.back().brief_comments=result.get_brief_comments(); + } + DEBUG("Number of suggestions"); + DEBUG_VAR(suggestions.size()); + return suggestions; } //////////////////// @@ -727,7 +727,7 @@ Source::Controller::Controller(const std::string& file_path, std::string project project_path=boost::filesystem::path(file_path).parent_path().string(); } if (Singletons::Config::source()->legal_extension(file_path.substr(file_path.find_last_of(".") + 1))) - view=std::unique_ptr(new ClangView(file_path, project_path, terminal)); + view=std::unique_ptr(new ClangViewAutocomplete(file_path, project_path, terminal)); else view=std::unique_ptr(new GenericView(file_path, project_path)); INFO("Source Controller with childs constructed"); diff --git a/juci/source.h b/juci/source.h index 2f9182b..6c87d4e 100644 --- a/juci/source.h +++ b/juci/source.h @@ -60,18 +60,16 @@ namespace Source { std::string project_path; Gtk::TextIter search_start, search_end; protected: - bool on_key_press(GdkEventKey* key); + bool on_key_press_event(GdkEventKey* key); }; // class View class GenericView : public View { public: GenericView(const std::string& file_path, const std::string& project_path): - View(file_path, project_path) { - signal_key_press_event().connect(sigc::mem_fun(*this, &Source::GenericView::on_key_press), false); - } - private: - bool on_key_press(GdkEventKey* key) { - return Source::View::on_key_press(key); + View(file_path, project_path) {} + protected: + bool on_key_press_event(GdkEventKey* key) { + return Source::View::on_key_press_event(key); } }; @@ -79,6 +77,12 @@ namespace Source { public: ClangView(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal); ~ClangView(); + protected: + std::unique_ptr clang_tu; + std::map get_buffer_map() const; + std::mutex parsing_mutex; + sigc::connection delayed_reparse_connection; + bool on_key_press_event(GdkEventKey* key); private: // inits the syntax highligthing on file open void init_syntax_highlighting(const std::map @@ -86,9 +90,6 @@ namespace Source { int start_offset, int end_offset, clang::Index *index); - std::vector get_autocomplete_suggestions(int line_number, int column, std::map& buffer_map); - SelectionDialog selection_dialog; - int reparse(const std::map &buffers); void update_syntax(); void update_diagnostics(); @@ -100,12 +101,7 @@ namespace Source { sigc::connection delayed_tooltips_connection; bool clangview_on_focus_out_event(GdkEventFocus* event); bool clangview_on_scroll_event(GdkEventScroll* event); - static clang::Index clang_index; - std::map get_buffer_map() const; - std::mutex parsing_mutex; - - std::unique_ptr clang_tu; std::unique_ptr clang_tokens; bool clang_readable=false; void highlight_token(clang::Token *token, @@ -114,17 +110,9 @@ namespace Source { void highlight_cursor(clang::Token *token, std::vector *source_ranges); std::vector get_compilation_commands(); - bool on_key_press(GdkEventKey* key); - bool on_key_release(GdkEventKey* key); Terminal::Controller& terminal; - - Glib::Dispatcher autocomplete_done; - sigc::connection autocomplete_done_connection; - - sigc::connection delayed_reparse_connection; + std::shared_ptr parsing_in_progress; - bool autocomplete_running=false; - bool cancel_show_autocomplete=false; Glib::Dispatcher parse_done; Glib::Dispatcher parse_start; std::thread parse_thread; @@ -134,6 +122,22 @@ namespace Source { std::atomic parse_thread_mapped; std::atomic parse_thread_stop; }; + + class ClangViewAutocomplete : public ClangView { + public: + ClangViewAutocomplete(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal); + protected: + bool on_key_press_event(GdkEventKey* key); + private: + void start_autocomplete(); + SelectionDialog selection_dialog; + std::vector get_autocomplete_suggestions(int line_number, int column, std::map& buffer_map); + Glib::Dispatcher autocomplete_done; + sigc::connection autocomplete_done_connection; + bool autocomplete_running=false; + bool cancel_show_autocomplete=false; + char last_keyval=0; + }; class Controller { public: From 6814e5ebf69aff911842c4504ee64f78380342ef Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 11 Jul 2015 17:54:35 +0200 Subject: [PATCH 30/34] Disabled reparse while autocompleting. --- juci/source.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/juci/source.cc b/juci/source.cc index cc3cf0a..70ced96 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -587,6 +587,8 @@ bool Source::ClangView::on_key_press_event(GdkEventKey* key) { Source::ClangViewAutocomplete::ClangViewAutocomplete(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): Source::ClangView(file_path, project_path, terminal), selection_dialog(*this) { get_buffer()->signal_changed().connect([this](){ + if(autocomplete_running || selection_dialog.shown) + delayed_reparse_connection.disconnect(); if(!selection_dialog.shown) { auto insert=get_buffer()->get_insert(); auto iter=insert->get_iter(); From e3ce56aa1fc797837623752dcbaf7dece248317d Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 11 Jul 2015 17:58:45 +0200 Subject: [PATCH 31/34] Minor cleanup. --- juci/source.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 70ced96..426c97e 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -587,8 +587,6 @@ bool Source::ClangView::on_key_press_event(GdkEventKey* key) { Source::ClangViewAutocomplete::ClangViewAutocomplete(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): Source::ClangView(file_path, project_path, terminal), selection_dialog(*this) { get_buffer()->signal_changed().connect([this](){ - if(autocomplete_running || selection_dialog.shown) - delayed_reparse_connection.disconnect(); if(!selection_dialog.shown) { auto insert=get_buffer()->get_insert(); auto iter=insert->get_iter(); @@ -609,6 +607,9 @@ Source::ClangView(file_path, project_path, terminal), selection_dialog(*this) { else if(autocomplete_running) cancel_show_autocomplete=true; } + if(autocomplete_running || selection_dialog.shown) + delayed_reparse_connection.disconnect(); + }); get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark){ if(mark->get_name()=="insert") { @@ -643,7 +644,6 @@ bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { return ClangView::on_key_press_event(key); } void Source::ClangViewAutocomplete::start_autocomplete() { - delayed_reparse_connection.disconnect(); if(!autocomplete_running) { autocomplete_running=true; cancel_show_autocomplete=false; From 4e38ef8760a7046179640a13d0a919b0c4c67c7e Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 12 Jul 2015 16:11:44 +0200 Subject: [PATCH 32/34] Added autocomplete in current namespace for clangview. Autocomplete currently starts after 3 characters. Will try to clean up this code soon. --- juci/source.cc | 127 +++++++++++++++++++++++++++++++------------------ juci/source.h | 15 +++--- 2 files changed, 88 insertions(+), 54 deletions(-) diff --git a/juci/source.cc b/juci/source.cc index 426c97e..da5055c 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -234,10 +234,7 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { diagnostic_tooltips.hide(); }); - signal_motion_notify_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_motion_notify_event), false); - signal_focus_out_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_focus_out_event), false); - signal_scroll_event().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_scroll_event), false); - get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangView::clangview_on_mark_set), false); + get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangView::on_mark_set), false); } Source::ClangView::~ClangView() { @@ -406,7 +403,7 @@ void Source::ClangView::update_types() { } } -bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) { +bool Source::ClangView::on_motion_notify_event(GdkEventMotion* event) { delayed_tooltips_connection.disconnect(); if(clang_readable) { Gdk::Rectangle rectangle(event->x, event->y, 1, 1); @@ -419,10 +416,10 @@ bool Source::ClangView::clangview_on_motion_notify_event(GdkEventMotion* event) diagnostic_tooltips.hide(); } - return false; + return Source::View::on_motion_notify_event(event); } -void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { +void Source::ClangView::on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { if(get_buffer()->get_has_selection() && mark->get_name()=="selection_bound") delayed_tooltips_connection.disconnect(); @@ -448,18 +445,18 @@ void Source::ClangView::clangview_on_mark_set(const Gtk::TextBuffer::iterator& i } } -bool Source::ClangView::clangview_on_focus_out_event(GdkEventFocus* event) { +bool Source::ClangView::on_focus_out_event(GdkEventFocus* event) { delayed_tooltips_connection.disconnect(); type_tooltips.hide(); diagnostic_tooltips.hide(); - return false; + return Source::View::on_focus_out_event(event); } -bool Source::ClangView::clangview_on_scroll_event(GdkEventScroll* event) { +bool Source::ClangView::on_scroll_event(GdkEventScroll* event) { delayed_tooltips_connection.disconnect(); type_tooltips.hide(); diagnostic_tooltips.hide(); - return false; + return Source::View::on_scroll_event(event); } void Source::ClangView:: @@ -587,33 +584,46 @@ bool Source::ClangView::on_key_press_event(GdkEventKey* key) { Source::ClangViewAutocomplete::ClangViewAutocomplete(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): Source::ClangView(file_path, project_path, terminal), selection_dialog(*this) { get_buffer()->signal_changed().connect([this](){ - if(!selection_dialog.shown) { - auto insert=get_buffer()->get_insert(); - auto iter=insert->get_iter(); - int line_nr=iter.get_line(); - auto line_iter=get_buffer()->get_iter_at_line(line_nr); - std::string line=get_buffer()->get_text(line_iter, iter); - const std::regex method("^(.*)(->|\\.|::)([a-zA-Z0-9_]*)$"); + std::string line=" "+get_line_before_insert(); + if((std::count(line.begin(), line.end(), '\"')%2)!=1 && line.find("//")==std::string::npos) { + const std::regex in_specified_namespace("^(.*)(->|\\.|::)([a-zA-Z0-9_]*)$"); + const std::regex within_namespace("^(.*)([^a-zA-Z0-9_]+)([a-zA-Z_][a-zA-Z0-9_]{2,})$"); std::smatch sm; - if(std::regex_match(line, sm, method)) { - if(sm[1].str().find("//")==std::string::npos) { - if(last_keyval=='.' || last_keyval=='>' || last_keyval==':') { - if(sm[3]=="" && !autocomplete_running) { - start_autocomplete(); - } + if(std::regex_match(line, sm, in_specified_namespace)) { + if(last_keyval=='.' || last_keyval=='>' || last_keyval==':') { + if(sm[3]=="" && !autocomplete_starting && !selection_dialog.shown) { + prefix=""; + autocomplete(); } + else if(autocomplete_starting) + autocomplete_cancel_starting=true; + } + } + else if(std::regex_match(line, sm, within_namespace)) { + prefix=sm[3].str(); + if((last_keyval>='a' && last_keyval<='z') || (last_keyval>='A' && last_keyval<='Z') || (last_keyval>='0' && last_keyval<='9') || last_keyval=='_') { + if(!autocomplete_starting && !selection_dialog.shown) { + autocomplete(); + } + } + else if(last_keyval!=0) { + autocomplete_cancel_starting=true; + if(selection_dialog.shown) + selection_dialog.hide(); } } - else if(autocomplete_running) - cancel_show_autocomplete=true; + else if(last_keyval!=0) { + autocomplete_cancel_starting=true; + if(selection_dialog.shown) + selection_dialog.hide(); + } + if(autocomplete_starting || selection_dialog.shown) + delayed_reparse_connection.disconnect(); } - if(autocomplete_running || selection_dialog.shown) - delayed_reparse_connection.disconnect(); - }); get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark){ if(mark->get_name()=="insert") { - cancel_show_autocomplete=true; + autocomplete_cancel_starting=true; if(selection_dialog.shown) { selection_dialog.hide(); } @@ -635,6 +645,7 @@ Source::ClangView(file_path, project_path, terminal), selection_dialog(*this) { } bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { + last_keyval=0; if(selection_dialog.shown) { delayed_reparse_connection.disconnect(); if(selection_dialog.on_key_press(key)) @@ -643,18 +654,30 @@ bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { last_keyval=key->keyval; return ClangView::on_key_press_event(key); } -void Source::ClangViewAutocomplete::start_autocomplete() { - if(!autocomplete_running) { - autocomplete_running=true; - cancel_show_autocomplete=false; +void Source::ClangViewAutocomplete::autocomplete() { + if(!autocomplete_starting) { + autocomplete_starting=true; + autocomplete_cancel_starting=false; + if(prefix.size()==0) { + if(selection_dialog.start_mark) + get_buffer()->delete_mark(selection_dialog.start_mark); + auto start_iter=get_buffer()->get_insert()->get_iter(); + selection_dialog.start_mark=get_buffer()->create_mark(start_iter); + } INFO("Source::ClangView::on_key_release getting autocompletions"); std::shared_ptr > ac_data=std::make_shared >(); - if(selection_dialog.start_mark) - get_buffer()->delete_mark(selection_dialog.start_mark); - selection_dialog.start_mark=get_buffer()->create_mark(get_buffer()->get_insert()->get_iter()); autocomplete_done_connection.disconnect(); autocomplete_done_connection=autocomplete_done.connect([this, ac_data](){ - if(!cancel_show_autocomplete) { + if(!autocomplete_cancel_starting) { + if(prefix.size()>0) { + if(selection_dialog.start_mark) + get_buffer()->delete_mark(selection_dialog.start_mark); + auto start_iter=get_buffer()->get_insert()->get_iter(); + for(size_t c=0;ccreate_mark(start_iter); + } + std::map > rows; for (auto &data : *ac_data) { std::stringstream ss; @@ -669,8 +692,10 @@ void Source::ClangViewAutocomplete::start_autocomplete() { } } if (ss.str().length() > 0) { // if length is 0 the result is empty - auto pair=std::pair(ss.str(), data.brief_comments); - rows[ss.str() + " --> " + return_value] = pair; + if(prefix.size()==0 || ss.str().find(prefix)==0) { + auto pair=std::pair(ss.str(), data.brief_comments); + rows[ss.str() + " --> " + return_value] = pair; + } } } if (rows.empty()) { @@ -679,18 +704,24 @@ void Source::ClangViewAutocomplete::start_autocomplete() { selection_dialog.rows=std::move(rows); selection_dialog.show(); } - autocomplete_running=false; + autocomplete_starting=false; }); std::shared_ptr > buffer_map=std::make_shared >(); - (*buffer_map)[this->file_path]=get_buffer()->get_text(get_buffer()->begin(), get_buffer()->get_insert()->get_iter()); - (*buffer_map)[this->file_path]+="\n"; + auto& buffer=(*buffer_map)[this->file_path]; + buffer=get_buffer()->get_text(get_buffer()->begin(), get_buffer()->get_insert()->get_iter()); auto iter = get_source_buffer()->get_insert()->get_iter(); auto line_nr=iter.get_line()+1; - auto column_nr=iter.get_line_offset()+2; + auto column_nr=iter.get_line_offset()+1; + while((buffer.back()>='a' && buffer.back()<='z') || (buffer.back()>='A' && buffer.back()<='Z') || (buffer.back()>='0' && buffer.back()<='9') || buffer.back()=='_') { + buffer.pop_back(); + column_nr--; + } + buffer+="\n"; std::thread autocomplete_thread([this, ac_data, line_nr, column_nr, buffer_map](){ parsing_mutex.lock(); *ac_data=move(get_autocomplete_suggestions(line_nr, column_nr, *buffer_map)); + cout << "selection size: " << ac_data->size() << endl; autocomplete_done(); parsing_mutex.unlock(); }); @@ -707,11 +738,13 @@ get_autocomplete_suggestions(int line_number, int column, std::map& mark); + bool on_motion_notify_event(GdkEventMotion* event); + void on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); sigc::connection delayed_tooltips_connection; - bool clangview_on_focus_out_event(GdkEventFocus* event); - bool clangview_on_scroll_event(GdkEventScroll* event); + bool on_focus_out_event(GdkEventFocus* event); + bool on_scroll_event(GdkEventScroll* event); static clang::Index clang_index; std::unique_ptr clang_tokens; bool clang_readable=false; @@ -129,14 +129,15 @@ namespace Source { protected: bool on_key_press_event(GdkEventKey* key); private: - void start_autocomplete(); + void autocomplete(); SelectionDialog selection_dialog; std::vector get_autocomplete_suggestions(int line_number, int column, std::map& buffer_map); Glib::Dispatcher autocomplete_done; sigc::connection autocomplete_done_connection; - bool autocomplete_running=false; - bool cancel_show_autocomplete=false; + bool autocomplete_starting=false; + bool autocomplete_cancel_starting=false; char last_keyval=0; + std::string prefix; }; class Controller { From 188a5b46cff64dfa02649093e36ec127979554c0 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 12 Jul 2015 16:17:53 +0200 Subject: [PATCH 33/34] Removed cout line. --- juci/source.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/juci/source.cc b/juci/source.cc index da5055c..b7beb13 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -721,7 +721,6 @@ void Source::ClangViewAutocomplete::autocomplete() { std::thread autocomplete_thread([this, ac_data, line_nr, column_nr, buffer_map](){ parsing_mutex.lock(); *ac_data=move(get_autocomplete_suggestions(line_nr, column_nr, *buffer_map)); - cout << "selection size: " << ac_data->size() << endl; autocomplete_done(); parsing_mutex.unlock(); }); From a1be9e0d927879bef72a1754ed8aef46c6e31335 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 12 Jul 2015 17:38:05 +0200 Subject: [PATCH 34/34] Cleanup and improvement of autocompletion. --- juci/selectiondialog.cc | 4 +-- juci/selectiondialog.h | 2 +- juci/source.cc | 57 ++++++++++++++--------------------------- juci/source.h | 2 +- 4 files changed, 23 insertions(+), 42 deletions(-) diff --git a/juci/selectiondialog.cc b/juci/selectiondialog.cc index 8edb13d..ca794bc 100644 --- a/juci/selectiondialog.cc +++ b/juci/selectiondialog.cc @@ -34,7 +34,7 @@ void SelectionDialog::show() { resize(); }); - start_offset=start_mark->get_iter().get_offset(); + show_offset=text_view.get_buffer()->get_insert()->get_iter().get_offset(); list_view_text->clear_items(); for (auto &i : rows) { list_view_text->append(i.first); @@ -99,7 +99,7 @@ bool SelectionDialog::on_key_release(GdkEventKey* key) { if(key->keyval==GDK_KEY_Down || key->keyval==GDK_KEY_Up) return false; - if(start_offset>text_view.get_buffer()->get_insert()->get_iter().get_offset()) { + if(show_offset>text_view.get_buffer()->get_insert()->get_iter().get_offset()) { hide(); } else { diff --git a/juci/selectiondialog.h b/juci/selectiondialog.h index 32d5e27..f93274f 100644 --- a/juci/selectiondialog.h +++ b/juci/selectiondialog.h @@ -24,7 +24,7 @@ private: void cursor_changed(); Gtk::Entry search_entry; - int start_offset; + int show_offset; bool row_in_entry; Gtk::TextView& text_view; diff --git a/juci/source.cc b/juci/source.cc index b7beb13..2c1d7e6 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -584,39 +584,29 @@ bool Source::ClangView::on_key_press_event(GdkEventKey* key) { Source::ClangViewAutocomplete::ClangViewAutocomplete(const std::string& file_path, const std::string& project_path, Terminal::Controller& terminal): Source::ClangView(file_path, project_path, terminal), selection_dialog(*this) { get_buffer()->signal_changed().connect([this](){ + if(last_keyval==GDK_KEY_BackSpace) + return; std::string line=" "+get_line_before_insert(); if((std::count(line.begin(), line.end(), '\"')%2)!=1 && line.find("//")==std::string::npos) { - const std::regex in_specified_namespace("^(.*)(->|\\.|::)([a-zA-Z0-9_]*)$"); - const std::regex within_namespace("^(.*)([^a-zA-Z0-9_]+)([a-zA-Z_][a-zA-Z0-9_]{2,})$"); + 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)) { - if(last_keyval=='.' || last_keyval=='>' || last_keyval==':') { - if(sm[3]=="" && !autocomplete_starting && !selection_dialog.shown) { - prefix=""; - autocomplete(); - } - else if(autocomplete_starting) - autocomplete_cancel_starting=true; + prefix=sm[3].str(); + if((prefix.size()==0 || prefix[0]<'0' || prefix[0]>'9') && !autocomplete_starting && !selection_dialog.shown) { + autocomplete(); } + else if(last_keyval=='.' && autocomplete_starting) + autocomplete_cancel_starting=true; } else if(std::regex_match(line, sm, within_namespace)) { prefix=sm[3].str(); - if((last_keyval>='a' && last_keyval<='z') || (last_keyval>='A' && last_keyval<='Z') || (last_keyval>='0' && last_keyval<='9') || last_keyval=='_') { - if(!autocomplete_starting && !selection_dialog.shown) { - autocomplete(); - } - } - else if(last_keyval!=0) { - autocomplete_cancel_starting=true; - if(selection_dialog.shown) - selection_dialog.hide(); + if((prefix.size()==0 || prefix[0]<'0' || prefix[0]>'9') && !autocomplete_starting && !selection_dialog.shown) { + autocomplete(); } } - else if(last_keyval!=0) { + else autocomplete_cancel_starting=true; - if(selection_dialog.shown) - selection_dialog.hide(); - } if(autocomplete_starting || selection_dialog.shown) delayed_reparse_connection.disconnect(); } @@ -645,38 +635,29 @@ Source::ClangView(file_path, project_path, terminal), selection_dialog(*this) { } bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { - last_keyval=0; + last_keyval=key->keyval; if(selection_dialog.shown) { delayed_reparse_connection.disconnect(); if(selection_dialog.on_key_press(key)) return true; } - last_keyval=key->keyval; return ClangView::on_key_press_event(key); } void Source::ClangViewAutocomplete::autocomplete() { if(!autocomplete_starting) { autocomplete_starting=true; autocomplete_cancel_starting=false; - if(prefix.size()==0) { - if(selection_dialog.start_mark) - get_buffer()->delete_mark(selection_dialog.start_mark); - auto start_iter=get_buffer()->get_insert()->get_iter(); - selection_dialog.start_mark=get_buffer()->create_mark(start_iter); - } INFO("Source::ClangView::on_key_release getting autocompletions"); std::shared_ptr > ac_data=std::make_shared >(); autocomplete_done_connection.disconnect(); autocomplete_done_connection=autocomplete_done.connect([this, ac_data](){ if(!autocomplete_cancel_starting) { - if(prefix.size()>0) { - if(selection_dialog.start_mark) - get_buffer()->delete_mark(selection_dialog.start_mark); - auto start_iter=get_buffer()->get_insert()->get_iter(); - for(size_t c=0;ccreate_mark(start_iter); - } + if(selection_dialog.start_mark) + get_buffer()->delete_mark(selection_dialog.start_mark); + auto start_iter=get_buffer()->get_insert()->get_iter(); + for(size_t c=0;ccreate_mark(start_iter); std::map > rows; for (auto &data : *ac_data) { diff --git a/juci/source.h b/juci/source.h index 4a6e170..a86654c 100644 --- a/juci/source.h +++ b/juci/source.h @@ -136,7 +136,7 @@ namespace Source { sigc::connection autocomplete_done_connection; bool autocomplete_starting=false; bool autocomplete_cancel_starting=false; - char last_keyval=0; + guint last_keyval=0; std::string prefix; };