[gnome-builder] Search Feature in Terminal



commit 4b1ecbe4824c2bbc9aad9565dbea7d3f53306dab
Author: kritarth <kritarth 3010 gmail com>
Date:   Sat Jan 21 01:52:06 2017 +0530

    Search Feature in Terminal
    
    round 4
    
    Created separate class for the search revealer ui. This helped in
    making the code more compact and readable.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=763022

 contrib/gd/Makefile.am                        |   11 +-
 libide/Makefile.am                            |    3 +-
 plugins/terminal/Makefile.am                  |    8 +-
 plugins/terminal/gb-terminal-search-private.h |   62 ++++
 plugins/terminal/gb-terminal-search.c         |  395 +++++++++++++++++++++++++
 plugins/terminal/gb-terminal-search.h         |   39 +++
 plugins/terminal/gb-terminal-search.ui        |  220 ++++++++++++++
 plugins/terminal/gb-terminal-view-private.h   |   13 +
 plugins/terminal/gb-terminal-view.c           |   36 ++-
 plugins/terminal/gb-terminal-view.h           |    4 +-
 plugins/terminal/gb-terminal-view.ui          |   46 ++--
 plugins/terminal/gb-terminal.c                |   36 +++
 plugins/terminal/gb-terminal.gresource.xml    |    1 +
 13 files changed, 842 insertions(+), 32 deletions(-)
---
diff --git a/contrib/gd/Makefile.am b/contrib/gd/Makefile.am
index 5ac2bd5..58c1820 100644
--- a/contrib/gd/Makefile.am
+++ b/contrib/gd/Makefile.am
@@ -3,14 +3,15 @@ CLEANFILES =
 BUILT_SOURCES =
 EXTRA_DIST =
 
-noinst_LTLIBRARIES = libgd.la
+pkglibdir = $(libdir)/gnome-builder
+pkglib_LTLIBRARIES = libgd-private.la
 
-libgd_la_SOURCES = \
+libgd_private_la_SOURCES = \
        gd-tagged-entry.c \
        gd-tagged-entry.h \
        $(NULL)
 
-nodist_libgd_la_SOURCES = \
+nodist_libgd_private_la_SOURCES = \
        gd-resources.c \
        gd-resources.h
 
@@ -20,7 +21,7 @@ glib_resources_xml = gd-tagged-entry.gresource.xml
 glib_resources_namespace = gd
 include $(top_srcdir)/build/autotools/Makefile.am.gresources
 
-libgd_la_CFLAGS = $(GD_CFLAGS)
-libgd_la_LIBADD = $(GD_LIBS)
+libgd_private_la_CFLAGS = $(GD_CFLAGS)
+libgd_private_la_LIBADD = $(GD_LIBS)
 
 -include $(top_srcdir)/git.mk
diff --git a/libide/Makefile.am b/libide/Makefile.am
index ee3ac39..0577dd3 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -588,6 +588,7 @@ libide_1_0_la_LDFLAGS =                         \
        $(OPTIMIZE_LDFLAGS)                     \
        -avoid-version                          \
        -no-undefined                           \
+       --no-as-needed                          \
        -export-symbols-regex '^(ide_|_ide_).*' \
        $(NULL)
 
@@ -597,7 +598,7 @@ libide_1_0_la_LIBADD =                                          \
        -lm                                                     \
        $(top_builddir)/data/icons/hicolor/libicons.la          \
        $(top_builddir)/contrib/egg/libegg-private.la           \
-       $(top_builddir)/contrib/gd/libgd.la                     \
+       $(top_builddir)/contrib/gd/libgd-private.la             \
        $(top_builddir)/contrib/jsonrpc-glib/libjsonrpc-glib.la \
        $(top_builddir)/contrib/nautilus/libnautilus.la         \
        $(top_builddir)/contrib/pnl/libpanel-gtk.la             \
diff --git a/plugins/terminal/Makefile.am b/plugins/terminal/Makefile.am
index 17c2f13..5483a50 100644
--- a/plugins/terminal/Makefile.am
+++ b/plugins/terminal/Makefile.am
@@ -23,6 +23,9 @@ libterminal_la_SOURCES = \
        gb-terminal-view-private.h \
        gb-terminal-view-actions.c \
        gb-terminal-view-actions.h \
+       gb-terminal-search.c \
+       gb-terminal-search.h \
+       gb-terminal-search-private.h \
        gb-terminal-workbench-addin.c \
        gb-terminal-workbench-addin.h \
        $(NULL)
@@ -33,7 +36,10 @@ nodist_libterminal_la_SOURCES = \
        $(NULL)
 
 libterminal_la_CFLAGS = $(PLUGIN_CFLAGS) $(TERMINAL_CFLAGS)
