Browse Source

Fixed search and added replace. Use shift-enter in the entry boxes to search or replace backwards.

merge-requests/365/head
eidheim 11 years ago
parent
commit
5ec6243411
  1. 1
      juci/config.json
  2. 4
      juci/entrybox.cc
  3. 116
      juci/notebook.cc
  4. 5
      juci/notebook.h
  5. 122
      juci/source.cc
  6. 16
      juci/source.h
  7. 8
      juci/window.cc

1
juci/config.json

@ -2,7 +2,6 @@
"source": { "source": {
"colors": { "colors": {
"text_color": "black", "text_color": "black",
"search": "orange",
"string": "#CC0000", "string": "#CC0000",
"namespace_ref": "#990099", "namespace_ref": "#990099",
"type": "#0066FF", "type": "#0066FF",

4
juci/entrybox.cc

@ -29,11 +29,15 @@ void EntryBox::clear() {
} }
void EntryBox::show() { void EntryBox::show() {
std::vector<Gtk::Widget*> focus_chain;
for(auto& entry: entries) { for(auto& entry: entries) {
pack_start(entry, Gtk::PACK_SHRINK); pack_start(entry, Gtk::PACK_SHRINK);
focus_chain.emplace_back(&entry);
} }
for(auto& button: buttons) for(auto& button: buttons)
pack_start(button, Gtk::PACK_SHRINK); pack_start(button, Gtk::PACK_SHRINK);
set_focus_chain(focus_chain);
show_all(); show_all();
if(entries.size()>0) { if(entries.size()>0) {
entries.begin()->grab_focus(); entries.begin()->grab_focus();

116
juci/notebook.cc

@ -2,7 +2,12 @@
#include "notebook.h" #include "notebook.h"
#include "logging.h" #include "logging.h"
#include "singletons.h" #include "singletons.h"
#include <gtksourceview/gtksource.h> // c-library #include <iostream> //TODO: remove
using namespace std; //TODO: remove
namespace sigc {
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
}
Notebook::View::View() { Notebook::View::View() {
pack2(notebook); pack2(notebook);
@ -21,6 +26,10 @@ Notebook::Controller::Controller() :
CurrentSourceView()->grab_focus(); CurrentSourceView()->grab_focus();
} }
}); });
view.notebook.signal_switch_page().connect([this](Gtk::Widget* page, guint page_num) {
if(search_entry_shown && CurrentPage()!=-1)
CurrentSourceView()->search_highlight(last_search);
});
INFO("Notebook Controller Success"); INFO("Notebook Controller Success");
} // Constructor } // Constructor
@ -45,27 +54,63 @@ void Notebook::Controller::CreateKeybindings() {
//TODO: Also update cursor position //TODO: Also update cursor position
menu->action_group->add(Gtk::Action::create("EditFind", "Find"), Gtk::AccelKey(menu->key_map["edit_find"]), [this]() { menu->action_group->add(Gtk::Action::create("EditFind", "Find"), Gtk::AccelKey(menu->key_map["edit_find"]), [this]() {
entry_box.clear(); entry_box.clear();
entry_box.entries.emplace_back("", [this](const std::string& content){ entry_box.entries.emplace_back(last_search, [this](const std::string& content){
search(content, true); if(CurrentPage()!=-1)
CurrentSourceView()->search_forward();
}); });
auto entry_it=entry_box.entries.begin(); auto search_entry_it=entry_box.entries.begin();
entry_box.buttons.emplace_back("Next", [this, entry_it](){ search_entry_it->set_placeholder_text("Find");
search(entry_it->get_text(), true); if(CurrentPage()!=-1)
CurrentSourceView()->search_highlight(search_entry_it->get_text());
search_entry_it->signal_key_press_event().connect([this, search_entry_it](GdkEventKey* event){
if(event->keyval==GDK_KEY_Return && event->state==GDK_SHIFT_MASK) {
if(CurrentPage()!=-1)
CurrentSourceView()->search_backward();
}
return false;
}); });
entry_box.buttons.emplace_back("Previous", [this, entry_it](){ search_entry_it->signal_changed().connect([this, search_entry_it](){
search(entry_it->get_text(), false); last_search=search_entry_it->get_text();
if(CurrentPage()!=-1)
CurrentSourceView()->search_highlight(search_entry_it->get_text());
}); });
entry_box.buttons.emplace_back("Cancel", [this](){
entry_box.hide(); entry_box.entries.emplace_back(last_replace, [this](const std::string &content){
if(CurrentPage()!=-1)
CurrentSourceView()->replace_forward(content);
}); });
entry_box.signal_hide().connect([this]() { auto replace_entry_it=entry_box.entries.begin();
auto buffer=CurrentSourceView()->get_buffer(); replace_entry_it++;
buffer->remove_tag_by_name("search", buffer->begin(), buffer->end()); replace_entry_it->set_placeholder_text("Replace");
if(search_context!=NULL) { replace_entry_it->signal_key_press_event().connect([this, replace_entry_it](GdkEventKey* event){
gtk_source_search_context_set_highlight(search_context, false); if(event->keyval==GDK_KEY_Return && event->state==GDK_SHIFT_MASK) {
if(CurrentPage()!=-1)
CurrentSourceView()->replace_backward(replace_entry_it->get_text());
} }
return false;
});
replace_entry_it->signal_changed().connect([this, replace_entry_it](){
last_replace=replace_entry_it->get_text();
});
entry_box.buttons.emplace_back("Find", [this](){
if(CurrentPage()!=-1)
CurrentSourceView()->search_forward();
});
entry_box.buttons.emplace_back("Replace", [this, replace_entry_it](){
if(CurrentPage()!=-1)
CurrentSourceView()->replace_forward(replace_entry_it->get_text());
}); });
search_context=NULL; //TODO: delete content if any? Neither delete nor free worked... Do this on hide entry_box.buttons.emplace_back("Replace all", [this, replace_entry_it](){
if(CurrentPage()!=-1)
CurrentSourceView()->replace_all(replace_entry_it->get_text());
});
entry_box.signal_hide().connect([this]() {
for(int c=0;c<Pages();c++)
source_views.at(c)->view->search_highlight("");
search_entry_shown=false;
});
search_entry_shown=true;
entry_box.show(); entry_box.show();
}); });
menu->action_group->add(Gtk::Action::create("EditCopy", "Copy"), Gtk::AccelKey(menu->key_map["edit_copy"]), [this]() { menu->action_group->add(Gtk::Action::create("EditCopy", "Copy"), Gtk::AccelKey(menu->key_map["edit_copy"]), [this]() {
@ -203,48 +248,9 @@ void Notebook::Controller::OnFileNewFile() {
entry_box.buttons.emplace_back("Create file", [this, entry_it](){ entry_box.buttons.emplace_back("Create file", [this, entry_it](){
entry_it->activate(); entry_it->activate();
}); });
entry_box.buttons.emplace_back("Cancel", [this](){
entry_box.hide();
});
entry_box.show(); entry_box.show();
} }
//TODO: see search TODO earlier
void Notebook::Controller::search(const std::string& text, bool forward) {
INFO("Notebook search");
if(search_context!=NULL)
gtk_source_search_context_set_highlight(search_context, false);
auto start = CurrentSourceView()->search_start;
auto end = CurrentSourceView()->search_end;
// fetch buffer and greate settings
auto buffer = CurrentSourceView()->get_source_buffer();
auto settings = gtk_source_search_settings_new();
gtk_source_search_settings_set_search_text(settings, text.c_str());
// make sure the search continues
gtk_source_search_settings_set_wrap_around(settings, true);
search_context = gtk_source_search_context_new(buffer->gobj(), settings);
gtk_source_search_context_set_highlight(search_context, true);
auto itr = buffer->get_insert()->get_iter();
buffer->remove_tag_by_name("search", start ? start : itr, end ? end : itr);
if (forward) {
DEBUG("Doing forward search");
gtk_source_search_context_forward(search_context,
end ? end.gobj() : itr.gobj(),
start.gobj(),
end.gobj());
} else {
DEBUG("Doing backward search");
gtk_source_search_context_backward(search_context,
start ? start.gobj() : itr.gobj(),
start.gobj(),
end.gobj());
}
buffer->apply_tag_by_name("search", start, end);
CurrentSourceView()->scroll_to(end);
CurrentSourceView()->search_start = start;
CurrentSourceView()->search_end = end;
}
void Notebook::Controller void Notebook::Controller
::OnDirectoryNavigation(const Gtk::TreeModel::Path& path, ::OnDirectoryNavigation(const Gtk::TreeModel::Path& path,
Gtk::TreeViewColumn* column) { Gtk::TreeViewColumn* column) {

5
juci/notebook.h

@ -31,13 +31,14 @@ namespace Notebook {
Gtk::TreeViewColumn* column); Gtk::TreeViewColumn* column);
void open_file(std::string filename); void open_file(std::string filename);
int Pages(); int Pages();
void search(const std::string& text, bool forward);
GtkSourceSearchContext* search_context;
View view; View view;
std::string OnSaveFileAs(); std::string OnSaveFileAs();
std::string project_path; std::string project_path;
Directories::Controller directories; //Todo: make private after creating open_directory() Directories::Controller directories; //Todo: make private after creating open_directory()
EntryBox entry_box; EntryBox entry_box;
std::string last_search;
std::string last_replace;
bool search_entry_shown=false;
std::vector<std::unique_ptr<Source> > source_views; std::vector<std::unique_ptr<Source> > source_views;
private: private:
void CreateKeybindings(); void CreateKeybindings();

122
juci/source.cc

@ -7,6 +7,7 @@
#include <algorithm> #include <algorithm>
#include <regex> #include <regex>
#include "singletons.h" #include "singletons.h"
#include <gtksourceview/gtksource.h>
#include <iostream> //TODO: remove #include <iostream> //TODO: remove
using namespace std; //TODO: remove using namespace std; //TODO: remove
@ -37,7 +38,6 @@ file_path(file_path), project_path(project_path) {
get_source_buffer()->get_undo_manager()->begin_not_undoable_action(); get_source_buffer()->get_undo_manager()->begin_not_undoable_action();
get_source_buffer()->set_text(s.get_content()); get_source_buffer()->set_text(s.get_content());
get_source_buffer()->get_undo_manager()->end_not_undoable_action(); get_source_buffer()->get_undo_manager()->end_not_undoable_action();
search_start = search_end = this->get_buffer()->end();
override_font(Pango::FontDescription(Singleton::Config::source()->font)); override_font(Pango::FontDescription(Singleton::Config::source()->font));
@ -58,6 +58,82 @@ file_path(file_path), project_path(project_path) {
after_user_input=true; after_user_input=true;
return false; return false;
}); });
search_settings = gtk_source_search_settings_new();
gtk_source_search_settings_set_wrap_around(search_settings, true);
search_context = gtk_source_search_context_new(get_source_buffer()->gobj(), search_settings);
//TODO: why does this not work?: Might be best to use the styles from sourceview. These has to be read from file, search-matches got style "search-match"
//TODO: in header if trying again: GtkSourceStyle* search_match_style;
//search_match_style=(GtkSourceStyle*)g_object_new(GTK_SOURCE_TYPE_STYLE, "background-set", 1, "background", "#00FF00", NULL);
//gtk_source_search_context_set_match_style(search_context, search_match_style);
}
Source::View::~View() {
g_clear_object(&search_context);
g_clear_object(&search_settings);
}
void Source::View::search_highlight(const std::string &text) {
if(text.size()>0) {
gtk_source_search_settings_set_search_text(search_settings, text.c_str());
gtk_source_search_context_set_highlight(search_context, true);
}
else
gtk_source_search_context_set_highlight(search_context, false);
}
void Source::View::search_forward() {
Gtk::TextIter insert, selection_bound;
get_buffer()->get_selection_bounds(insert, selection_bound);
auto& start=selection_bound;
Gtk::TextIter match_start, match_end;
if(gtk_source_search_context_forward(search_context, start.gobj(), match_start.gobj(), match_end.gobj())) {
get_buffer()->select_range(match_start, match_end);
scroll_to(get_buffer()->get_insert());
}
}
void Source::View::search_backward() {
Gtk::TextIter insert, selection_bound;
get_buffer()->get_selection_bounds(insert, selection_bound);
auto &start=insert;
Gtk::TextIter match_start, match_end;
if(gtk_source_search_context_backward(search_context, start.gobj(), match_start.gobj(), match_end.gobj())) {
get_buffer()->select_range(match_start, match_end);
scroll_to(get_buffer()->get_insert());
}
}
void Source::View::replace_forward(const std::string &replacement) {
Gtk::TextIter insert, selection_bound;
get_buffer()->get_selection_bounds(insert, selection_bound);
auto &start=insert;
Gtk::TextIter match_start, match_end;
if(gtk_source_search_context_forward(search_context, start.gobj(), match_start.gobj(), match_end.gobj())) {
auto offset=match_start.get_offset();
gtk_source_search_context_replace(search_context, match_start.gobj(), match_end.gobj(), replacement.c_str(), replacement.size(), NULL);
get_buffer()->select_range(get_buffer()->get_iter_at_offset(offset), get_buffer()->get_iter_at_offset(offset+replacement.size()));
scroll_to(get_buffer()->get_insert());
}
}
void Source::View::replace_backward(const std::string &replacement) {
Gtk::TextIter insert, selection_bound;
get_buffer()->get_selection_bounds(insert, selection_bound);
auto &start=selection_bound;
Gtk::TextIter match_start, match_end;
if(gtk_source_search_context_backward(search_context, start.gobj(), match_start.gobj(), match_end.gobj())) {
auto offset=match_start.get_offset();
gtk_source_search_context_replace(search_context, match_start.gobj(), match_end.gobj(), replacement.c_str(), replacement.size(), NULL);
get_buffer()->select_range(get_buffer()->get_iter_at_offset(offset), get_buffer()->get_iter_at_offset(offset+replacement.size()));
scroll_to(get_buffer()->get_insert());
}
}
void Source::View::replace_all(const std::string &replacement) {
gtk_source_search_context_replace_all(search_context, replacement.c_str(), replacement.size(), NULL);
} }
string Source::View::get_line(size_t line_number) { string Source::View::get_line(size_t line_number) {
@ -163,7 +239,28 @@ clang::Index Source::ClangViewParse::clang_index(0, 0);
Source::ClangViewParse::ClangViewParse(const std::string& file_path, const std::string& project_path): Source::ClangViewParse::ClangViewParse(const std::string& file_path, const std::string& project_path):
Source::View(file_path, project_path), Source::View(file_path, project_path),
parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) {
//Create underline color tags for diagnostic warnings and errors:
auto diagnostic_tag=get_buffer()->get_tag_table()->lookup("diagnostic_warning");
auto diagnostic_tag_underline=Gtk::TextTag::create("diagnostic_warning_underline");
get_buffer()->get_tag_table()->add(diagnostic_tag_underline);
diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR;
auto tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions:
auto param_spec=g_object_class_find_property(tag_class, "underline-rgba");
if(param_spec!=NULL) {
diagnostic_tag_underline->set_property("underline-rgba", diagnostic_tag->property_foreground_rgba().get_value());
}
diagnostic_tag=get_buffer()->get_tag_table()->lookup("diagnostic_error");
diagnostic_tag_underline=Gtk::TextTag::create("diagnostic_error_underline");
get_buffer()->get_tag_table()->add(diagnostic_tag_underline);
diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR;
tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions:
param_spec=g_object_class_find_property(tag_class, "underline-rgba");
if(param_spec!=NULL) {
diagnostic_tag_underline->set_property("underline-rgba", diagnostic_tag->property_foreground_rgba().get_value());
}
//TODO: clear tag_class and param_spec?
int start_offset = get_source_buffer()->begin().get_offset(); int start_offset = get_source_buffer()->begin().get_offset();
int end_offset = get_source_buffer()->end().get_offset(); int end_offset = get_source_buffer()->end().get_offset();
auto buffer_map=get_buffer_map(); auto buffer_map=get_buffer_map();
@ -323,11 +420,13 @@ void Source::ClangViewParse::update_syntax() {
return; return;
} }
auto buffer = get_source_buffer(); auto buffer = get_source_buffer();
buffer->remove_all_tags(buffer->begin(), buffer->end()); for(auto &tag: last_syntax_tags)
buffer->remove_tag_by_name(tag, buffer->begin(), buffer->end());
last_syntax_tags.clear();
for (auto &range : ranges) { for (auto &range : ranges) {
std::string type = std::to_string(range.kind); std::string type = std::to_string(range.kind);
try { try {
Singleton::Config::source()->types.at(type); last_syntax_tags.emplace(Singleton::Config::source()->types.at(type));
} catch (std::exception) { } catch (std::exception) {
continue; continue;
} }
@ -341,6 +440,8 @@ void Source::ClangViewParse::update_syntax() {
void Source::ClangViewParse::update_diagnostics() { void Source::ClangViewParse::update_diagnostics() {
diagnostic_tooltips.clear(); diagnostic_tooltips.clear();
get_buffer()->remove_tag_by_name("diagnostic_warning_underline", get_buffer()->begin(), get_buffer()->end());
get_buffer()->remove_tag_by_name("diagnostic_error_underline", get_buffer()->begin(), get_buffer()->end());
auto diagnostics=clang_tu->get_diagnostics(); auto diagnostics=clang_tu->get_diagnostics();
for(auto &diagnostic: diagnostics) { for(auto &diagnostic: diagnostics) {
if(diagnostic.path==file_path) { if(diagnostic.path==file_path) {
@ -362,17 +463,8 @@ void Source::ClangViewParse::update_diagnostics() {
return tooltip_buffer; return tooltip_buffer;
}; };
diagnostic_tooltips.emplace_back(get_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); diagnostic_tooltips.emplace_back(get_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end));
auto tag=get_buffer()->create_tag(); get_buffer()->apply_tag_by_name(diagnostic_tag_name+"_underline", start, end);
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=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());
}
get_buffer()->apply_tag(tag, start, end);
} }
} }
} }

16
juci/source.h

@ -13,6 +13,7 @@
#include "terminal.h" #include "terminal.h"
#include "tooltips.h" #include "tooltips.h"
#include "selectiondialog.h" #include "selectiondialog.h"
#include <set>
class Source { class Source {
public: public:
@ -47,17 +48,29 @@ public:
class View : public Gsv::View { class View : public Gsv::View {
public: public:
View(const std::string& file_path, const std::string& project_path); View(const std::string& file_path, const std::string& project_path);
~View();
void search_highlight(const std::string &text);
void search_forward();
void search_backward();
void replace_forward(const std::string &replacement);
void replace_backward(const std::string &replacement);
void replace_all(const std::string &replacement);
std::string get_line(size_t line_number); std::string get_line(size_t line_number);
std::string get_line_before_insert(); std::string get_line_before_insert();
std::string file_path; std::string file_path;
std::string project_path; std::string project_path;
Gtk::TextIter search_start, search_end;
std::function<std::pair<std::string, unsigned>()> get_declaration_location; std::function<std::pair<std::string, unsigned>()> get_declaration_location;
std::function<void()> goto_method; std::function<void()> goto_method;
bool after_user_input=false; bool after_user_input=false;
protected: protected:
bool on_key_press_event(GdkEventKey* key); bool on_key_press_event(GdkEventKey* key);
private:
GtkSourceSearchContext *search_context;
GtkSourceSearchSettings *search_settings;
}; // class View }; // class View
class GenericView : public View { class GenericView : public View {
@ -89,6 +102,7 @@ public:
int end_offset); int end_offset);
int reparse(const std::map<std::string, std::string> &buffers); int reparse(const std::map<std::string, std::string> &buffers);
void update_syntax(); void update_syntax();
std::set<std::string> last_syntax_tags;
void update_diagnostics(); void update_diagnostics();
void update_types(); void update_types();
Tooltips diagnostic_tooltips; Tooltips diagnostic_tooltips;

8
juci/window.cc

@ -85,6 +85,14 @@ Window::Window() :
Singleton::notebook()->entry_box.hide(); Singleton::notebook()->entry_box.hide();
return false; return false;
}); });
Singleton::notebook()->entry_box.signal_show().connect([this](){
std::vector<Gtk::Widget*> focus_chain;
focus_chain.emplace_back(&Singleton::notebook()->entry_box);
window_box_.set_focus_chain(focus_chain);
});
Singleton::notebook()->entry_box.signal_hide().connect([this](){
window_box_.unset_focus_chain();
});
INFO("Window created"); INFO("Window created");
} // Window constructor } // Window constructor

Loading…
Cancel
Save