Browse Source

Can now search in terminal

pipelines/235045657
eidheim 6 years ago
parent
commit
a4adb778dc
  1. 2
      src/notebook.cc
  2. 1
      src/notebook.h
  3. 223
      src/source_base.cc
  4. 33
      src/source_base.h
  5. 18
      src/terminal.cc
  6. 3
      src/terminal.h
  7. 135
      src/window.cc
  8. 4
      src/window.h
  9. 2
      tests/compile_commands_test.cc
  10. 35
      tests/ctags_grep_test.cc
  11. 2
      tests/terminal_test.cc

2
src/notebook.cc

@ -415,6 +415,8 @@ void Notebook::open(const boost::filesystem::path &file_path_, Position position
#endif #endif
view->signal_focus_in_event().connect([this, view](GdkEventFocus *) { view->signal_focus_in_event().connect([this, view](GdkEventFocus *) {
if(on_focus_page)
on_focus_page(view);
set_current_view(view); set_current_view(view);
return false; return false;
}); });

1
src/notebook.h

@ -57,6 +57,7 @@ public:
void update_status(Source::BaseView *view); void update_status(Source::BaseView *view);
void clear_status(); void clear_status();
std::function<void(Source::View *)> on_focus_page;
std::function<void(Source::View *)> on_change_page; std::function<void(Source::View *)> on_change_page;
std::function<void(Source::View *)> on_close_page; std::function<void(Source::View *)> on_close_page;

223
src/source_base.cc

@ -10,7 +10,119 @@
#include <gtksourceview/gtksource.h> #include <gtksourceview/gtksource.h>
#include <regex> #include <regex>
Source::BaseView::BaseView(const boost::filesystem::path &file_path, const Glib::RefPtr<Gsv::Language> &language) : Gsv::View(), file_path(file_path), language(language), status_diagnostics(0, 0, 0) { Source::SearchView::SearchView() : Gsv::View() {
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);
gtk_source_search_context_set_highlight(search_context, true);
g_signal_connect(search_context, "notify::occurrences-count", G_CALLBACK(search_occurrences_updated), this);
}
Source::SearchView::~SearchView() {
g_clear_object(&search_context);
g_clear_object(&search_settings);
}
void Source::SearchView::search_highlight(const std::string &text, bool case_sensitive, bool regex) {
gtk_source_search_settings_set_case_sensitive(search_settings, case_sensitive);
gtk_source_search_settings_set_regex_enabled(search_settings, regex);
gtk_source_search_settings_set_search_text(search_settings, text.c_str());
search_occurrences_updated(nullptr, nullptr, this);
}
void Source::SearchView::search_forward() {
Gtk::TextIter start, end;
get_buffer()->get_selection_bounds(start, end);
Gtk::TextIter match_start, match_end;
#if defined(GTK_SOURCE_MAJOR_VERSION) && (GTK_SOURCE_MAJOR_VERSION > 3 || (GTK_SOURCE_MAJOR_VERSION == 3 && GTK_SOURCE_MINOR_VERSION >= 22))
gboolean has_wrapped_around;
if(gtk_source_search_context_forward2(search_context, end.gobj(), match_start.gobj(), match_end.gobj(), &has_wrapped_around)) {
get_buffer()->select_range(match_start, match_end);
scroll_to(get_buffer()->get_insert());
}
#else
if(gtk_source_search_context_forward(search_context, end.gobj(), match_start.gobj(), match_end.gobj())) {
get_buffer()->select_range(match_start, match_end);
scroll_to(get_buffer()->get_insert());
}
#endif
}
void Source::SearchView::search_backward() {
Gtk::TextIter start, end;
get_buffer()->get_selection_bounds(start, end);
Gtk::TextIter match_start, match_end;
#if defined(GTK_SOURCE_MAJOR_VERSION) && (GTK_SOURCE_MAJOR_VERSION > 3 || (GTK_SOURCE_MAJOR_VERSION == 3 && GTK_SOURCE_MINOR_VERSION >= 22))
gboolean has_wrapped_around;
if(gtk_source_search_context_backward2(search_context, start.gobj(), match_start.gobj(), match_end.gobj(), &has_wrapped_around)) {
get_buffer()->select_range(match_start, match_end);
scroll_to(get_buffer()->get_insert());
}
#else
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());
}
#endif
}
void Source::SearchView::replace_forward(const std::string &replacement) {
Gtk::TextIter start, end;
get_buffer()->get_selection_bounds(start, end);
Gtk::TextIter match_start, match_end;
#if defined(GTK_SOURCE_MAJOR_VERSION) && (GTK_SOURCE_MAJOR_VERSION > 3 || (GTK_SOURCE_MAJOR_VERSION == 3 && GTK_SOURCE_MINOR_VERSION >= 22))
gboolean has_wrapped_around;
if(gtk_source_search_context_forward2(search_context, start.gobj(), match_start.gobj(), match_end.gobj(), &has_wrapped_around)) {
auto offset = match_start.get_offset();
gtk_source_search_context_replace2(search_context, match_start.gobj(), match_end.gobj(), replacement.c_str(), replacement.size(), nullptr);
Glib::ustring replacement_ustring = replacement;
get_buffer()->select_range(get_buffer()->get_iter_at_offset(offset), get_buffer()->get_iter_at_offset(offset + replacement_ustring.size()));
scroll_to(get_buffer()->get_insert());
}
#else
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(), nullptr);
Glib::ustring replacement_ustring = replacement;
get_buffer()->select_range(get_buffer()->get_iter_at_offset(offset), get_buffer()->get_iter_at_offset(offset + replacement_ustring.size()));
scroll_to(get_buffer()->get_insert());
}
#endif
}
void Source::SearchView::replace_backward(const std::string &replacement) {
Gtk::TextIter start, end;
get_buffer()->get_selection_bounds(start, end);
Gtk::TextIter match_start, match_end;
#if defined(GTK_SOURCE_MAJOR_VERSION) && (GTK_SOURCE_MAJOR_VERSION > 3 || (GTK_SOURCE_MAJOR_VERSION == 3 && GTK_SOURCE_MINOR_VERSION >= 22))
gboolean has_wrapped_around;
if(gtk_source_search_context_backward2(search_context, end.gobj(), match_start.gobj(), match_end.gobj(), &has_wrapped_around)) {
auto offset = match_start.get_offset();
gtk_source_search_context_replace2(search_context, match_start.gobj(), match_end.gobj(), replacement.c_str(), replacement.size(), nullptr);
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());
}
#else
if(gtk_source_search_context_backward(search_context, end.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(), nullptr);
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());
}
#endif
}
void Source::SearchView::replace_all(const std::string &replacement) {
gtk_source_search_context_replace_all(search_context, replacement.c_str(), replacement.size(), nullptr);
}
void Source::SearchView::search_occurrences_updated(GtkWidget *widget, GParamSpec *property, gpointer data) {
auto view = static_cast<Source::BaseView *>(data);
if(view->update_search_occurrences)
view->update_search_occurrences(gtk_source_search_context_get_occurrences_count(view->search_context));
}
Source::BaseView::BaseView(const boost::filesystem::path &file_path, const Glib::RefPtr<Gsv::Language> &language) : SearchView(), file_path(file_path), language(language), status_diagnostics(0, 0, 0) {
get_style_context()->add_class("juci_source_view"); get_style_context()->add_class("juci_source_view");
load(true); load(true);
@ -59,13 +171,6 @@ Source::BaseView::BaseView(const boost::filesystem::path &file_path, const Glib:
#endif #endif
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);
gtk_source_search_context_set_highlight(search_context, true);
g_signal_connect(search_context, "notify::occurrences-count", G_CALLBACK(search_occurrences_updated), this);
set_snippets(); set_snippets();
snippet_argument_tag = get_buffer()->create_tag(); snippet_argument_tag = get_buffer()->create_tag();
@ -85,9 +190,6 @@ Source::BaseView::BaseView(const boost::filesystem::path &file_path, const Glib:
} }
Source::BaseView::~BaseView() { Source::BaseView::~BaseView() {
g_clear_object(&search_context);
g_clear_object(&search_settings);
monitor_changed_connection.disconnect(); monitor_changed_connection.disconnect();
delayed_monitor_changed_connection.disconnect(); delayed_monitor_changed_connection.disconnect();
} }
@ -819,105 +921,6 @@ std::string Source::BaseView::get_selected_text() {
return get_buffer()->get_text(start, end); return get_buffer()->get_text(start, end);
} }
void Source::BaseView::search_highlight(const std::string &text, bool case_sensitive, bool regex) {
gtk_source_search_settings_set_case_sensitive(search_settings, case_sensitive);
gtk_source_search_settings_set_regex_enabled(search_settings, regex);
gtk_source_search_settings_set_search_text(search_settings, text.c_str());
search_occurrences_updated(nullptr, nullptr, this);
}
void Source::BaseView::search_forward() {
Gtk::TextIter start, end;
get_buffer()->get_selection_bounds(start, end);
Gtk::TextIter match_start, match_end;
#if defined(GTK_SOURCE_MAJOR_VERSION) && (GTK_SOURCE_MAJOR_VERSION > 3 || (GTK_SOURCE_MAJOR_VERSION == 3 && GTK_SOURCE_MINOR_VERSION >= 22))
gboolean has_wrapped_around;
if(gtk_source_search_context_forward2(search_context, end.gobj(), match_start.gobj(), match_end.gobj(), &has_wrapped_around)) {
get_buffer()->select_range(match_start, match_end);
scroll_to(get_buffer()->get_insert());
}
#else
if(gtk_source_search_context_forward(search_context, end.gobj(), match_start.gobj(), match_end.gobj())) {
get_buffer()->select_range(match_start, match_end);
scroll_to(get_buffer()->get_insert());
}
#endif
}
void Source::BaseView::search_backward() {
Gtk::TextIter start, end;
get_buffer()->get_selection_bounds(start, end);
Gtk::TextIter match_start, match_end;
#if defined(GTK_SOURCE_MAJOR_VERSION) && (GTK_SOURCE_MAJOR_VERSION > 3 || (GTK_SOURCE_MAJOR_VERSION == 3 && GTK_SOURCE_MINOR_VERSION >= 22))
gboolean has_wrapped_around;
if(gtk_source_search_context_backward2(search_context, start.gobj(), match_start.gobj(), match_end.gobj(), &has_wrapped_around)) {
get_buffer()->select_range(match_start, match_end);
scroll_to(get_buffer()->get_insert());
}
#else
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());
}
#endif
}
void Source::BaseView::replace_forward(const std::string &replacement) {
Gtk::TextIter start, end;
get_buffer()->get_selection_bounds(start, end);
Gtk::TextIter match_start, match_end;
#if defined(GTK_SOURCE_MAJOR_VERSION) && (GTK_SOURCE_MAJOR_VERSION > 3 || (GTK_SOURCE_MAJOR_VERSION == 3 && GTK_SOURCE_MINOR_VERSION >= 22))
gboolean has_wrapped_around;
if(gtk_source_search_context_forward2(search_context, start.gobj(), match_start.gobj(), match_end.gobj(), &has_wrapped_around)) {
auto offset = match_start.get_offset();
gtk_source_search_context_replace2(search_context, match_start.gobj(), match_end.gobj(), replacement.c_str(), replacement.size(), nullptr);
Glib::ustring replacement_ustring = replacement;
get_buffer()->select_range(get_buffer()->get_iter_at_offset(offset), get_buffer()->get_iter_at_offset(offset + replacement_ustring.size()));
scroll_to(get_buffer()->get_insert());
}
#else
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(), nullptr);
Glib::ustring replacement_ustring = replacement;
get_buffer()->select_range(get_buffer()->get_iter_at_offset(offset), get_buffer()->get_iter_at_offset(offset + replacement_ustring.size()));
scroll_to(get_buffer()->get_insert());
}
#endif
}
void Source::BaseView::replace_backward(const std::string &replacement) {
Gtk::TextIter start, end;
get_buffer()->get_selection_bounds(start, end);
Gtk::TextIter match_start, match_end;
#if defined(GTK_SOURCE_MAJOR_VERSION) && (GTK_SOURCE_MAJOR_VERSION > 3 || (GTK_SOURCE_MAJOR_VERSION == 3 && GTK_SOURCE_MINOR_VERSION >= 22))
gboolean has_wrapped_around;
if(gtk_source_search_context_backward2(search_context, end.gobj(), match_start.gobj(), match_end.gobj(), &has_wrapped_around)) {
auto offset = match_start.get_offset();
gtk_source_search_context_replace2(search_context, match_start.gobj(), match_end.gobj(), replacement.c_str(), replacement.size(), nullptr);
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());
}
#else
if(gtk_source_search_context_backward(search_context, end.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(), nullptr);
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());
}
#endif
}
void Source::BaseView::replace_all(const std::string &replacement) {
gtk_source_search_context_replace_all(search_context, replacement.c_str(), replacement.size(), nullptr);
}
void Source::BaseView::search_occurrences_updated(GtkWidget *widget, GParamSpec *property, gpointer data) {
auto view = static_cast<Source::BaseView *>(data);
if(view->update_search_occurrences)
view->update_search_occurrences(gtk_source_search_context_get_occurrences_count(view->search_context));
}
void Source::BaseView::set_snippets() { void Source::BaseView::set_snippets() {
LockGuard lock(snippets_mutex); LockGuard lock(snippets_mutex);

33
src/source_base.h

@ -10,7 +10,26 @@
#include <vector> #include <vector>
namespace Source { namespace Source {
class BaseView : public Gsv::View { class SearchView : public Gsv::View {
public:
SearchView();
~SearchView() override;
void search_highlight(const std::string &text, bool case_sensitive, bool regex);
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::function<void(int number)> update_search_occurrences;
private:
GtkSourceSearchContext *search_context;
GtkSourceSearchSettings *search_settings;
static void search_occurrences_updated(GtkWidget *widget, GParamSpec *property, gpointer data);
};
class BaseView : public SearchView {
public: public:
BaseView(const boost::filesystem::path &file_path, const Glib::RefPtr<Gsv::Language> &language); BaseView(const boost::filesystem::path &file_path, const Glib::RefPtr<Gsv::Language> &language);
~BaseView() override; ~BaseView() override;
@ -62,7 +81,6 @@ namespace Source {
std::string status_state; std::string status_state;
std::function<void(BaseView *view)> update_status_branch; std::function<void(BaseView *view)> update_status_branch;
std::string status_branch; std::string status_branch;
std::function<void(int number)> update_search_occurrences;
void cut(); void cut();
void cut_line(); void cut_line();
@ -70,22 +88,11 @@ namespace Source {
std::string get_selected_text(); std::string get_selected_text();
void search_highlight(const std::string &text, bool case_sensitive, bool regex);
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);
bool disable_spellcheck = false; bool disable_spellcheck = false;
void set_snippets(); void set_snippets();
private: private:
GtkSourceSearchContext *search_context;
GtkSourceSearchSettings *search_settings;
static void search_occurrences_updated(GtkWidget *widget, GParamSpec *property, gpointer data);
bool keep_clipboard = false; bool keep_clipboard = false;
protected: protected:

18
src/terminal.cc

@ -8,7 +8,7 @@
#include <regex> #include <regex>
#include <thread> #include <thread>
Terminal::Terminal() { Terminal::Terminal() : Source::SearchView() {
get_style_context()->add_class("juci_terminal"); get_style_context()->add_class("juci_terminal");
set_editable(false); set_editable(false);
@ -321,6 +321,22 @@ void Terminal::async_print(size_t line_nr, const std::string &message) {
void Terminal::configure() { void Terminal::configure() {
link_tag->property_foreground_rgba() = get_style_context()->get_color(Gtk::StateFlags::STATE_FLAG_LINK); link_tag->property_foreground_rgba() = get_style_context()->get_color(Gtk::StateFlags::STATE_FLAG_LINK);
// Set search match style:
get_buffer()->get_tag_table()->foreach([](const Glib::RefPtr<Gtk::TextTag> &tag) {
if(tag->property_background_set()) {
auto scheme = Source::StyleSchemeManager::get_default()->get_scheme(Config::get().source.style);
if(scheme) {
auto style = scheme->get_style("search-match");
if(style) {
if(style->property_background_set())
tag->property_background() = style->property_background();
if(style->property_foreground_set())
tag->property_foreground() = style->property_foreground();
}
}
}
});
} }
void Terminal::clear() { void Terminal::clear() {

3
src/terminal.h

@ -3,12 +3,13 @@
#include "gtkmm.h" #include "gtkmm.h"
#include "mutex.h" #include "mutex.h"
#include "process.hpp" #include "process.hpp"
#include "source_base.h"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <tuple> #include <tuple>
class Terminal : public Gtk::TextView { class Terminal : public Source::SearchView {
Terminal(); Terminal();
public: public:

135
src/window.cc

@ -56,19 +56,18 @@ Window::Window() {
Menu::get().right_click_line_menu->attach_to_widget(*this); Menu::get().right_click_line_menu->attach_to_widget(*this);
Menu::get().right_click_selected_menu->attach_to_widget(*this); Menu::get().right_click_selected_menu->attach_to_widget(*this);
EntryBox::get().signal_hide().connect([]() { EntryBox::get().signal_hide().connect([this]() {
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->grab_focus(); focused_view->grab_focus();
}); });
Notebook::get().on_change_page = [this](Source::View *view) { Notebook::get().on_focus_page = [this](Source::View *view) {
if(search_entry_shown && EntryBox::get().labels.size() > 0) { if(focused_view != view) {
view->update_search_occurrences = [](int number) { focused_view = view;
EntryBox::get().labels.begin()->update(0, std::to_string(number)); update_search_and_replace_entry();
};
view->search_highlight(last_search, case_sensitive_search, regex_search);
} }
};
Notebook::get().on_change_page = [](Source::View *view) {
Menu::get().toggle_menu_items(); Menu::get().toggle_menu_items();
Directories::get().select(view->file_path); Directories::get().select(view->file_path);
@ -85,7 +84,7 @@ Window::Window() {
Project::debug_update_stop(); Project::debug_update_stop();
#endif #endif
}; };
Notebook::get().on_close_page = [](Source::View *view) { Notebook::get().on_close_page = [this](Source::View *view) {
#ifdef JUCI_ENABLE_DEBUG #ifdef JUCI_ENABLE_DEBUG
if(Project::current && Project::debugging) { if(Project::current && Project::debugging) {
auto iter = view->get_buffer()->begin(); auto iter = view->get_buffer()->begin();
@ -102,11 +101,20 @@ Window::Window() {
Notebook::get().update_status(view); Notebook::get().update_status(view);
else { else {
Notebook::get().clear_status(); Notebook::get().clear_status();
Menu::get().toggle_menu_items(); Menu::get().toggle_menu_items();
if(dynamic_cast<Source::View *>(focused_view))
focused_view = nullptr;
} }
}; };
Terminal::get().signal_focus_in_event().connect([this](GdkEventFocus *) {
if(focused_view != &Terminal::get()) {
focused_view = &Terminal::get();
update_search_and_replace_entry();
}
return false;
});
signal_focus_out_event().connect([](GdkEventFocus *event) { signal_focus_out_event().connect([](GdkEventFocus *event) {
if(auto view = Notebook::get().get_current_view()) { if(auto view = Notebook::get().get_current_view()) {
view->hide_tooltips(); view->hide_tooltips();
@ -1809,49 +1817,43 @@ void Window::search_and_replace_entry() {
} }
}; };
if(auto view = Notebook::get().get_current_view()) { if(focused_view) {
if(Config::get().source.search_for_selection) { if(Config::get().source.search_for_selection) {
auto const selected = view->get_selected_text(); Gtk::TextIter start, end;
if(!selected.empty()) if(focused_view->get_buffer()->get_selection_bounds(start, end))
last_search = selected; last_search = focused_view->get_buffer()->get_text(start, end);
} }
} }
EntryBox::get().entries.emplace_back(last_search, [](const std::string &content) { EntryBox::get().entries.emplace_back(last_search, [this](const std::string &content) {
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->search_forward(); focused_view->search_forward();
}); });
auto search_entry_it = EntryBox::get().entries.begin(); auto search_entry_it = EntryBox::get().entries.begin();
search_entry_it->set_placeholder_text("Find"); search_entry_it->set_placeholder_text("Find");
if(auto view = Notebook::get().get_current_view()) { search_entry_it->signal_key_press_event().connect([this](GdkEventKey *event) {
view->update_search_occurrences = [label_it](int number) {
label_it->update(0, std::to_string(number));
};
view->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search);
}
search_entry_it->signal_key_press_event().connect([](GdkEventKey *event) {
if((event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter) && (event->state & GDK_SHIFT_MASK) > 0) { if((event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter) && (event->state & GDK_SHIFT_MASK) > 0) {
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->search_backward(); focused_view->search_backward();
} }
return false; return false;
}); });
search_entry_it->signal_changed().connect([this, search_entry_it]() { search_entry_it->signal_changed().connect([this, search_entry_it]() {
last_search = search_entry_it->get_text(); last_search = search_entry_it->get_text();
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); focused_view->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search);
}); });
EntryBox::get().entries.emplace_back(last_replace, [](const std::string &content) { EntryBox::get().entries.emplace_back(last_replace, [this](const std::string &content) {
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->replace_forward(content); focused_view->replace_forward(content);
}); });
auto replace_entry_it = EntryBox::get().entries.begin(); auto replace_entry_it = EntryBox::get().entries.begin();
replace_entry_it++; replace_entry_it++;
replace_entry_it->set_placeholder_text("Replace"); replace_entry_it->set_placeholder_text("Replace");
replace_entry_it->signal_key_press_event().connect([replace_entry_it](GdkEventKey *event) { replace_entry_it->signal_key_press_event().connect([this, replace_entry_it](GdkEventKey *event) {
if((event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter) && (event->state & GDK_SHIFT_MASK) > 0) { if((event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter) && (event->state & GDK_SHIFT_MASK) > 0) {
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->replace_backward(replace_entry_it->get_text()); focused_view->replace_backward(replace_entry_it->get_text());
} }
return false; return false;
}); });
@ -1859,25 +1861,24 @@ void Window::search_and_replace_entry() {
last_replace = replace_entry_it->get_text(); last_replace = replace_entry_it->get_text();
}); });
EntryBox::get().buttons.emplace_back("", []() { EntryBox::get().buttons.emplace_back("", [this]() {
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->search_backward(); focused_view->search_backward();
}); });
EntryBox::get().buttons.back().set_tooltip_text("Find Previous\n\nShortcut: Shift+Enter in the Find entry field"); EntryBox::get().buttons.back().set_tooltip_text("Find Previous\n\nShortcut: Shift+Enter in the Find entry field");
EntryBox::get().buttons.emplace_back("", [replace_entry_it]() { EntryBox::get().buttons.emplace_back("", [this, replace_entry_it]() {
if(auto view = Notebook::get().get_current_view()) { if(focused_view)
view->replace_forward(replace_entry_it->get_text()); focused_view->replace_forward(replace_entry_it->get_text());
}
}); });
EntryBox::get().buttons.back().set_tooltip_text("Replace Next\n\nShortcut: Enter in the Replace entry field"); EntryBox::get().buttons.back().set_tooltip_text("Replace Next\n\nShortcut: Enter in the Replace entry field");
EntryBox::get().buttons.emplace_back("", []() { EntryBox::get().buttons.emplace_back("", [this]() {
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->search_forward(); focused_view->search_forward();
}); });
EntryBox::get().buttons.back().set_tooltip_text("Find Next\n\nShortcut: Enter in the Find entry field"); EntryBox::get().buttons.back().set_tooltip_text("Find Next\n\nShortcut: Enter in the Find entry field");
EntryBox::get().buttons.emplace_back("Replace All", [replace_entry_it]() { EntryBox::get().buttons.emplace_back("Replace All", [this, replace_entry_it]() {
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->replace_all(replace_entry_it->get_text()); focused_view->replace_all(replace_entry_it->get_text());
}); });
EntryBox::get().buttons.back().set_tooltip_text("Replace All"); EntryBox::get().buttons.back().set_tooltip_text("Replace All");
@ -1886,28 +1887,56 @@ void Window::search_and_replace_entry() {
EntryBox::get().toggle_buttons.back().set_active(case_sensitive_search); EntryBox::get().toggle_buttons.back().set_active(case_sensitive_search);
EntryBox::get().toggle_buttons.back().on_activate = [this, search_entry_it]() { EntryBox::get().toggle_buttons.back().on_activate = [this, search_entry_it]() {
case_sensitive_search = !case_sensitive_search; case_sensitive_search = !case_sensitive_search;
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); focused_view->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search);
}; };
EntryBox::get().toggle_buttons.emplace_back(".*"); EntryBox::get().toggle_buttons.emplace_back(".*");
EntryBox::get().toggle_buttons.back().set_tooltip_text("Use Regex"); EntryBox::get().toggle_buttons.back().set_tooltip_text("Use Regex");
EntryBox::get().toggle_buttons.back().set_active(regex_search); EntryBox::get().toggle_buttons.back().set_active(regex_search);
EntryBox::get().toggle_buttons.back().on_activate = [this, search_entry_it]() { EntryBox::get().toggle_buttons.back().on_activate = [this, search_entry_it]() {
regex_search = !regex_search; regex_search = !regex_search;
if(auto view = Notebook::get().get_current_view()) if(focused_view)
view->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); focused_view->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search);
}; };
EntryBox::get().signal_hide().connect([this]() { EntryBox::get().signal_hide().connect([this]() {
for(size_t c = 0; c < Notebook::get().size(); c++) { for(size_t c = 0; c < Notebook::get().size(); c++) {
Notebook::get().get_view(c)->update_search_occurrences = nullptr; Notebook::get().get_view(c)->update_search_occurrences = nullptr;
Notebook::get().get_view(c)->search_highlight("", case_sensitive_search, regex_search); Notebook::get().get_view(c)->search_highlight("", case_sensitive_search, regex_search);
} }
Terminal::get().update_search_occurrences = nullptr;
Terminal::get().search_highlight("", case_sensitive_search, regex_search);
search_entry_shown = false; search_entry_shown = false;
}); });
search_entry_shown = true; search_entry_shown = true;
update_search_and_replace_entry();
EntryBox::get().show(); EntryBox::get().show();
} }
void Window::update_search_and_replace_entry() {
if(!search_entry_shown || !focused_view)
return;
focused_view->update_search_occurrences = [](int number) {
EntryBox::get().labels.begin()->update(0, std::to_string(number));
};
focused_view->search_highlight(last_search, case_sensitive_search, regex_search);
auto source_view = dynamic_cast<Source::View *>(focused_view);
auto entry = EntryBox::get().entries.begin();
entry++;
entry->set_sensitive(source_view);
auto button = EntryBox::get().buttons.begin();
button++;
button->set_sensitive(source_view);
button++;
button++;
button->set_sensitive(source_view);
}
void Window::set_tab_entry() { void Window::set_tab_entry() {
EntryBox::get().clear(); EntryBox::get().clear();
if(auto view = Notebook::get().get_current_view()) { if(auto view = Notebook::get().get_current_view()) {

4
src/window.h

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "source_base.h"
#include <atomic> #include <atomic>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <gtkmm.h> #include <gtkmm.h>
@ -25,6 +26,7 @@ private:
void configure(); void configure();
void set_menu_actions(); void set_menu_actions();
void search_and_replace_entry(); void search_and_replace_entry();
void update_search_and_replace_entry();
void set_tab_entry(); void set_tab_entry();
void goto_line_entry(); void goto_line_entry();
void rename_token_entry(); void rename_token_entry();
@ -36,6 +38,8 @@ private:
bool case_sensitive_search = true; bool case_sensitive_search = true;
bool regex_search = false; bool regex_search = false;
bool search_entry_shown = false; bool search_entry_shown = false;
/// Last source view focused
Source::SearchView *focused_view = nullptr;
bool find_pattern_case_sensitive = true; bool find_pattern_case_sensitive = true;
bool find_pattern_extended_regex = false; bool find_pattern_extended_regex = false;
}; };

2
tests/compile_commands_test.cc

@ -1,9 +1,11 @@
#include "compile_commands.h" #include "compile_commands.h"
#include <glib.h> #include <glib.h>
#include <gtkmm.h> #include <gtkmm.h>
#include <gtksourceviewmm.h>
int main() { int main() {
auto app = Gtk::Application::create(); auto app = Gtk::Application::create();
Gsv::init();
auto tests_path = boost::filesystem::canonical(JUCI_TESTS_PATH); auto tests_path = boost::filesystem::canonical(JUCI_TESTS_PATH);

35
tests/ctags_grep_test.cc

@ -3,6 +3,7 @@
#include "grep.h" #include "grep.h"
#include <glib.h> #include <glib.h>
#include <gtkmm.h> #include <gtkmm.h>
#include <gtksourceviewmm.h>
void ctags_grep_test_function() { void ctags_grep_test_function() {
} }
@ -14,6 +15,8 @@ class Test {
int main() { int main() {
auto app = Gtk::Application::create(); auto app = Gtk::Application::create();
Gsv::init();
#ifdef JUCI_USE_UCTAGS #ifdef JUCI_USE_UCTAGS
Config::get().project.ctags_command = "uctags"; Config::get().project.ctags_command = "uctags";
#else #else
@ -36,7 +39,7 @@ int main() {
auto location = ctags.get_location(line, false); auto location = ctags.get_location(line, false);
g_assert(location.source == "void ctags_grep_test_function() {"); g_assert(location.source == "void ctags_grep_test_function() {");
g_assert(ctags.project_path / location.file_path == tests_path / "ctags_grep_test.cc"); g_assert(ctags.project_path / location.file_path == tests_path / "ctags_grep_test.cc");
g_assert_cmpint(location.line, ==, 6); g_assert_cmpint(location.line, ==, 7);
g_assert_cmpint(location.index, ==, 5); g_assert_cmpint(location.index, ==, 5);
g_assert(location.symbol == "ctags_grep_test_function"); g_assert(location.symbol == "ctags_grep_test_function");
g_assert(location.scope.empty()); g_assert(location.scope.empty());
@ -46,7 +49,7 @@ int main() {
auto location = ctags.get_location(line, true); auto location = ctags.get_location(line, true);
g_assert(location.source == "void <b>ctags_grep_test_function</b>() {"); g_assert(location.source == "void <b>ctags_grep_test_function</b>() {");
g_assert(ctags.project_path / location.file_path == tests_path / "ctags_grep_test.cc"); g_assert(ctags.project_path / location.file_path == tests_path / "ctags_grep_test.cc");
g_assert_cmpint(location.line, ==, 6); g_assert_cmpint(location.line, ==, 7);
g_assert_cmpint(location.index, ==, 5); g_assert_cmpint(location.index, ==, 5);
g_assert(location.symbol == "ctags_grep_test_function"); g_assert(location.symbol == "ctags_grep_test_function");
g_assert(location.scope.empty()); g_assert(location.scope.empty());
@ -69,7 +72,7 @@ int main() {
auto location = ctags.get_location(line, false); auto location = ctags.get_location(line, false);
g_assert(location.source == "void ctags_grep_test_function() {"); g_assert(location.source == "void ctags_grep_test_function() {");
g_assert(ctags.project_path / location.file_path == tests_path / "ctags_grep_test.cc"); g_assert(ctags.project_path / location.file_path == tests_path / "ctags_grep_test.cc");
g_assert_cmpint(location.line, ==, 6); g_assert_cmpint(location.line, ==, 7);
g_assert_cmpint(location.index, ==, 5); g_assert_cmpint(location.index, ==, 5);
g_assert(location.symbol == "ctags_grep_test_function"); g_assert(location.symbol == "ctags_grep_test_function");
g_assert(location.scope.empty()); g_assert(location.scope.empty());
@ -79,7 +82,7 @@ int main() {
auto location = ctags.get_location(line, true); auto location = ctags.get_location(line, true);
g_assert(location.source == "void <b>ctags_grep_test_function</b>() {"); g_assert(location.source == "void <b>ctags_grep_test_function</b>() {");
g_assert(ctags.project_path / location.file_path == tests_path / "ctags_grep_test.cc"); g_assert(ctags.project_path / location.file_path == tests_path / "ctags_grep_test.cc");
g_assert_cmpint(location.line, ==, 6); g_assert_cmpint(location.line, ==, 7);
g_assert_cmpint(location.index, ==, 5); g_assert_cmpint(location.index, ==, 5);
g_assert(location.symbol == "ctags_grep_test_function"); g_assert(location.symbol == "ctags_grep_test_function");
g_assert(location.scope.empty()); g_assert(location.scope.empty());
@ -102,7 +105,7 @@ int main() {
auto location = ctags.get_location(line, false); auto location = ctags.get_location(line, false);
g_assert(location.source == "void ctags_grep_test_function2() {"); g_assert(location.source == "void ctags_grep_test_function2() {");
g_assert(ctags.project_path / location.file_path == tests_path / "ctags_grep_test.cc"); g_assert(ctags.project_path / location.file_path == tests_path / "ctags_grep_test.cc");
g_assert_cmpint(location.line, ==, 10); g_assert_cmpint(location.line, ==, 11);
g_assert_cmpint(location.index, ==, 7); g_assert_cmpint(location.index, ==, 7);
g_assert(location.symbol == "ctags_grep_test_function2"); g_assert(location.symbol == "ctags_grep_test_function2");
g_assert(location.scope == "Test"); g_assert(location.scope == "Test");
@ -125,43 +128,43 @@ int main() {
if(line.find("ctags_grep_test_function") != std::string::npos) { if(line.find("ctags_grep_test_function") != std::string::npos) {
{ {
auto location = grep.get_location(line, true, true); auto location = grep.get_location(line, true, true);
g_assert(location.markup == "tests/ctags_grep_test.cc:7:void <b>ctags_grep_test_function</b>() {"); g_assert(location.markup == "tests/ctags_grep_test.cc:8:void <b>ctags_grep_test_function</b>() {");
g_assert(grep.project_path / location.file_path == tests_path / "ctags_grep_test.cc"); g_assert(grep.project_path / location.file_path == tests_path / "ctags_grep_test.cc");
g_assert_cmpint(location.line, ==, 6); g_assert_cmpint(location.line, ==, 7);
g_assert_cmpint(location.offset, ==, 5); g_assert_cmpint(location.offset, ==, 5);
{ {
auto location2 = grep.get_location(location.markup, false, true); auto location2 = grep.get_location(location.markup, false, true);
g_assert(location2.markup == "tests/ctags_grep_test.cc:7:void <b>ctags_grep_test_function</b>() {"); g_assert(location2.markup == "tests/ctags_grep_test.cc:8:void <b>ctags_grep_test_function</b>() {");
g_assert(grep.project_path / location2.file_path == tests_path / "ctags_grep_test.cc"); g_assert(grep.project_path / location2.file_path == tests_path / "ctags_grep_test.cc");
g_assert_cmpint(location2.line, ==, 6); g_assert_cmpint(location2.line, ==, 7);
g_assert_cmpint(location2.offset, ==, 5); g_assert_cmpint(location2.offset, ==, 5);
} }
} }
{ {
auto location = grep.get_location(line, true, false); auto location = grep.get_location(line, true, false);
g_assert(location.markup == "tests/ctags_grep_test.cc:7:void <b>ctags_grep_test_function</b>() {"); g_assert(location.markup == "tests/ctags_grep_test.cc:8:void <b>ctags_grep_test_function</b>() {");
g_assert(grep.project_path / location.file_path == tests_path / "ctags_grep_test.cc"); g_assert(grep.project_path / location.file_path == tests_path / "ctags_grep_test.cc");
g_assert_cmpint(location.line, ==, 6); g_assert_cmpint(location.line, ==, 7);
g_assert_cmpint(location.offset, ==, 0); g_assert_cmpint(location.offset, ==, 0);
{ {
auto location2 = grep.get_location(location.markup, false, false); auto location2 = grep.get_location(location.markup, false, false);
g_assert(location2.markup == "tests/ctags_grep_test.cc:7:void <b>ctags_grep_test_function</b>() {"); g_assert(location2.markup == "tests/ctags_grep_test.cc:8:void <b>ctags_grep_test_function</b>() {");
g_assert(grep.project_path / location2.file_path == tests_path / "ctags_grep_test.cc"); g_assert(grep.project_path / location2.file_path == tests_path / "ctags_grep_test.cc");
g_assert_cmpint(location2.line, ==, 6); g_assert_cmpint(location2.line, ==, 7);
g_assert_cmpint(location2.offset, ==, 0); g_assert_cmpint(location2.offset, ==, 0);
} }
} }
{ {
auto location = grep.get_location(line, true, true, (boost::filesystem::path("tests") / "ctags_grep_test.cc").string()); auto location = grep.get_location(line, true, true, (boost::filesystem::path("tests") / "ctags_grep_test.cc").string());
g_assert(location.markup == "tests/ctags_grep_test.cc:7:void <b>ctags_grep_test_function</b>() {"); g_assert(location.markup == "tests/ctags_grep_test.cc:8:void <b>ctags_grep_test_function</b>() {");
g_assert(grep.project_path / location.file_path == tests_path / "ctags_grep_test.cc"); g_assert(grep.project_path / location.file_path == tests_path / "ctags_grep_test.cc");
g_assert(location); g_assert(location);
g_assert_cmpint(location.line, ==, 6); g_assert_cmpint(location.line, ==, 7);
g_assert_cmpint(location.offset, ==, 5); g_assert_cmpint(location.offset, ==, 5);
} }
{ {
auto location = grep.get_location(line, true, true, "CMakeLists.txt"); auto location = grep.get_location(line, true, true, "CMakeLists.txt");
g_assert(location.markup == "tests/ctags_grep_test.cc:7:void <b>ctags_grep_test_function</b>() {"); g_assert(location.markup == "tests/ctags_grep_test.cc:8:void <b>ctags_grep_test_function</b>() {");
g_assert(location.file_path.empty()); g_assert(location.file_path.empty());
g_assert(!location); g_assert(!location);
} }

2
tests/terminal_test.cc

@ -1,5 +1,6 @@
#include "terminal.h" #include "terminal.h"
#include <glib.h> #include <glib.h>
#include <gtksourceviewmm.h>
//Requires display server to work //Requires display server to work
//However, it is possible to use the Broadway backend if the test is run in a pure terminal environment: //However, it is possible to use the Broadway backend if the test is run in a pure terminal environment:
@ -8,6 +9,7 @@
int main() { int main() {
auto app = Gtk::Application::create(); auto app = Gtk::Application::create();
Gsv::init();
{ {
auto link = Terminal::get().find_link("~/test/test.cc:7:41: error: expected ';' after expression."); auto link = Terminal::get().find_link("~/test/test.cc:7:41: error: expected ';' after expression.");

Loading…
Cancel
Save