-libterminal_la_LIBADD = $(TERMINAL_LIBS)
+libterminal_la_LIBADD = \
+    $(TERMINAL_LIBS) \
+    $(top_builddir)/contrib/gd/libgd-private.la \
+    $(NULL)
 libterminal_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 
 glib_resources_c = gb-terminal-resources.c
diff --git a/plugins/terminal/gb-terminal-search-private.h b/plugins/terminal/gb-terminal-search-private.h
new file mode 100644
index 0000000..0ff7833
--- /dev/null
+++ b/plugins/terminal/gb-terminal-search-private.h
@@ -0,0 +1,62 @@
+/* gb-terminal-view-private.h
+ *
+ * Copyright (C) 2015 Sebastien Lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_TERMINAL_SEARCH_PRIVATE_H
+#define GB_TERMINAL_SEARCH_PRIVATE_H
+
+#include <gd-tagged-entry.h>
+#include <ide.h>
+#include <vte/vte.h>
+
+G_BEGIN_DECLS
+
+struct _GbTerminalSearch
+{
+  GtkBin               parent_instance;
+
+  VteTerminal         *terminal;
+
+  GtkRevealer         *search_revealer;
+  
+  GdTaggedEntry       *search_entry;
+
+  GtkButton           *search_prev_button;
+  GtkButton           *search_next_button;
+  GtkButton           *close_button;
+
+  GtkGrid             *search_options;
+
+  GtkToggleButton     *reveal_button;
+  GtkToggleButton     *match_case_checkbutton;
+  GtkToggleButton     *entire_word_checkbutton;
+  GtkToggleButton     *regex_checkbutton;
+  GtkToggleButton     *wrap_around_checkbutton;
+
+  /* Cached regex */
+  gboolean             regex_caseless;
+  gchar               *regex_pattern;
+  VteRegex            *regex;
+
+  GtkClipboard        *clipboard;
+  gchar               *selected_text;
+  gchar               *selection_buffer;
+};
+
+G_END_DECLS
+
+#endif /* GB_TERMINAL_SEARCH_PRIVATE_H */
diff --git a/plugins/terminal/gb-terminal-search.c b/plugins/terminal/gb-terminal-search.c
new file mode 100644
index 0000000..70c8246
--- /dev/null
+++ b/plugins/terminal/gb-terminal-search.c
@@ -0,0 +1,395 @@
+/* gb-terminal-search.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gb-terminal-search"
+#define PCRE2_CODE_UNIT_WIDTH 0
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <glib/gi18n.h>
+#include <ide.h>
+#include <pcre2.h>
+#include <stdlib.h>
+#include <vte/vte.h>
+#include <unistd.h>
+
+#include "gb-terminal-search.h"
+#include "gb-terminal-search-private.h"
+
+G_DEFINE_TYPE (GbTerminalSearch, gb_terminal_search, GTK_TYPE_BIN)
+
+enum {
+  PROP_0,
+  PROP_REGEX,
+  PROP_WRAP_AROUND,
+  LAST_PROP
+};
+
+enum {
+  SEARCH,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+static GParamSpec *properties[LAST_PROP];
+
+static void
+update_sensitivity (GbTerminalSearch *self)
+{
+  gboolean can_search;
+
+  can_search = self->regex != NULL;
+
+  gtk_widget_set_sensitive (GTK_WIDGET (self->search_prev_button), can_search);
+  gtk_widget_set_sensitive (GTK_WIDGET (self->search_next_button), can_search);
+}
+
+static void
+perform_search (GbTerminalSearch *self,
+                gboolean       backward)
+{
+  g_assert (GB_IS_TERMINAL_SEARCH (self));
+
+  if (self->regex == NULL)
+    return;
+
+  g_signal_emit (self, signals[SEARCH], 0, backward);
+}
+
+static void
+close_clicked_cb (GtkButton        *button,
+                  GbTerminalSearch *self)
+{
+  g_assert (GB_IS_TERMINAL_SEARCH (self));
+
+  gtk_revealer_set_reveal_child(self->search_revealer, FALSE);
+}
+
+static void
+search_button_clicked_cb (GtkButton        *button,
+                          GbTerminalSearch *self)
+{
+  g_assert (GB_IS_TERMINAL_SEARCH (self));
+
+  perform_search (self, button == self->search_prev_button);
+}
+
+static void
+update_regex (GbTerminalSearch *self)
+{
+  const char *search_text;
+  gboolean caseless;
+  g_autofree gchar *pattern = NULL;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (GB_IS_TERMINAL_SEARCH (self));
+
+  search_text = gtk_entry_get_text (GTK_ENTRY (self->search_entry));
+  caseless = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->match_case_checkbutton));
+
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->regex_checkbutton)))
+    pattern = g_strdup (search_text);
+  else
+    pattern = g_regex_escape_string (search_text, -1);
+
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->entire_word_checkbutton)))
+    {
+      char *new_pattern;
+      new_pattern = g_strdup_printf ("\\b%s\\b", pattern);
+      g_free (pattern);
+      pattern = new_pattern;
+    }
+
+  if (self->regex_caseless == caseless &&
+      g_strcmp0 (self->regex_pattern, pattern) == 0)
+    return;
+
+  if (self->regex)
+    {
+      vte_regex_unref (self->regex);
+    }
+
+  g_clear_pointer (&self->regex_pattern, g_free);
+
+  if (search_text[0] != '\0')
+    {
+      guint32 compile_flags;
+
+      compile_flags = PCRE2_UTF | PCRE2_NO_UTF_CHECK | PCRE2_MULTILINE;
+      if (caseless)
+        compile_flags |= PCRE2_CASELESS;
+
+      self->regex = vte_regex_new_for_search (pattern, -1, compile_flags, &error);
+
+      if (self->regex != NULL)
+        self->regex_pattern = g_steal_pointer (&pattern);
+    }
+  else
+    self->regex = NULL;
+
+  update_sensitivity (self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_REGEX]);     
+}
+
+static void
+search_text_changed_cb (GdTaggedEntry  *search_entry,
+                        GbTerminalSearch *self)
+{
+  update_regex (self);
+}
+
+static void
+search_parameters_changed_cb (GtkToggleButton *button,
+                              GbTerminalSearch  *self)
+{
+  update_regex (self);
+}
+
+static void
+wrap_around_toggled_cb (GtkToggleButton *button,
+                        GbTerminalSearch  *self)
+{
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WRAP_AROUND]);
+}
+
+static void
+reveal_options_changed_cb (GtkToggleButton *button,
+                           GbTerminalSearch  *self)
+{
+  g_assert (GB_IS_TERMINAL_SEARCH (self));
+
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->reveal_button)))
+    gtk_widget_set_visible (GTK_WIDGET (self->search_options), TRUE);
+  else
+    gtk_widget_set_visible (GTK_WIDGET (self->search_options), FALSE);
+}
+
+static void
+search_overlay_notify_regex_cb (VteTerminal    *terminal,
+                                GParamSpec     *pspec G_GNUC_UNUSED,
+                                GbTerminalSearch *self)
+{
+  VteRegex *regex;
+
+  g_assert (GB_IS_TERMINAL_SEARCH (self));
+  g_assert (VTE_IS_TERMINAL (terminal));
+
+  regex = terminal_search_get_regex (self);
+  vte_terminal_search_set_regex (VTE_TERMINAL (terminal), regex, 0);
+}
+
+static void
+search_overlay_notify_wrap_around_cb (VteTerminal    *terminal,
+                                      GParamSpec     *pspec G_GNUC_UNUSED,
+                                      GbTerminalSearch *self)
+{
+  gboolean wrap;
+
+  g_assert (GB_IS_TERMINAL_SEARCH (self));
+  g_assert (VTE_IS_TERMINAL (terminal));
+
+  wrap = terminal_search_get_wrap_around (self);
+  vte_terminal_search_set_wrap_around (terminal, wrap);
+}
+
+static void
+search_overlay_search_cb (VteTerminal    *terminal,
+                          gboolean        backward,
+                          GbTerminalSearch *self)
+{
+  g_assert (VTE_IS_TERMINAL (terminal));
+
+  if (backward)
+    vte_terminal_search_find_previous (terminal);
+  else
+    vte_terminal_search_find_next (terminal);
+}
+
+static void
+search_revealer_cb (GtkRevealer      *search_revealer,
+                    GParamSpec       *pspec G_GNUC_UNUSED,
+                    GbTerminalSearch *self)
+{
+  g_assert (GB_IS_TERMINAL_SEARCH (self));
+
+  if (gtk_revealer_get_child_revealed (search_revealer))
+    { 
+      if (vte_terminal_get_has_selection (self->terminal))
+        {
+          vte_terminal_copy_primary (self->terminal);
+          self->selected_text = gtk_clipboard_wait_for_text (self->clipboard);
+          gtk_entry_set_text (GTK_ENTRY (self->search_entry), self->selected_text);
+        }
+      gtk_widget_grab_focus (GTK_WIDGET (self->search_entry));
+    }
+  else
+    {
+      gtk_revealer_set_reveal_child (self->search_revealer, FALSE);
+    }
+}
+
+static void
+gb_terminal_search_connect_terminal (GbTerminalSearch *self)
+{
+  g_signal_connect_object (self,
+                           "notify::regex",
+                           G_CALLBACK (search_overlay_notify_regex_cb),
+                           self->terminal,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (self,
+                           "notify::wrap-around",
+                           G_CALLBACK (search_overlay_notify_wrap_around_cb),
+                           self->terminal,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (self,
+                           "search",
+                           G_CALLBACK (search_overlay_search_cb),
+                           self->terminal,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+gb_terminal_search_get_property (GObject    *object,
+                               guint       prop_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+  GbTerminalSearch *self = GB_TERMINAL_SEARCH (object);
+
+  switch (prop_id)
+    {
+    case PROP_REGEX:
+      g_value_set_boxed (value, terminal_search_get_regex (self));
+      break;
+    
+    case PROP_WRAP_AROUND:
+      g_value_set_boolean (value, terminal_search_get_wrap_around (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gb_terminal_search_class_init (GbTerminalSearchClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->get_property = gb_terminal_search_get_property;
+  
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/plugins/terminal/gb-terminal-search.ui");
+  
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, search_prev_button);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, search_next_button);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, close_button);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, search_entry);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, match_case_checkbutton);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, entire_word_checkbutton);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, regex_checkbutton);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, wrap_around_checkbutton);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, reveal_button);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, search_revealer);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalSearch, search_options);
+
+  g_type_ensure (GD_TYPE_TAGGED_ENTRY);
+
+  signals[SEARCH] =
+    g_signal_new ("search",
+                  G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE,
+                  1,
+                  G_TYPE_BOOLEAN);
+
+  properties[PROP_REGEX] =
+    g_param_spec_boxed ("regex", NULL, NULL,
+                        VTE_TYPE_REGEX,
+                        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_WRAP_AROUND] =
+    g_param_spec_boolean ("wrap-around", NULL, NULL,
+                          FALSE,
+                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, LAST_PROP, properties);
+}
+
+static void
+gb_terminal_search_init (GbTerminalSearch *self)
+{
+  self->regex_caseless = FALSE;
+  self->regex_pattern = 0;
+
+  self->clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  g_signal_connect (self->search_prev_button, "clicked", G_CALLBACK (search_button_clicked_cb), self);
+  g_signal_connect (self->search_next_button, "clicked", G_CALLBACK (search_button_clicked_cb), self);
+  g_signal_connect (self->close_button, "clicked", G_CALLBACK (close_clicked_cb), self);
+  g_signal_connect (self->search_entry, "search-changed", G_CALLBACK (search_text_changed_cb), self);
+  g_signal_connect (self->match_case_checkbutton, "toggled", G_CALLBACK (search_parameters_changed_cb), 
self);
+  g_signal_connect (self->entire_word_checkbutton, "toggled", G_CALLBACK (search_parameters_changed_cb), 
self);
+  g_signal_connect (self->regex_checkbutton, "toggled", G_CALLBACK (search_parameters_changed_cb), self);
+  g_signal_connect (self->reveal_button, "toggled", G_CALLBACK (reveal_options_changed_cb), self);
+  g_signal_connect (self->wrap_around_checkbutton, "toggled", G_CALLBACK (wrap_around_toggled_cb), self);
+  g_signal_connect (self->search_revealer, "notify::child-revealed", G_CALLBACK (search_revealer_cb), self);
+}
+
+
+void
+gb_terminal_search_set_terminal (GbTerminalSearch *self,
+                                 VteTerminal      *terminal)
+{
+  g_assert (GB_IS_TERMINAL_SEARCH (self));
+  
+  self->terminal = terminal;
+  gb_terminal_search_connect_terminal (self);
+}
+
+VteRegex *
+terminal_search_get_regex (GbTerminalSearch *self)
+{
+  g_return_val_if_fail (GB_IS_TERMINAL_SEARCH (self), NULL);
+
+  return self->regex;
+}
+
+gboolean
+terminal_search_get_wrap_around (GbTerminalSearch *self)
+{
+  g_return_val_if_fail (GB_IS_TERMINAL_SEARCH (self), FALSE);
+
+  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->wrap_around_checkbutton));
+}
+
+GtkRevealer *
+terminal_search_get_revealer (GbTerminalSearch *self)
+{
+  g_return_val_if_fail (GB_IS_TERMINAL_SEARCH (self), FALSE);
+
+  return self->search_revealer;
+}
\ No newline at end of file
diff --git a/plugins/terminal/gb-terminal-search.h b/plugins/terminal/gb-terminal-search.h
new file mode 100644
index 0000000..e300940
--- /dev/null
+++ b/plugins/terminal/gb-terminal-search.h
@@ -0,0 +1,39 @@
+/* gb-terminal-view.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_TERMINAL_SEARCH_H
+#define GB_TERMINAL_SEARCH_H
+
+#include <ide.h>
+#include <vte/vte.h>
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_TERMINAL_SEARCH (gb_terminal_search_get_type())
+
+G_DECLARE_FINAL_TYPE (GbTerminalSearch, gb_terminal_search, GB, TERMINAL_SEARCH, GtkBin)
+
+VteRegex    *terminal_search_get_regex       (GbTerminalSearch *self);
+gboolean     terminal_search_get_wrap_around (GbTerminalSearch *self);
+void         gb_terminal_search_set_terminal  (GbTerminalSearch *self,
+                                                                          VteTerminal      *terminal);
+GtkRevealer *terminal_search_get_revealer     (GbTerminalSearch *self);
+
+G_END_DECLS
+
+#endif /* GB_TERMINAL_SEARCH_H */
diff --git a/plugins/terminal/gb-terminal-search.ui b/plugins/terminal/gb-terminal-search.ui
new file mode 100644
index 0000000..1b1f0e6
--- /dev/null
+++ b/plugins/terminal/gb-terminal-search.ui
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- <template class="GbTerminalSearch" parent="GtkBin">
+    <child> -->
+      <object class="GtkRevealer" id="search_revealer">
+        <property name="halign">end</property>
+        <property name="valign">start</property>
+        <property name="visible">true</property>
+        <child>
+          <object class="GtkFrame">
+            <property name="visible">true</property>
+            <property name="margin-end">12</property>
+            <style>
+              <class name="gb-search-frame"/>
+            </style>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">true</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">7</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">true</property>
+                    <property name="can_focus">false</property>
+                    <property name="row_spacing">8</property>
+                    <property name="column_spacing">8</property>
+                    <child>
+                      <object class="GdTaggedEntry" id="search_entry">
+                        <property name="visible">true</property>
+                        <property name="can_focus">true</property>
+                        <property name="width-chars">20</property>
+                        <property name="max-width-chars">30</property>
+                        <property name="primary_icon_name">edit-find-symbolic</property>
+                        <property name="primary_icon_activatable">false</property>
+                        <property name="primary_icon_sensitive">false</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="homogeneous">true</property>
+                        <property name="visible">true</property>
+                        <property name="can_focus">false</property>
+                        <property name="valign">center</property>
+                        <style>
+                          <class name="linked"/>
+                        </style>
+                        <child>
+                          <object class="GtkButton" id="search_prev_button">
+                            <property name="visible">true</property>
+                            <property name="can_focus">false</property>
+                            <property name="receives_default">true</property>
+                            <child>
+                              <object class="GtkImage">
+                                <property name="visible">true</property>
+                                <property name="can_focus">false</property>
+                                <property name="icon_name">go-up-symbolic</property>
+                                <property name="icon_size">1</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">false</property>
+                            <property name="fill">true</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkButton" id="search_next_button">
+                            <property name="visible">true</property>
+                            <property name="can_focus">false</property>
+                            <property name="receives_default">true</property>
+                            <child>
+                              <object class="GtkImage">
+                                <property name="visible">true</property>
+                                <property name="can_focus">false</property>
+                                <property name="icon_name">go-down-symbolic</property>
+                                <property name="icon_size">1</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">false</property>
+                            <property name="fill">true</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkToggleButton" id="reveal_button">
+                        <property name="action-target">true</property>
+                        <property name="tooltip-text" translatable="yes">Show or hide search options such as 
case sensitivity</property>
+                        <property name="visible">true</property>
+                        <property name="can_focus">true</property>
+                        <property name="receives_default">true</property>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">true</property>
+                            <property name="can_focus">false</property>
+                            <property name="icon_name">emblem-system-symbolic</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="close_button">
+                        <property name="visible">true</property>
+                        <property name="halign">center</property>
+                        <property name="valign">center</property>
+                        <property name="focus_on_click">false</property>
+                        <style>
+                          <class name="close"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">true</property>
+                            <property name="icon_name">window-close-symbolic</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">3</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">false</property>
+                    <property name="fill">true</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkGrid" id="search_options">
+                    <property name="visible">false</property>
+                    <property name="can_focus">false</property>
+                    <property name="column_spacing">8</property>
+                    <child>
+                      <object class="GtkCheckButton" id="regex_checkbutton">
+                        <property name="label" translatable="yes">Regex</property>
+                        <property name="visible">true</property>
+                        <property name="can_focus">false</property>
+                        <property name="receives_default">false</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">true</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="match_case_checkbutton">
+                        <property name="label" translatable="yes">Case sensitive</property>
+                        <property name="visible">true</property>
+                        <property name="can_focus">false</property>
+                        <property name="receives_default">false</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">true</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="entire_word_checkbutton">
+                        <property name="label" translatable="yes">Match whole word</property>
+                        <property name="visible">true</property>
+                        <property name="can_focus">false</property>
+                        <property name="receives_default">false</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">true</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="wrap_around_checkbutton">
+                        <property name="label" translatable="yes">Wrap around</property>
+                        <property name="visible">true</property>
+                        <property name="can_focus">false</property>
+                        <property name="receives_default">false</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">true</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">3</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">false</property>
+                    <property name="fill">true</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    <!-- </child>
+  </template> -->
+</interface>
\ No newline at end of file
diff --git a/plugins/terminal/gb-terminal-view-private.h b/plugins/terminal/gb-terminal-view-private.h
index 775ebdc..a615d37 100644
--- a/plugins/terminal/gb-terminal-view-private.h
+++ b/plugins/terminal/gb-terminal-view-private.h
@@ -19,21 +19,34 @@
 #ifndef GB_TERMINAL_VIEW_PRIVATE_H
 #define GB_TERMINAL_VIEW_PRIVATE_H
 
+#include <gd-tagged-entry.h>
 #include <ide.h>
 #include <vte/vte.h>
 
+#include "gb-terminal-search.h"
+#include "gb-terminal-search-private.h"
+
 G_BEGIN_DECLS
 
 struct _GbTerminalView
 {
   IdeLayoutView        parent_instance;
 
+  GtkOverlay          *terminal_overlay_top;
+  GtkOverlay          *terminal_overlay_bottom;
+
+  GtkRevealer         *search_revealer_top;
+  GtkRevealer         *search_revealer_bottom;
+
   VteTerminal         *terminal_top;
   VteTerminal         *terminal_bottom;
 
   GtkScrollbar        *top_scrollbar;
   GtkScrollbar        *bottom_scrollbar;
 
+  GbTerminalSearch    *tsearch;
+  GbTerminalSearch    *bsearch;
+
   GFile               *save_as_file_top;
   GFile               *save_as_file_bottom;
 
diff --git a/plugins/terminal/gb-terminal-view.c b/plugins/terminal/gb-terminal-view.c
index bccac42..676b2cd 100644
--- a/plugins/terminal/gb-terminal-view.c
+++ b/plugins/terminal/gb-terminal-view.c
@@ -17,12 +17,14 @@
  */
 
 #define G_LOG_DOMAIN "gb-terminal-view"
+#define PCRE2_CODE_UNIT_WIDTH 0
 
 #include "config.h"
 
 #include <fcntl.h>
 #include <glib/gi18n.h>
 #include <ide.h>
+#include <pcre2.h>
 #include <stdlib.h>
 #include <vte/vte.h>
 #include <unistd.h>
@@ -43,7 +45,7 @@ enum {
   LAST_PROP
 };
 
-static GParamSpec *properties [LAST_PROP];
+static GParamSpec *properties[LAST_PROP];
 static gchar *cached_shell;
 
 /* TODO: allow palette to come from gnome-terminal. */
@@ -459,16 +461,18 @@ focus_in_event_cb (VteTerminal    *terminal,
   g_assert (GB_IS_TERMINAL_VIEW (self));
 
   self->bottom_has_focus = (terminal != self->terminal_top);
-
+  
   if (terminal == self->terminal_top)
     {
       self->top_has_needs_attention = FALSE;
       gb_terminal_set_needs_attention (self, FALSE, GTK_POS_TOP);
+      gtk_revealer_set_reveal_child (self->search_revealer_top, FALSE);
     }
   else if (terminal == self->terminal_bottom)
     {
       self->bottom_has_needs_attention = FALSE;
       gb_terminal_set_needs_attention (self, FALSE, GTK_POS_BOTTOM);
+      gtk_revealer_set_reveal_child (self->search_revealer_bottom, FALSE);
     }
 
   return GDK_EVENT_PROPAGATE;
@@ -594,9 +598,18 @@ gb_terminal_set_split_view (IdeLayoutView   *view,
                                          GTK_WIDGET (self->terminal_bottom),
                                          "position", 0,
                                          NULL);
-      gtk_widget_show (self->bottom_container);
+      gtk_widget_show ( GTK_WIDGET (self->terminal_overlay_bottom));
+
+      self->bsearch = g_object_new (GB_TYPE_TERMINAL_SEARCH, NULL);
+      self->search_revealer_bottom = terminal_search_get_revealer (self->bsearch);
+
+      gtk_overlay_add_overlay (self->terminal_overlay_bottom,
+                               GTK_WIDGET (self->search_revealer_bottom));
 
       gb_terminal_view_connect_terminal (self, self->terminal_bottom);
+
+      gb_terminal_search_set_terminal (self->bsearch, self->terminal_bottom);
+
       style_context_changed (style_context, GB_TERMINAL_VIEW (view));
 
       gtk_widget_grab_focus (GTK_WIDGET (self->terminal_bottom));
@@ -609,15 +622,19 @@ gb_terminal_set_split_view (IdeLayoutView   *view,
     }
   else
     {
+      gtk_container_remove (GTK_CONTAINER (self->terminal_overlay_bottom),
+                            GTK_WIDGET (self->search_revealer_bottom));
       gtk_container_remove (GTK_CONTAINER (self->bottom_container),
                             GTK_WIDGET (self->terminal_bottom));
-      gtk_widget_hide (self->bottom_container);
+      gtk_widget_hide ( GTK_WIDGET (self->terminal_overlay_bottom));
 
       self->terminal_bottom = NULL;
+      self->search_revealer_bottom = NULL;
       self->bottom_has_focus = FALSE;
       self->bottom_has_spawned = FALSE;
       self->bottom_has_needs_attention = FALSE;
       g_clear_object (&self->save_as_file_bottom);
+      g_clear_object (&self->bsearch);
       gtk_widget_grab_focus (GTK_WIDGET (self->terminal_top));
     }
 }
@@ -765,6 +782,8 @@ gb_terminal_view_class_init (GbTerminalViewClass *klass)
   gtk_widget_class_bind_template_child (widget_class, GbTerminalView, bottom_container);
   gtk_widget_class_bind_template_child (widget_class, GbTerminalView, top_scrollbar);
   gtk_widget_class_bind_template_child (widget_class, GbTerminalView, bottom_scrollbar);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalView, terminal_overlay_top);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalView, terminal_overlay_bottom);
 
   g_type_ensure (VTE_TYPE_TERMINAL);
 
@@ -802,9 +821,18 @@ gb_terminal_view_init (GbTerminalView *self)
 
   self->manage_spawn = TRUE;
 
+  self->tsearch = g_object_new (GB_TYPE_TERMINAL_SEARCH, NULL);
+  self->search_revealer_top = terminal_search_get_revealer (self->tsearch);
+
   gtk_widget_init_template (GTK_WIDGET (self));
 
+  gtk_overlay_add_overlay (self->terminal_overlay_top,
+                           GTK_WIDGET (self->search_revealer_top));
+
   gb_terminal_view_connect_terminal (self, self->terminal_top);
+
+  gb_terminal_search_set_terminal (self->tsearch, self->terminal_top);
+
   gb_terminal_view_actions_init (self);
 
   settings = g_settings_new ("org.gnome.builder.terminal");
diff --git a/plugins/terminal/gb-terminal-view.h b/plugins/terminal/gb-terminal-view.h
index b4169da..278d42c 100644
--- a/plugins/terminal/gb-terminal-view.h
+++ b/plugins/terminal/gb-terminal-view.h
@@ -28,8 +28,8 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GbTerminalView, gb_terminal_view, GB, TERMINAL_VIEW, IdeLayoutView)
 
-void gb_terminal_view_set_pty (GbTerminalView *self,
-                               VtePty         *pty);
+void      gb_terminal_view_set_pty        (GbTerminalView *self,
+                                           VtePty         *pty);
 
 G_END_DECLS
 
diff --git a/plugins/terminal/gb-terminal-view.ui b/plugins/terminal/gb-terminal-view.ui
index 30a3ebe..871333a 100644
--- a/plugins/terminal/gb-terminal-view.ui
+++ b/plugins/terminal/gb-terminal-view.ui
@@ -9,39 +9,47 @@
         <property name="orientation">vertical</property>
         <property name="visible">true</property>
         <child>
-          <object class="GtkBox" id="top_container">
-            <property name="orientation">horizontal</property>
+          <object class="GtkOverlay" id="terminal_overlay_top">
             <property name="expand">true</property>
             <property name="visible">true</property>
             <child>
-              <object class="GbTerminal" id="terminal_top">
-                <property name="audible-bell">false</property>
+              <object class="GtkBox" id="top_container">
+                <property name="orientation">horizontal</property>
                 <property name="expand">true</property>
                 <property name="visible">true</property>
-                <property name="scrollback-lines">0xffffffff</property>
-              </object>
-            </child>
-            <child>
-              <object class="GtkScrollbar" id="top_scrollbar">
-                <property name="orientation">vertical</property>
-                <property name="visible">true</property>
+                <child>
+                  <object class="GbTerminal" id="terminal_top">
+                    <property name="audible-bell">false</property>
+                    <property name="expand">true</property>
+                    <property name="visible">true</property>
+                    <property name="scrollback-lines">0xffffffff</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkScrollbar" id="top_scrollbar">
+                    <property name="orientation">vertical</property>
+                    <property name="visible">true</property>
+                  </object>
+                </child>
               </object>
             </child>
           </object>
-          <packing>
-            <property name="resize">true</property>
-            <property name="shrink">true</property>
-          </packing>
         </child>
         <child>
-          <object class="GtkBox" id="bottom_container">
-            <property name="orientation">horizontal</property>
+          <object class="GtkOverlay" id="terminal_overlay_bottom">
             <property name="expand">true</property>
             <property name="visible">false</property>
             <child>
-              <object class="GtkScrollbar" id="bottom_scrollbar">
-                <property name="orientation">vertical</property>
+              <object class="GtkBox" id="bottom_container">
+                <property name="orientation">horizontal</property>
+                <property name="expand">true</property>
                 <property name="visible">true</property>
+                <child>
+                  <object class="GtkScrollbar" id="bottom_scrollbar">
+                    <property name="orientation">vertical</property>
+                    <property name="visible">true</property>
+                  </object>
+                </child>
               </object>
             </child>
           </object>
diff --git a/plugins/terminal/gb-terminal.c b/plugins/terminal/gb-terminal.c
index 872477e..8e64bf8 100644
--- a/plugins/terminal/gb-terminal.c
+++ b/plugins/terminal/gb-terminal.c
@@ -48,6 +48,7 @@ struct _GbTerminalClass
                                    GtkWidget  *widget);
   void     (*select_all)          (GbTerminal *self,
                                    gboolean    all);
+  void     (*search_reveal)       (GbTerminal *self);
   gboolean (*open_link)           (GbTerminal *self);
   gboolean (*copy_link_address)   (GbTerminal *self);
 };
@@ -59,6 +60,7 @@ enum {
   OPEN_LINK,
   POPULATE_POPUP,
   SELECT_ALL,
+  SEARCH_REVEAL,
   LAST_SIGNAL
 };
 
@@ -233,6 +235,24 @@ gb_terminal_open_link (GbTerminal *self)
 }
 
 static void
+gb_terminal_real_search_reveal (GbTerminal *self)
+{
+  GtkWidget *parent_overlay;
+
+  g_assert (GB_IS_TERMINAL (self));
+
+  parent_overlay = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_OVERLAY);
+
+  if (parent_overlay != NULL)
+    {
+      GtkRevealer *revealer = ide_widget_find_child_typed (parent_overlay, GTK_TYPE_REVEALER);
+      
+      if (revealer != NULL && !gtk_revealer_get_child_revealed (revealer))
+        gtk_revealer_set_reveal_child (revealer, TRUE);
+    }
+}
+
+static void
 gb_terminal_class_init (GbTerminalClass *klass)
 {
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
@@ -244,6 +264,7 @@ gb_terminal_class_init (GbTerminalClass *klass)
   klass->copy_link_address = gb_terminal_copy_link_address;
   klass->open_link = gb_terminal_open_link;
   klass->select_all = gb_terminal_real_select_all;
+  klass->search_reveal = gb_terminal_real_search_reveal;
 
   signals [COPY_LINK_ADDRESS] =
     g_signal_new ("copy-link-address",
@@ -254,6 +275,15 @@ gb_terminal_class_init (GbTerminalClass *klass)
                   G_TYPE_BOOLEAN,
                   0);
 
+  signals [SEARCH_REVEAL] =
+    g_signal_new ("search-reveal",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GbTerminalClass, search_reveal),
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE,
+                  0);
+
   signals [OPEN_LINK] =
     g_signal_new ("open-link",
                   G_TYPE_FROM_CLASS (klass),
@@ -296,6 +326,12 @@ gb_terminal_class_init (GbTerminalClass *klass)
                                 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
                                 "paste-clipboard",
                                 0);
+
+  gtk_binding_entry_add_signal (binding_set,
+                                GDK_KEY_f,
+                                GDK_CONTROL_MASK,
+                                "search-reveal",
+                                0);
 }
 
 static void
diff --git a/plugins/terminal/gb-terminal.gresource.xml b/plugins/terminal/gb-terminal.gresource.xml
index ab0134e..215c200 100644
--- a/plugins/terminal/gb-terminal.gresource.xml
+++ b/plugins/terminal/gb-terminal.gresource.xml
@@ -2,6 +2,7 @@
 <gresources>
   <gresource prefix="/org/gnome/builder/plugins/terminal">
     <file>gb-terminal-view.ui</file>
+    <file>gb-terminal-search.ui</file>
     <file>gtk/menus.ui</file>
     <file>theme/shared.css</file>
   </gresource>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]