Port to the GtkSourceView search functionality
This also gives us support for regex search
This commit is contained in:
parent
0a9588ef63
commit
511fc3dfec
|
@ -64,7 +64,6 @@ IGNORE_HFILES= \
|
||||||
# Do not parse them to make the docs.
|
# Do not parse them to make the docs.
|
||||||
IGNORE_HFILES += \
|
IGNORE_HFILES += \
|
||||||
bacon-message-connection.h \
|
bacon-message-connection.h \
|
||||||
xedtextregion.h \
|
|
||||||
sexy-icon-entry.h
|
sexy-icon-entry.h
|
||||||
|
|
||||||
# Images to copy into HTML directory.
|
# Images to copy into HTML directory.
|
||||||
|
|
|
@ -36,7 +36,6 @@ xed_app_activatable_get_type
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>xed-document</FILE>
|
<FILE>xed-document</FILE>
|
||||||
XedSearchFlags
|
|
||||||
XedDocumentPrivate
|
XedDocumentPrivate
|
||||||
<TITLE>XedDocument</TITLE>
|
<TITLE>XedDocument</TITLE>
|
||||||
XedDocument
|
XedDocument
|
||||||
|
@ -58,21 +57,7 @@ xed_document_is_untouched
|
||||||
xed_document_is_untitled
|
xed_document_is_untitled
|
||||||
xed_document_get_deleted
|
xed_document_get_deleted
|
||||||
xed_document_goto_line
|
xed_document_goto_line
|
||||||
xed_document_set_search_text
|
|
||||||
xed_document_get_search_text
|
|
||||||
xed_document_get_can_search_again
|
|
||||||
xed_document_search_forward
|
|
||||||
xed_document_search_backward
|
|
||||||
xed_document_replace_all
|
|
||||||
xed_document_set_language
|
xed_document_set_language
|
||||||
xed_document_set_enable_search_highlighting
|
|
||||||
xed_document_get_enable_search_highlighting
|
|
||||||
XED_SEARCH_IS_DONT_SET_FLAGS
|
|
||||||
XED_SEARCH_SET_DONT_SET_FLAGS
|
|
||||||
XED_SEARCH_IS_ENTIRE_WORD
|
|
||||||
XED_SEARCH_SET_ENTIRE_WORD
|
|
||||||
XED_SEARCH_IS_CASE_SENSITIVE
|
|
||||||
XED_SEARCH_SET_CASE_SENSITIVE
|
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
XED_DOCUMENT
|
XED_DOCUMENT
|
||||||
XED_IS_DOCUMENT
|
XED_IS_DOCUMENT
|
||||||
|
@ -517,8 +502,6 @@ g_utf8_caselessnmatch
|
||||||
xed_utils_set_atk_name_description
|
xed_utils_set_atk_name_description
|
||||||
xed_utils_set_atk_relation
|
xed_utils_set_atk_relation
|
||||||
xed_utils_uri_exists
|
xed_utils_uri_exists
|
||||||
xed_utils_escape_search_text
|
|
||||||
xed_utils_unescape_search_text
|
|
||||||
xed_utils_get_stdin
|
xed_utils_get_stdin
|
||||||
xed_warning
|
xed_warning
|
||||||
xed_utils_make_valid_utf8
|
xed_utils_make_valid_utf8
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <xed/xed-debug.h>
|
#include <xed/xed-debug.h>
|
||||||
#include <xed/xed-statusbar.h>
|
#include <xed/xed-statusbar.h>
|
||||||
#include <xed/xed-utils.h>
|
#include <xed/xed-utils.h>
|
||||||
|
#include <gtksourceview/gtksource.h>
|
||||||
|
|
||||||
#include "xed-spell-checker.h"
|
#include "xed-spell-checker.h"
|
||||||
#include "xed-spell-checker-dialog.h"
|
#include "xed-spell-checker-dialog.h"
|
||||||
|
@ -704,7 +705,8 @@ change_all_cb (XedSpellCheckerDialog *dlg,
|
||||||
CheckRange *range;
|
CheckRange *range;
|
||||||
gchar *w = NULL;
|
gchar *w = NULL;
|
||||||
GtkTextIter start, end;
|
GtkTextIter start, end;
|
||||||
gint flags = 0;
|
GtkSourceSearchSettings *search_settings;
|
||||||
|
GtkSourceSearchContext *search_context;
|
||||||
|
|
||||||
xed_debug (DEBUG_PLUGINS);
|
xed_debug (DEBUG_PLUGINS);
|
||||||
|
|
||||||
|
@ -739,16 +741,24 @@ change_all_cb (XedSpellCheckerDialog *dlg,
|
||||||
|
|
||||||
g_free (w);
|
g_free (w);
|
||||||
|
|
||||||
XED_SEARCH_SET_CASE_SENSITIVE (flags, TRUE);
|
search_settings = gtk_source_search_settings_new ();
|
||||||
XED_SEARCH_SET_ENTIRE_WORD (flags, TRUE);
|
gtk_source_search_settings_set_case_sensitive (search_settings, TRUE);
|
||||||
|
gtk_source_search_settings_set_at_word_boundaries (search_settings, TRUE);
|
||||||
|
gtk_source_search_settings_set_search_text (search_settings, word);
|
||||||
|
|
||||||
/* CHECK: currently this function does escaping etc */
|
search_context = gtk_source_search_context_new (GTK_SOURCE_BUFFER (doc), search_settings);
|
||||||
xed_document_replace_all (doc, word, change, flags);
|
|
||||||
|
gtk_source_search_context_set_highlight (search_context, FALSE);
|
||||||
|
|
||||||
|
gtk_source_search_context_replace_all (search_context, change, -1, NULL);
|
||||||
|
|
||||||
update_current (doc, range->mw_start + g_utf8_strlen (change, -1));
|
update_current (doc, range->mw_start + g_utf8_strlen (change, -1));
|
||||||
|
|
||||||
/* go to next misspelled word */
|
/* go to next misspelled word */
|
||||||
ignore_cb (dlg, word, view);
|
ignore_cb (dlg, word, view);
|
||||||
|
|
||||||
|
g_object_unref (search_settings);
|
||||||
|
g_object_unref (search_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "xed-spell-utils.h"
|
#include "xed-spell-utils.h"
|
||||||
#include <gtksourceview/gtksourcebuffer.h>
|
#include <gtksourceview/gtksource.h>
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
xed_spell_utils_is_digit (const char *text, gssize length)
|
xed_spell_utils_is_digit (const char *text, gssize length)
|
||||||
|
|
|
@ -60,7 +60,6 @@ NOINST_H_FILES = \
|
||||||
xed-settings.h \
|
xed-settings.h \
|
||||||
xed-status-combo-box.h \
|
xed-status-combo-box.h \
|
||||||
xed-tab-label.h \
|
xed-tab-label.h \
|
||||||
xedtextregion.h \
|
|
||||||
xed-ui.h \
|
xed-ui.h \
|
||||||
xed-utils.h \
|
xed-utils.h \
|
||||||
xed-view-frame.h \
|
xed-view-frame.h \
|
||||||
|
@ -146,8 +145,7 @@ libxed_c_files = \
|
||||||
xed-view-activatable.c \
|
xed-view-activatable.c \
|
||||||
xed-view-frame.c \
|
xed-view-frame.c \
|
||||||
xed-window.c \
|
xed-window.c \
|
||||||
xed-window-activatable.c \
|
xed-window-activatable.c
|
||||||
xedtextregion.c
|
|
||||||
|
|
||||||
libxed_la_SOURCES = \
|
libxed_la_SOURCES = \
|
||||||
$(BUILT_SOURCES) \
|
$(BUILT_SOURCES) \
|
||||||
|
|
|
@ -14,18 +14,25 @@
|
||||||
#include "xed-searchbar.h"
|
#include "xed-searchbar.h"
|
||||||
#include "xed-view-frame.h"
|
#include "xed-view-frame.h"
|
||||||
|
|
||||||
|
// void
|
||||||
|
// _xed_cmd_search_find (GtkAction *action,
|
||||||
|
// XedWindow *window)
|
||||||
|
// {
|
||||||
|
// xed_searchbar_show (XED_SEARCHBAR (xed_window_get_searchbar (window)), FALSE);
|
||||||
|
// }
|
||||||
|
|
||||||
void
|
void
|
||||||
_xed_cmd_search_find (GtkAction *action,
|
_xed_cmd_search_find (GtkAction *action,
|
||||||
XedWindow *window)
|
XedWindow *window)
|
||||||
{
|
{
|
||||||
xed_searchbar_show (XED_SEARCHBAR (xed_window_get_searchbar (window)), FALSE);
|
xed_searchbar_show (XED_SEARCHBAR (xed_window_get_searchbar (window)), SEARCH_MODE_SEARCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_xed_cmd_search_replace (GtkAction *action,
|
_xed_cmd_search_replace (GtkAction *action,
|
||||||
XedWindow *window)
|
XedWindow *window)
|
||||||
{
|
{
|
||||||
xed_searchbar_show (XED_SEARCHBAR (xed_window_get_searchbar (window)), TRUE);
|
xed_searchbar_show (XED_SEARCHBAR (xed_window_get_searchbar (window)), SEARCH_MODE_REPLACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -54,7 +61,7 @@ _xed_cmd_search_clear_highlight (XedWindow *window)
|
||||||
doc = xed_window_get_active_document (window);
|
doc = xed_window_get_active_document (window);
|
||||||
if (doc != NULL)
|
if (doc != NULL)
|
||||||
{
|
{
|
||||||
xed_document_set_search_text (XED_DOCUMENT(doc), "", XED_SEARCH_DONT_SET_FLAGS);
|
_xed_document_set_search_context (doc, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
#include "xed-document-saver.h"
|
#include "xed-document-saver.h"
|
||||||
#include "xed-marshal.h"
|
#include "xed-marshal.h"
|
||||||
#include "xed-enum-types.h"
|
#include "xed-enum-types.h"
|
||||||
#include "xedtextregion.h"
|
|
||||||
|
|
||||||
#ifndef ENABLE_GVFS_METADATA
|
#ifndef ENABLE_GVFS_METADATA
|
||||||
#include "xed-metadata-manager.h"
|
#include "xed-metadata-manager.h"
|
||||||
|
@ -86,14 +85,6 @@ static void xed_document_save_real (XedDocument *doc,
|
||||||
GFile *location,
|
GFile *location,
|
||||||
const XedEncoding *encoding,
|
const XedEncoding *encoding,
|
||||||
XedDocumentSaveFlags flags);
|
XedDocumentSaveFlags flags);
|
||||||
static void insert_text_cb (XedDocument *doc,
|
|
||||||
GtkTextIter *pos,
|
|
||||||
const gchar *text,
|
|
||||||
gint length);
|
|
||||||
|
|
||||||
static void delete_range_cb (XedDocument *doc,
|
|
||||||
GtkTextIter *start,
|
|
||||||
GtkTextIter *end);
|
|
||||||
|
|
||||||
struct _XedDocumentPrivate
|
struct _XedDocumentPrivate
|
||||||
{
|
{
|
||||||
|
@ -113,9 +104,7 @@ struct _XedDocumentPrivate
|
||||||
GTimeVal mtime;
|
GTimeVal mtime;
|
||||||
GTimeVal time_of_last_save_or_load;
|
GTimeVal time_of_last_save_or_load;
|
||||||
|
|
||||||
guint search_flags;
|
GtkSourceSearchContext *search_context;
|
||||||
gchar *search_text;
|
|
||||||
gint num_of_lines_search_text;
|
|
||||||
|
|
||||||
XedDocumentNewlineType newline_type;
|
XedDocumentNewlineType newline_type;
|
||||||
|
|
||||||
|
@ -129,10 +118,6 @@ struct _XedDocumentPrivate
|
||||||
/* Saving stuff */
|
/* Saving stuff */
|
||||||
XedDocumentSaver *saver;
|
XedDocumentSaver *saver;
|
||||||
|
|
||||||
/* Search highlighting support variables */
|
|
||||||
XedTextRegion *to_search_region;
|
|
||||||
GtkTextTag *found_tag;
|
|
||||||
|
|
||||||
GtkTextTag *error_tag;
|
GtkTextTag *error_tag;
|
||||||
|
|
||||||
/* Mount operation factory */
|
/* Mount operation factory */
|
||||||
|
@ -158,8 +143,6 @@ enum
|
||||||
PROP_MIME_TYPE,
|
PROP_MIME_TYPE,
|
||||||
PROP_READ_ONLY,
|
PROP_READ_ONLY,
|
||||||
PROP_ENCODING,
|
PROP_ENCODING,
|
||||||
PROP_CAN_SEARCH_AGAIN,
|
|
||||||
PROP_ENABLE_SEARCH_HIGHLIGHTING,
|
|
||||||
PROP_NEWLINE_TYPE
|
PROP_NEWLINE_TYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -172,7 +155,6 @@ enum
|
||||||
SAVE,
|
SAVE,
|
||||||
SAVING,
|
SAVING,
|
||||||
SAVED,
|
SAVED,
|
||||||
SEARCH_HIGHLIGHT_UPDATED,
|
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -284,6 +266,7 @@ xed_document_dispose (GObject *object)
|
||||||
g_clear_object (&doc->priv->editor_settings);
|
g_clear_object (&doc->priv->editor_settings);
|
||||||
g_clear_object (&doc->priv->metadata_info);
|
g_clear_object (&doc->priv->metadata_info);
|
||||||
g_clear_object (&doc->priv->location);
|
g_clear_object (&doc->priv->location);
|
||||||
|
g_clear_object (&doc->priv->search_context);
|
||||||
|
|
||||||
doc->priv->dispose_has_run = TRUE;
|
doc->priv->dispose_has_run = TRUE;
|
||||||
|
|
||||||
|
@ -303,13 +286,6 @@ xed_document_finalize (GObject *object)
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (doc->priv->content_type);
|
g_free (doc->priv->content_type);
|
||||||
g_free (doc->priv->search_text);
|
|
||||||
|
|
||||||
if (doc->priv->to_search_region != NULL)
|
|
||||||
{
|
|
||||||
/* we can't delete marks if we're finalizing the buffer */
|
|
||||||
xed_text_region_destroy (doc->priv->to_search_region, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (xed_document_parent_class)->finalize (object);
|
G_OBJECT_CLASS (xed_document_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -342,12 +318,6 @@ xed_document_get_property (GObject *object,
|
||||||
case PROP_ENCODING:
|
case PROP_ENCODING:
|
||||||
g_value_set_boxed (value, doc->priv->encoding);
|
g_value_set_boxed (value, doc->priv->encoding);
|
||||||
break;
|
break;
|
||||||
case PROP_CAN_SEARCH_AGAIN:
|
|
||||||
g_value_set_boolean (value, xed_document_get_can_search_again (doc));
|
|
||||||
break;
|
|
||||||
case PROP_ENABLE_SEARCH_HIGHLIGHTING:
|
|
||||||
g_value_set_boolean (value, xed_document_get_enable_search_highlighting (doc));
|
|
||||||
break;
|
|
||||||
case PROP_NEWLINE_TYPE:
|
case PROP_NEWLINE_TYPE:
|
||||||
g_value_set_enum (value, doc->priv->newline_type);
|
g_value_set_enum (value, doc->priv->newline_type);
|
||||||
break;
|
break;
|
||||||
|
@ -386,9 +356,6 @@ xed_document_set_property (GObject *object,
|
||||||
case PROP_CONTENT_TYPE:
|
case PROP_CONTENT_TYPE:
|
||||||
xed_document_set_content_type (doc, g_value_get_string (value));
|
xed_document_set_content_type (doc, g_value_get_string (value));
|
||||||
break;
|
break;
|
||||||
case PROP_ENABLE_SEARCH_HIGHLIGHTING:
|
|
||||||
xed_document_set_enable_search_highlighting (doc, g_value_get_boolean (value));
|
|
||||||
break;
|
|
||||||
case PROP_NEWLINE_TYPE:
|
case PROP_NEWLINE_TYPE:
|
||||||
xed_document_set_newline_type (doc, g_value_get_enum (value));
|
xed_document_set_newline_type (doc, g_value_get_enum (value));
|
||||||
break;
|
break;
|
||||||
|
@ -498,22 +465,6 @@ xed_document_class_init (XedDocumentClass *klass)
|
||||||
G_PARAM_READABLE |
|
G_PARAM_READABLE |
|
||||||
G_PARAM_STATIC_STRINGS));
|
G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_CAN_SEARCH_AGAIN,
|
|
||||||
g_param_spec_boolean ("can-search-again",
|
|
||||||
"Can search again",
|
|
||||||
"Whether it's possible to search again in the document",
|
|
||||||
FALSE,
|
|
||||||
G_PARAM_READABLE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_ENABLE_SEARCH_HIGHLIGHTING,
|
|
||||||
g_param_spec_boolean ("enable-search-highlighting",
|
|
||||||
"Enable Search Highlighting",
|
|
||||||
"Whether all the occurrences of the searched string must be highlighted",
|
|
||||||
FALSE,
|
|
||||||
G_PARAM_READWRITE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XedDocument:newline-type:
|
* XedDocument:newline-type:
|
||||||
*
|
*
|
||||||
|
@ -643,18 +594,6 @@ xed_document_class_init (XedDocumentClass *klass)
|
||||||
1,
|
1,
|
||||||
G_TYPE_POINTER);
|
G_TYPE_POINTER);
|
||||||
|
|
||||||
document_signals[SEARCH_HIGHLIGHT_UPDATED] =
|
|
||||||
g_signal_new ("search-highlight-updated",
|
|
||||||
G_OBJECT_CLASS_TYPE (object_class),
|
|
||||||
G_SIGNAL_RUN_LAST,
|
|
||||||
G_STRUCT_OFFSET (XedDocumentClass, search_highlight_updated),
|
|
||||||
NULL, NULL,
|
|
||||||
xed_marshal_VOID__BOXED_BOXED,
|
|
||||||
G_TYPE_NONE,
|
|
||||||
2,
|
|
||||||
GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
|
|
||||||
GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
||||||
|
|
||||||
g_type_class_add_private (object_class, sizeof (XedDocumentPrivate));
|
g_type_class_add_private (object_class, sizeof (XedDocumentPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -925,20 +864,12 @@ xed_document_init (XedDocument *doc)
|
||||||
"highlight-matching-brackets",
|
"highlight-matching-brackets",
|
||||||
G_SETTINGS_BIND_GET);
|
G_SETTINGS_BIND_GET);
|
||||||
|
|
||||||
g_settings_bind (priv->editor_settings,
|
|
||||||
XED_SETTINGS_SEARCH_HIGHLIGHTING,
|
|
||||||
doc,
|
|
||||||
"enable-search-highlighting",
|
|
||||||
G_SETTINGS_BIND_GET);
|
|
||||||
|
|
||||||
style_scheme = get_default_style_scheme (priv->editor_settings);
|
style_scheme = get_default_style_scheme (priv->editor_settings);
|
||||||
if (style_scheme != NULL)
|
if (style_scheme != NULL)
|
||||||
{
|
{
|
||||||
gtk_source_buffer_set_style_scheme (GTK_SOURCE_BUFFER (doc), style_scheme);
|
gtk_source_buffer_set_style_scheme (GTK_SOURCE_BUFFER (doc), style_scheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_signal_connect_after (doc, "insert-text", G_CALLBACK (insert_text_cb), NULL);
|
|
||||||
g_signal_connect_after (doc, "delete-range", G_CALLBACK (delete_range_cb), NULL);
|
|
||||||
g_signal_connect (doc, "notify::content-type", G_CALLBACK (on_content_type_changed), NULL);
|
g_signal_connect (doc, "notify::content-type", G_CALLBACK (on_content_type_changed), NULL);
|
||||||
g_signal_connect (doc, "notify::location", G_CALLBACK (on_location_changed), NULL);
|
g_signal_connect (doc, "notify::location", G_CALLBACK (on_location_changed), NULL);
|
||||||
}
|
}
|
||||||
|
@ -1807,448 +1738,6 @@ xed_document_goto_line_offset (XedDocument *doc,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
|
||||||
compute_num_of_lines (const gchar *text)
|
|
||||||
{
|
|
||||||
const gchar *p;
|
|
||||||
gint len;
|
|
||||||
gint n = 1;
|
|
||||||
|
|
||||||
g_return_val_if_fail (text != NULL, 0);
|
|
||||||
|
|
||||||
len = strlen (text);
|
|
||||||
p = text;
|
|
||||||
|
|
||||||
while (len > 0)
|
|
||||||
{
|
|
||||||
gint del, par;
|
|
||||||
|
|
||||||
pango_find_paragraph_boundary (p, len, &del, &par);
|
|
||||||
|
|
||||||
if (del == par) /* not found */
|
|
||||||
break;
|
|
||||||
|
|
||||||
p += par;
|
|
||||||
len -= par;
|
|
||||||
++n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
to_search_region_range (XedDocument *doc,
|
|
||||||
GtkTextIter *start,
|
|
||||||
GtkTextIter *end)
|
|
||||||
{
|
|
||||||
xed_debug (DEBUG_DOCUMENT);
|
|
||||||
|
|
||||||
if (doc->priv->to_search_region == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_text_iter_set_line_offset (start, 0);
|
|
||||||
gtk_text_iter_forward_to_line_end (end);
|
|
||||||
|
|
||||||
/*
|
|
||||||
g_print ("+ [%u (%u), %u (%u)]\n", gtk_text_iter_get_line (start), gtk_text_iter_get_offset (start),
|
|
||||||
gtk_text_iter_get_line (end), gtk_text_iter_get_offset (end));
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Add the region to the refresh region */
|
|
||||||
xed_text_region_add (doc->priv->to_search_region, start, end);
|
|
||||||
|
|
||||||
/* Notify views of the updated highlight region */
|
|
||||||
gtk_text_iter_backward_lines (start, doc->priv->num_of_lines_search_text);
|
|
||||||
gtk_text_iter_forward_lines (end, doc->priv->num_of_lines_search_text);
|
|
||||||
|
|
||||||
g_signal_emit (doc, document_signals [SEARCH_HIGHLIGHT_UPDATED], 0, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* xed_document_set_search_text:
|
|
||||||
* @doc:
|
|
||||||
* @text: (allow-none):
|
|
||||||
* @flags:
|
|
||||||
**/
|
|
||||||
void
|
|
||||||
xed_document_set_search_text (XedDocument *doc,
|
|
||||||
const gchar *text,
|
|
||||||
guint flags)
|
|
||||||
{
|
|
||||||
gchar *converted_text;
|
|
||||||
gboolean notify = FALSE;
|
|
||||||
gboolean update_to_search_region = FALSE;
|
|
||||||
|
|
||||||
g_return_if_fail (XED_IS_DOCUMENT (doc));
|
|
||||||
g_return_if_fail ((text == NULL) || (doc->priv->search_text != text));
|
|
||||||
g_return_if_fail ((text == NULL) || g_utf8_validate (text, -1, NULL));
|
|
||||||
|
|
||||||
xed_debug_message (DEBUG_DOCUMENT, "text = %s", text);
|
|
||||||
|
|
||||||
if (text != NULL)
|
|
||||||
{
|
|
||||||
if (*text != '\0')
|
|
||||||
{
|
|
||||||
converted_text = xed_utils_unescape_search_text (text);
|
|
||||||
notify = !xed_document_get_can_search_again (doc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
converted_text = g_strdup("");
|
|
||||||
notify = xed_document_get_can_search_again (doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (doc->priv->search_text);
|
|
||||||
|
|
||||||
doc->priv->search_text = converted_text;
|
|
||||||
doc->priv->num_of_lines_search_text = compute_num_of_lines (doc->priv->search_text);
|
|
||||||
update_to_search_region = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!XED_SEARCH_IS_DONT_SET_FLAGS (flags))
|
|
||||||
{
|
|
||||||
if (doc->priv->search_flags != flags)
|
|
||||||
{
|
|
||||||
update_to_search_region = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
doc->priv->search_flags = flags;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (update_to_search_region)
|
|
||||||
{
|
|
||||||
GtkTextIter begin;
|
|
||||||
GtkTextIter end;
|
|
||||||
|
|
||||||
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), &begin, &end);
|
|
||||||
to_search_region_range (doc, &begin, &end);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notify)
|
|
||||||
{
|
|
||||||
g_object_notify (G_OBJECT (doc), "can-search-again");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* xed_document_get_search_text:
|
|
||||||
* @doc:
|
|
||||||
* @flags: (allow-none):
|
|
||||||
*/
|
|
||||||
gchar *
|
|
||||||
xed_document_get_search_text (XedDocument *doc,
|
|
||||||
guint *flags)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
|
|
||||||
|
|
||||||
if (flags != NULL)
|
|
||||||
{
|
|
||||||
*flags = doc->priv->search_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
return xed_utils_escape_search_text (doc->priv->search_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
xed_document_get_can_search_again (XedDocument *doc)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE);
|
|
||||||
|
|
||||||
return ((doc->priv->search_text != NULL) && (*doc->priv->search_text != '\0'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* xed_document_search_forward:
|
|
||||||
* @doc:
|
|
||||||
* @start: (allow-none):
|
|
||||||
* @end: (allow-none):
|
|
||||||
* @match_start: (allow-none):
|
|
||||||
* @match_end: (allow-none):
|
|
||||||
**/
|
|
||||||
gboolean
|
|
||||||
xed_document_search_forward (XedDocument *doc,
|
|
||||||
const GtkTextIter *start,
|
|
||||||
const GtkTextIter *end,
|
|
||||||
GtkTextIter *match_start,
|
|
||||||
GtkTextIter *match_end)
|
|
||||||
{
|
|
||||||
GtkTextIter iter;
|
|
||||||
GtkTextSearchFlags search_flags;
|
|
||||||
gboolean found = FALSE;
|
|
||||||
GtkTextIter m_start;
|
|
||||||
GtkTextIter m_end;
|
|
||||||
|
|
||||||
g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE);
|
|
||||||
g_return_val_if_fail ((start == NULL) || (gtk_text_iter_get_buffer (start) == GTK_TEXT_BUFFER (doc)), FALSE);
|
|
||||||
g_return_val_if_fail ((end == NULL) || (gtk_text_iter_get_buffer (end) == GTK_TEXT_BUFFER (doc)), FALSE);
|
|
||||||
|
|
||||||
if (doc->priv->search_text == NULL)
|
|
||||||
{
|
|
||||||
xed_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == NULL\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xed_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == \"%s\"\n", doc->priv->search_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start == NULL)
|
|
||||||
{
|
|
||||||
gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (doc), &iter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iter = *start;
|
|
||||||
}
|
|
||||||
|
|
||||||
search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
|
|
||||||
|
|
||||||
if (!XED_SEARCH_IS_CASE_SENSITIVE (doc->priv->search_flags))
|
|
||||||
{
|
|
||||||
search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!found)
|
|
||||||
{
|
|
||||||
found = gtk_text_iter_forward_search (&iter,
|
|
||||||
doc->priv->search_text,
|
|
||||||
search_flags,
|
|
||||||
&m_start,
|
|
||||||
&m_end,
|
|
||||||
end);
|
|
||||||
|
|
||||||
if (found && XED_SEARCH_IS_ENTIRE_WORD (doc->priv->search_flags))
|
|
||||||
{
|
|
||||||
found = gtk_text_iter_starts_word (&m_start) && gtk_text_iter_ends_word (&m_end);
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
iter = m_end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found && (match_start != NULL))
|
|
||||||
{
|
|
||||||
*match_start = m_start;
|
|
||||||
}
|
|
||||||
if (found && (match_end != NULL))
|
|
||||||
{
|
|
||||||
*match_end = m_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* xed_document_search_backward:
|
|
||||||
* @doc:
|
|
||||||
* @start: (allow-none):
|
|
||||||
* @end: (allow-none):
|
|
||||||
* @match_start: (allow-none):
|
|
||||||
* @match_end: (allow-none):
|
|
||||||
**/
|
|
||||||
gboolean
|
|
||||||
xed_document_search_backward (XedDocument *doc,
|
|
||||||
const GtkTextIter *start,
|
|
||||||
const GtkTextIter *end,
|
|
||||||
GtkTextIter *match_start,
|
|
||||||
GtkTextIter *match_end)
|
|
||||||
{
|
|
||||||
GtkTextIter iter;
|
|
||||||
GtkTextSearchFlags search_flags;
|
|
||||||
gboolean found = FALSE;
|
|
||||||
GtkTextIter m_start;
|
|
||||||
GtkTextIter m_end;
|
|
||||||
|
|
||||||
g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE);
|
|
||||||
g_return_val_if_fail ((start == NULL) || (gtk_text_iter_get_buffer (start) == GTK_TEXT_BUFFER (doc)), FALSE);
|
|
||||||
g_return_val_if_fail ((end == NULL) || (gtk_text_iter_get_buffer (end) == GTK_TEXT_BUFFER (doc)), FALSE);
|
|
||||||
|
|
||||||
if (doc->priv->search_text == NULL)
|
|
||||||
{
|
|
||||||
xed_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == NULL\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xed_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == \"%s\"\n", doc->priv->search_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end == NULL)
|
|
||||||
{
|
|
||||||
gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &iter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iter = *end;
|
|
||||||
}
|
|
||||||
|
|
||||||
search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
|
|
||||||
|
|
||||||
if (!XED_SEARCH_IS_CASE_SENSITIVE (doc->priv->search_flags))
|
|
||||||
{
|
|
||||||
search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!found)
|
|
||||||
{
|
|
||||||
found = gtk_text_iter_backward_search (&iter,
|
|
||||||
doc->priv->search_text,
|
|
||||||
search_flags,
|
|
||||||
&m_start,
|
|
||||||
&m_end,
|
|
||||||
start);
|
|
||||||
|
|
||||||
if (found && XED_SEARCH_IS_ENTIRE_WORD (doc->priv->search_flags))
|
|
||||||
{
|
|
||||||
found = gtk_text_iter_starts_word (&m_start) && gtk_text_iter_ends_word (&m_end);
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
iter = m_start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found && (match_start != NULL))
|
|
||||||
{
|
|
||||||
*match_start = m_start;
|
|
||||||
}
|
|
||||||
if (found && (match_end != NULL))
|
|
||||||
{
|
|
||||||
*match_end = m_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME this is an issue for introspection regardning @find */
|
|
||||||
gint
|
|
||||||
xed_document_replace_all (XedDocument *doc,
|
|
||||||
const gchar *find,
|
|
||||||
const gchar *replace,
|
|
||||||
guint flags)
|
|
||||||
{
|
|
||||||
GtkTextIter iter;
|
|
||||||
GtkTextIter m_start;
|
|
||||||
GtkTextIter m_end;
|
|
||||||
GtkTextSearchFlags search_flags = 0;
|
|
||||||
gboolean found = TRUE;
|
|
||||||
gint cont = 0;
|
|
||||||
gchar *search_text;
|
|
||||||
gchar *replace_text;
|
|
||||||
gint replace_text_len;
|
|
||||||
GtkTextBuffer *buffer;
|
|
||||||
gboolean brackets_highlighting;
|
|
||||||
gboolean search_highliting;
|
|
||||||
|
|
||||||
g_return_val_if_fail (XED_IS_DOCUMENT (doc), 0);
|
|
||||||
g_return_val_if_fail (replace != NULL, 0);
|
|
||||||
g_return_val_if_fail ((find != NULL) || (doc->priv->search_text != NULL), 0);
|
|
||||||
|
|
||||||
buffer = GTK_TEXT_BUFFER (doc);
|
|
||||||
|
|
||||||
if (find == NULL)
|
|
||||||
{
|
|
||||||
search_text = g_strdup (doc->priv->search_text);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
search_text = xed_utils_unescape_search_text (find);
|
|
||||||
}
|
|
||||||
|
|
||||||
replace_text = xed_utils_unescape_search_text (replace);
|
|
||||||
|
|
||||||
gtk_text_buffer_get_start_iter (buffer, &iter);
|
|
||||||
|
|
||||||
search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
|
|
||||||
|
|
||||||
if (!XED_SEARCH_IS_CASE_SENSITIVE (flags))
|
|
||||||
{
|
|
||||||
search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
replace_text_len = strlen (replace_text);
|
|
||||||
|
|
||||||
/* disable cursor_moved emission until the end of the
|
|
||||||
* replace_all so that we don't spend all the time
|
|
||||||
* updating the position in the statusbar
|
|
||||||
*/
|
|
||||||
doc->priv->stop_cursor_moved_emission = TRUE;
|
|
||||||
|
|
||||||
/* also avoid spending time matching brackets */
|
|
||||||
brackets_highlighting = gtk_source_buffer_get_highlight_matching_brackets (GTK_SOURCE_BUFFER (buffer));
|
|
||||||
gtk_source_buffer_set_highlight_matching_brackets (GTK_SOURCE_BUFFER (buffer), FALSE);
|
|
||||||
|
|
||||||
/* and do search highliting later */
|
|
||||||
search_highliting = xed_document_get_enable_search_highlighting (doc);
|
|
||||||
xed_document_set_enable_search_highlighting (doc, FALSE);
|
|
||||||
|
|
||||||
gtk_text_buffer_begin_user_action (buffer);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
found = gtk_text_iter_forward_search (&iter,
|
|
||||||
search_text,
|
|
||||||
search_flags,
|
|
||||||
&m_start,
|
|
||||||
&m_end,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (found && XED_SEARCH_IS_ENTIRE_WORD (flags))
|
|
||||||
{
|
|
||||||
gboolean word;
|
|
||||||
|
|
||||||
word = gtk_text_iter_starts_word (&m_start) && gtk_text_iter_ends_word (&m_end);
|
|
||||||
|
|
||||||
if (!word)
|
|
||||||
{
|
|
||||||
iter = m_end;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
++cont;
|
|
||||||
|
|
||||||
gtk_text_buffer_delete (buffer, &m_start, &m_end);
|
|
||||||
gtk_text_buffer_insert (buffer, &m_start, replace_text, replace_text_len);
|
|
||||||
|
|
||||||
iter = m_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (found);
|
|
||||||
|
|
||||||
gtk_text_buffer_end_user_action (buffer);
|
|
||||||
|
|
||||||
/* re-enable cursor_moved emission and notify
|
|
||||||
* the current position
|
|
||||||
*/
|
|
||||||
doc->priv->stop_cursor_moved_emission = FALSE;
|
|
||||||
emit_cursor_moved (doc);
|
|
||||||
|
|
||||||
gtk_source_buffer_set_highlight_matching_brackets (GTK_SOURCE_BUFFER (buffer), brackets_highlighting);
|
|
||||||
xed_document_set_enable_search_highlighting (doc, search_highliting);
|
|
||||||
|
|
||||||
g_free (search_text);
|
|
||||||
g_free (replace_text);
|
|
||||||
|
|
||||||
return cont;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_style_colors (XedDocument *doc,
|
get_style_colors (XedDocument *doc,
|
||||||
const gchar *style_name,
|
const gchar *style_name,
|
||||||
|
@ -2393,14 +1882,6 @@ sync_tag_style (XedDocument *doc,
|
||||||
g_object_thaw_notify (G_OBJECT (tag));
|
g_object_thaw_notify (G_OBJECT (tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
sync_found_tag (XedDocument *doc,
|
|
||||||
GParamSpec *pspec,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
sync_tag_style (doc, doc->priv->found_tag, "search-match");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
text_tag_set_highest_priority (GtkTextTag *tag,
|
text_tag_set_highest_priority (GtkTextTag *tag,
|
||||||
GtkTextBuffer *buffer)
|
GtkTextBuffer *buffer)
|
||||||
|
@ -2413,200 +1894,6 @@ text_tag_set_highest_priority (GtkTextTag *tag,
|
||||||
gtk_text_tag_set_priority (tag, n - 1);
|
gtk_text_tag_set_priority (tag, n - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
search_region (XedDocument *doc,
|
|
||||||
GtkTextIter *start,
|
|
||||||
GtkTextIter *end)
|
|
||||||
{
|
|
||||||
GtkTextIter iter;
|
|
||||||
GtkTextIter m_start;
|
|
||||||
GtkTextIter m_end;
|
|
||||||
GtkTextSearchFlags search_flags = 0;
|
|
||||||
gboolean found = TRUE;
|
|
||||||
|
|
||||||
GtkTextBuffer *buffer;
|
|
||||||
|
|
||||||
xed_debug (DEBUG_DOCUMENT);
|
|
||||||
|
|
||||||
buffer = GTK_TEXT_BUFFER (doc);
|
|
||||||
|
|
||||||
if (doc->priv->found_tag == NULL)
|
|
||||||
{
|
|
||||||
doc->priv->found_tag = gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (doc), "found", NULL);
|
|
||||||
|
|
||||||
sync_found_tag (doc, NULL, NULL);
|
|
||||||
|
|
||||||
g_signal_connect (doc, "notify::style-scheme", G_CALLBACK (sync_found_tag), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure the 'found' tag has the priority over
|
|
||||||
* syntax highlighting tags */
|
|
||||||
text_tag_set_highest_priority (doc->priv->found_tag, GTK_TEXT_BUFFER (doc));
|
|
||||||
|
|
||||||
|
|
||||||
if (doc->priv->search_text == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_return_if_fail (doc->priv->num_of_lines_search_text > 0);
|
|
||||||
|
|
||||||
gtk_text_iter_backward_lines (start, doc->priv->num_of_lines_search_text);
|
|
||||||
gtk_text_iter_forward_lines (end, doc->priv->num_of_lines_search_text);
|
|
||||||
|
|
||||||
if (gtk_text_iter_has_tag (start, doc->priv->found_tag) &&
|
|
||||||
!gtk_text_iter_begins_tag (start, doc->priv->found_tag))
|
|
||||||
{
|
|
||||||
gtk_text_iter_backward_to_tag_toggle (start, doc->priv->found_tag);
|
|
||||||
}
|
|
||||||
if (gtk_text_iter_has_tag (end, doc->priv->found_tag) &&
|
|
||||||
!gtk_text_iter_ends_tag (end, doc->priv->found_tag))
|
|
||||||
{
|
|
||||||
gtk_text_iter_forward_to_tag_toggle (end, doc->priv->found_tag);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
g_print ("[%u (%u), %u (%u)]\n", gtk_text_iter_get_line (start), gtk_text_iter_get_offset (start),
|
|
||||||
gtk_text_iter_get_line (end), gtk_text_iter_get_offset (end));
|
|
||||||
*/
|
|
||||||
|
|
||||||
gtk_text_buffer_remove_tag (buffer, doc->priv->found_tag, start, end);
|
|
||||||
|
|
||||||
if (*doc->priv->search_text == '\0')
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
iter = *start;
|
|
||||||
|
|
||||||
search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
|
|
||||||
|
|
||||||
if (!XED_SEARCH_IS_CASE_SENSITIVE (doc->priv->search_flags))
|
|
||||||
{
|
|
||||||
search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if ((end != NULL) && gtk_text_iter_is_end (end))
|
|
||||||
{
|
|
||||||
end = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = gtk_text_iter_forward_search (&iter,
|
|
||||||
doc->priv->search_text,
|
|
||||||
search_flags,
|
|
||||||
&m_start,
|
|
||||||
&m_end,
|
|
||||||
end);
|
|
||||||
|
|
||||||
iter = m_end;
|
|
||||||
|
|
||||||
if (found && XED_SEARCH_IS_ENTIRE_WORD (doc->priv->search_flags))
|
|
||||||
{
|
|
||||||
gboolean word;
|
|
||||||
|
|
||||||
word = gtk_text_iter_starts_word (&m_start) && gtk_text_iter_ends_word (&m_end);
|
|
||||||
|
|
||||||
if (!word)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
gtk_text_buffer_apply_tag (buffer, doc->priv->found_tag, &m_start, &m_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (found);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_xed_document_search_region (XedDocument *doc,
|
|
||||||
const GtkTextIter *start,
|
|
||||||
const GtkTextIter *end)
|
|
||||||
{
|
|
||||||
XedTextRegion *region;
|
|
||||||
|
|
||||||
xed_debug (DEBUG_DOCUMENT);
|
|
||||||
|
|
||||||
g_return_if_fail (XED_IS_DOCUMENT (doc));
|
|
||||||
g_return_if_fail (start != NULL);
|
|
||||||
g_return_if_fail (end != NULL);
|
|
||||||
|
|
||||||
if (doc->priv->to_search_region == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
g_print ("U [%u (%u), %u (%u)]\n", gtk_text_iter_get_line (start), gtk_text_iter_get_offset (start),
|
|
||||||
gtk_text_iter_get_line (end), gtk_text_iter_get_offset (end));
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* get the subregions not yet highlighted */
|
|
||||||
region = xed_text_region_intersect (doc->priv->to_search_region, start, end);
|
|
||||||
if (region)
|
|
||||||
{
|
|
||||||
gint i;
|
|
||||||
GtkTextIter start_search;
|
|
||||||
GtkTextIter end_search;
|
|
||||||
|
|
||||||
i = xed_text_region_subregions (region);
|
|
||||||
xed_text_region_nth_subregion (region, 0, &start_search, NULL);
|
|
||||||
xed_text_region_nth_subregion (region, i - 1, NULL, &end_search);
|
|
||||||
|
|
||||||
xed_text_region_destroy (region, TRUE);
|
|
||||||
|
|
||||||
gtk_text_iter_order (&start_search, &end_search);
|
|
||||||
|
|
||||||
search_region (doc, &start_search, &end_search);
|
|
||||||
|
|
||||||
/* remove the just highlighted region */
|
|
||||||
xed_text_region_subtract (doc->priv->to_search_region, start, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
insert_text_cb (XedDocument *doc,
|
|
||||||
GtkTextIter *pos,
|
|
||||||
const gchar *text,
|
|
||||||
gint length)
|
|
||||||
{
|
|
||||||
GtkTextIter start;
|
|
||||||
GtkTextIter end;
|
|
||||||
|
|
||||||
xed_debug (DEBUG_DOCUMENT);
|
|
||||||
|
|
||||||
start = end = *pos;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pos is invalidated when
|
|
||||||
* insertion occurs (because the buffer contents change), but the
|
|
||||||
* default signal handler revalidates it to point to the end of the
|
|
||||||
* inserted text
|
|
||||||
*/
|
|
||||||
gtk_text_iter_backward_chars (&start, g_utf8_strlen (text, length));
|
|
||||||
|
|
||||||
to_search_region_range (doc, &start, &end);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
delete_range_cb (XedDocument *doc,
|
|
||||||
GtkTextIter *start,
|
|
||||||
GtkTextIter *end)
|
|
||||||
{
|
|
||||||
GtkTextIter d_start;
|
|
||||||
GtkTextIter d_end;
|
|
||||||
|
|
||||||
xed_debug (DEBUG_DOCUMENT);
|
|
||||||
|
|
||||||
d_start = *start;
|
|
||||||
d_end = *end;
|
|
||||||
|
|
||||||
to_search_region_range (doc, &d_start, &d_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xed_document_set_language:
|
* xed_document_set_language:
|
||||||
* @doc:
|
* @doc:
|
||||||
|
@ -2657,58 +1944,6 @@ _xed_document_get_seconds_since_last_save_or_load (XedDocument *doc)
|
||||||
return (current_time.tv_sec - doc->priv->time_of_last_save_or_load.tv_sec);
|
return (current_time.tv_sec - doc->priv->time_of_last_save_or_load.tv_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
xed_document_set_enable_search_highlighting (XedDocument *doc,
|
|
||||||
gboolean enable)
|
|
||||||
{
|
|
||||||
g_return_if_fail (XED_IS_DOCUMENT (doc));
|
|
||||||
|
|
||||||
enable = enable != FALSE;
|
|
||||||
|
|
||||||
if ((doc->priv->to_search_region != NULL) == enable)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doc->priv->to_search_region != NULL)
|
|
||||||
{
|
|
||||||
/* Disable search highlighting */
|
|
||||||
if (doc->priv->found_tag != NULL)
|
|
||||||
{
|
|
||||||
/* If needed remove the found_tag */
|
|
||||||
GtkTextIter begin;
|
|
||||||
GtkTextIter end;
|
|
||||||
|
|
||||||
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), &begin, &end);
|
|
||||||
gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (doc), doc->priv->found_tag, &begin, &end);
|
|
||||||
}
|
|
||||||
|
|
||||||
xed_text_region_destroy (doc->priv->to_search_region, TRUE);
|
|
||||||
doc->priv->to_search_region = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
doc->priv->to_search_region = xed_text_region_new (GTK_TEXT_BUFFER (doc));
|
|
||||||
if (xed_document_get_can_search_again (doc))
|
|
||||||
{
|
|
||||||
/* If search_text is not empty, highligth all its occurrences */
|
|
||||||
GtkTextIter begin;
|
|
||||||
GtkTextIter end;
|
|
||||||
|
|
||||||
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), &begin, &end);
|
|
||||||
to_search_region_range (doc, &begin, &end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
xed_document_get_enable_search_highlighting (XedDocument *doc)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE);
|
|
||||||
|
|
||||||
return (doc->priv->to_search_region != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
xed_document_set_newline_type (XedDocument *doc,
|
xed_document_set_newline_type (XedDocument *doc,
|
||||||
XedDocumentNewlineType newline_type)
|
XedDocumentNewlineType newline_type)
|
||||||
|
@ -2946,3 +2181,30 @@ _xed_document_apply_error_style (XedDocument *doc,
|
||||||
|
|
||||||
gtk_text_buffer_apply_tag (buffer, doc->priv->error_tag, start, end);
|
gtk_text_buffer_apply_tag (buffer, doc->priv->error_tag, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_xed_document_set_search_context (XedDocument *doc,
|
||||||
|
GtkSourceSearchContext *search_context)
|
||||||
|
{
|
||||||
|
g_return_if_fail (XED_IS_DOCUMENT (doc));
|
||||||
|
|
||||||
|
g_clear_object (&doc->priv->search_context);
|
||||||
|
doc->priv->search_context = search_context;
|
||||||
|
|
||||||
|
if (search_context != NULL)
|
||||||
|
{
|
||||||
|
gboolean highlight = g_settings_get_boolean (doc->priv->editor_settings, XED_SETTINGS_SEARCH_HIGHLIGHTING);
|
||||||
|
|
||||||
|
gtk_source_search_context_set_highlight (search_context, highlight);
|
||||||
|
|
||||||
|
g_object_ref (search_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkSourceSearchContext *
|
||||||
|
_xed_document_get_search_context (XedDocument *doc)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
|
||||||
|
|
||||||
|
return doc->priv->search_context;
|
||||||
|
}
|
||||||
|
|
|
@ -64,15 +64,6 @@ typedef enum
|
||||||
|
|
||||||
#define XED_DOCUMENT_NEWLINE_TYPE_DEFAULT XED_DOCUMENT_NEWLINE_TYPE_LF
|
#define XED_DOCUMENT_NEWLINE_TYPE_DEFAULT XED_DOCUMENT_NEWLINE_TYPE_LF
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
XED_SEARCH_DONT_SET_FLAGS = 1 << 0,
|
|
||||||
XED_SEARCH_ENTIRE_WORD = 1 << 1,
|
|
||||||
XED_SEARCH_CASE_SENSITIVE = 1 << 2,
|
|
||||||
XED_SEARCH_PARSE_ESCAPES = 1 << 3
|
|
||||||
|
|
||||||
} XedSearchFlags;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XedDocumentSaveFlags:
|
* XedDocumentSaveFlags:
|
||||||
* @XED_DOCUMENT_SAVE_IGNORE_MTIME: save file despite external modifications.
|
* @XED_DOCUMENT_SAVE_IGNORE_MTIME: save file despite external modifications.
|
||||||
|
@ -142,11 +133,6 @@ struct _XedDocumentClass
|
||||||
|
|
||||||
void (* saved) (XedDocument *document,
|
void (* saved) (XedDocument *document,
|
||||||
const GError *error);
|
const GError *error);
|
||||||
|
|
||||||
void (* search_highlight_updated)
|
|
||||||
(XedDocument *document,
|
|
||||||
GtkTextIter *start,
|
|
||||||
GtkTextIter *end);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -223,33 +209,6 @@ gboolean xed_document_goto_line_offset(XedDocument *doc,
|
||||||
gint line,
|
gint line,
|
||||||
gint line_offset);
|
gint line_offset);
|
||||||
|
|
||||||
void xed_document_set_search_text (XedDocument *doc,
|
|
||||||
const gchar *text,
|
|
||||||
guint flags);
|
|
||||||
|
|
||||||
gchar *xed_document_get_search_text (XedDocument *doc,
|
|
||||||
guint *flags);
|
|
||||||
|
|
||||||
gboolean xed_document_get_can_search_again
|
|
||||||
(XedDocument *doc);
|
|
||||||
|
|
||||||
gboolean xed_document_search_forward (XedDocument *doc,
|
|
||||||
const GtkTextIter *start,
|
|
||||||
const GtkTextIter *end,
|
|
||||||
GtkTextIter *match_start,
|
|
||||||
GtkTextIter *match_end);
|
|
||||||
|
|
||||||
gboolean xed_document_search_backward (XedDocument *doc,
|
|
||||||
const GtkTextIter *start,
|
|
||||||
const GtkTextIter *end,
|
|
||||||
GtkTextIter *match_start,
|
|
||||||
GtkTextIter *match_end);
|
|
||||||
|
|
||||||
gint xed_document_replace_all (XedDocument *doc,
|
|
||||||
const gchar *find,
|
|
||||||
const gchar *replace,
|
|
||||||
guint flags);
|
|
||||||
|
|
||||||
void xed_document_set_language (XedDocument *doc,
|
void xed_document_set_language (XedDocument *doc,
|
||||||
GtkSourceLanguage *lang);
|
GtkSourceLanguage *lang);
|
||||||
GtkSourceLanguage
|
GtkSourceLanguage
|
||||||
|
@ -258,13 +217,6 @@ GtkSourceLanguage
|
||||||
const XedEncoding
|
const XedEncoding
|
||||||
*xed_document_get_encoding (XedDocument *doc);
|
*xed_document_get_encoding (XedDocument *doc);
|
||||||
|
|
||||||
void xed_document_set_enable_search_highlighting
|
|
||||||
(XedDocument *doc,
|
|
||||||
gboolean enable);
|
|
||||||
|
|
||||||
gboolean xed_document_get_enable_search_highlighting
|
|
||||||
(XedDocument *doc);
|
|
||||||
|
|
||||||
void xed_document_set_newline_type (XedDocument *doc,
|
void xed_document_set_newline_type (XedDocument *doc,
|
||||||
XedDocumentNewlineType newline_type);
|
XedDocumentNewlineType newline_type);
|
||||||
|
|
||||||
|
@ -299,27 +251,6 @@ void _xed_document_apply_error_style (XedDocument *doc,
|
||||||
gboolean _xed_document_check_externally_modified
|
gboolean _xed_document_check_externally_modified
|
||||||
(XedDocument *doc);
|
(XedDocument *doc);
|
||||||
|
|
||||||
void _xed_document_search_region (XedDocument *doc,
|
|
||||||
const GtkTextIter *start,
|
|
||||||
const GtkTextIter *end);
|
|
||||||
|
|
||||||
/* Search macros */
|
|
||||||
#define XED_SEARCH_IS_DONT_SET_FLAGS(sflags) ((sflags & XED_SEARCH_DONT_SET_FLAGS) != 0)
|
|
||||||
#define XED_SEARCH_SET_DONT_SET_FLAGS(sflags,state) ((state == TRUE) ? \
|
|
||||||
(sflags |= XED_SEARCH_DONT_SET_FLAGS) : (sflags &= ~XED_SEARCH_DONT_SET_FLAGS))
|
|
||||||
|
|
||||||
#define XED_SEARCH_IS_ENTIRE_WORD(sflags) ((sflags & XED_SEARCH_ENTIRE_WORD) != 0)
|
|
||||||
#define XED_SEARCH_SET_ENTIRE_WORD(sflags,state) ((state == TRUE) ? \
|
|
||||||
(sflags |= XED_SEARCH_ENTIRE_WORD) : (sflags &= ~XED_SEARCH_ENTIRE_WORD))
|
|
||||||
|
|
||||||
#define XED_SEARCH_IS_CASE_SENSITIVE(sflags) ((sflags & XED_SEARCH_CASE_SENSITIVE) != 0)
|
|
||||||
#define XED_SEARCH_SET_CASE_SENSITIVE(sflags,state) ((state == TRUE) ? \
|
|
||||||
(sflags |= XED_SEARCH_CASE_SENSITIVE) : (sflags &= ~XED_SEARCH_CASE_SENSITIVE))
|
|
||||||
|
|
||||||
#define XED_SEARCH_IS_PARSE_ESCAPES(sflags) ((sflags & XED_SEARCH_PARSE_ESCAPES) != 0)
|
|
||||||
#define XED_SEARCH_SET_PARSE_ESCAPES(sflags,state) ((state == TRUE) ? \
|
|
||||||
(sflags |= XED_SEARCH_PARSE_ESCAPES) : (sflags &= ~XED_SEARCH_PARSE_ESCAPES))
|
|
||||||
|
|
||||||
typedef GMountOperation *(*XedMountOperationFactory)(XedDocument *doc,
|
typedef GMountOperation *(*XedMountOperationFactory)(XedDocument *doc,
|
||||||
gpointer userdata);
|
gpointer userdata);
|
||||||
|
|
||||||
|
@ -331,6 +262,11 @@ GMountOperation
|
||||||
*_xed_document_create_mount_operation
|
*_xed_document_create_mount_operation
|
||||||
(XedDocument *doc);
|
(XedDocument *doc);
|
||||||
|
|
||||||
|
void _xed_document_set_search_context (XedDocument *doc,
|
||||||
|
GtkSourceSearchContext *search_context);
|
||||||
|
|
||||||
|
GtkSourceSearchContext *_xed_document_get_search_context (XedDocument *doc);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __XED_DOCUMENT_H__ */
|
#endif /* __XED_DOCUMENT_H__ */
|
||||||
|
|
|
@ -516,54 +516,3 @@ xed_history_entry_get_entry (XedHistoryEntry *entry)
|
||||||
|
|
||||||
return gtk_bin_get_child (GTK_BIN (entry));
|
return gtk_bin_get_child (GTK_BIN (entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
escape_cell_data_func (GtkTreeViewColumn *col,
|
|
||||||
GtkCellRenderer *renderer,
|
|
||||||
GtkTreeModel *model,
|
|
||||||
GtkTreeIter *iter,
|
|
||||||
XedHistoryEntryEscapeFunc escape_func)
|
|
||||||
{
|
|
||||||
gchar *str;
|
|
||||||
gchar *escaped;
|
|
||||||
|
|
||||||
gtk_tree_model_get (model, iter, 0, &str, -1);
|
|
||||||
escaped = escape_func (str);
|
|
||||||
g_object_set (renderer, "text", escaped, NULL);
|
|
||||||
|
|
||||||
g_free (str);
|
|
||||||
g_free (escaped);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
xed_history_entry_set_escape_func (XedHistoryEntry *entry,
|
|
||||||
XedHistoryEntryEscapeFunc escape_func)
|
|
||||||
{
|
|
||||||
GList *cells;
|
|
||||||
|
|
||||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (entry));
|
|
||||||
|
|
||||||
cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (entry));
|
|
||||||
|
|
||||||
/* We only have one cell renderer */
|
|
||||||
g_return_if_fail (cells->data != NULL && cells->next == NULL);
|
|
||||||
|
|
||||||
if (escape_func != NULL)
|
|
||||||
{
|
|
||||||
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry),
|
|
||||||
GTK_CELL_RENDERER (cells->data),
|
|
||||||
(GtkCellLayoutDataFunc) escape_cell_data_func,
|
|
||||||
escape_func,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry),
|
|
||||||
GTK_CELL_RENDERER (cells->data),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free (cells);
|
|
||||||
}
|
|
||||||
|
|
|
@ -80,10 +80,6 @@ gboolean xed_history_entry_get_enable_completion (XedHistoryEntry *entry);
|
||||||
|
|
||||||
GtkWidget *xed_history_entry_get_entry (XedHistoryEntry *entry);
|
GtkWidget *xed_history_entry_get_entry (XedHistoryEntry *entry);
|
||||||
|
|
||||||
typedef gchar * (* XedHistoryEntryEscapeFunc) (const gchar *str);
|
|
||||||
void xed_history_entry_set_escape_func (XedHistoryEntry *entry,
|
|
||||||
XedHistoryEntryEscapeFunc escape_func);
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __XED_HISTORY_ENTRY_H__ */
|
#endif /* __XED_HISTORY_ENTRY_H__ */
|
||||||
|
|
|
@ -18,7 +18,13 @@
|
||||||
|
|
||||||
#define XED_SEARCHBAR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_SEARCHBAR, XedSearchbarPrivate))
|
#define XED_SEARCHBAR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_SEARCHBAR, XedSearchbarPrivate))
|
||||||
|
|
||||||
/* Signals */
|
// typedef enum
|
||||||
|
// {
|
||||||
|
// SEARCH,
|
||||||
|
// REPLACE
|
||||||
|
// } SearchMode;
|
||||||
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
SHOW_REPLACE,
|
SHOW_REPLACE,
|
||||||
|
@ -37,6 +43,7 @@ struct _XedSearchbarPrivate
|
||||||
GtkWidget *replace_label;
|
GtkWidget *replace_label;
|
||||||
GtkWidget *replace_entry;
|
GtkWidget *replace_entry;
|
||||||
GtkWidget *replace_text_entry;
|
GtkWidget *replace_text_entry;
|
||||||
|
GtkWidget *regex_checkbutton;
|
||||||
GtkWidget *match_case_checkbutton;
|
GtkWidget *match_case_checkbutton;
|
||||||
GtkWidget *entire_word_checkbutton;
|
GtkWidget *entire_word_checkbutton;
|
||||||
GtkWidget *wrap_around_checkbutton;
|
GtkWidget *wrap_around_checkbutton;
|
||||||
|
@ -45,15 +52,38 @@ struct _XedSearchbarPrivate
|
||||||
GtkWidget *replace_button;
|
GtkWidget *replace_button;
|
||||||
GtkWidget *replace_all_button;
|
GtkWidget *replace_all_button;
|
||||||
GtkWidget *close_button;
|
GtkWidget *close_button;
|
||||||
|
|
||||||
|
GtkSourceSearchSettings *search_settings;
|
||||||
|
SearchMode search_mode;
|
||||||
|
|
||||||
|
guint update_occurrence_count_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(XedSearchbar, xed_searchbar, GTK_TYPE_BOX)
|
G_DEFINE_TYPE(XedSearchbar, xed_searchbar, GTK_TYPE_BOX)
|
||||||
|
|
||||||
|
static void
|
||||||
|
xed_searchbar_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
XedSearchbar *searchbar = XED_SEARCHBAR (object);
|
||||||
|
|
||||||
|
if (searchbar->priv->update_occurrence_count_id != 0)
|
||||||
|
{
|
||||||
|
g_source_remove (searchbar->priv->update_occurrence_count_id);
|
||||||
|
searchbar->priv->update_occurrence_count_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_object (&searchbar->priv->search_settings);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (xed_searchbar_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xed_searchbar_class_init (XedSearchbarClass *klass)
|
xed_searchbar_class_init (XedSearchbarClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->dispose = xed_searchbar_dispose;
|
||||||
|
|
||||||
g_type_class_add_private (object_class, sizeof(XedSearchbarPrivate));
|
g_type_class_add_private (object_class, sizeof(XedSearchbarPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,130 +121,285 @@ text_found (XedWindow *window,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
text_not_found (XedWindow *window,
|
text_not_found (XedSearchbar *searchbar)
|
||||||
const gchar *text)
|
|
||||||
{
|
{
|
||||||
gchar *searched;
|
const gchar *search_text;
|
||||||
|
gchar *truncated_text;
|
||||||
|
|
||||||
searched = xed_utils_str_end_truncate (text, MAX_MSG_LENGTH);
|
search_text = xed_searchbar_get_search_text (searchbar);
|
||||||
xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
|
truncated_text = xed_utils_str_end_truncate (search_text, MAX_MSG_LENGTH);
|
||||||
window->priv->generic_message_cid,
|
|
||||||
_("\"%s\" not found"), searched);
|
xed_statusbar_flash_message (XED_STATUSBAR (searchbar->window->priv->statusbar),
|
||||||
g_free (searched);
|
searchbar->window->priv->generic_message_cid,
|
||||||
|
_("\"%s\" not found"), truncated_text);
|
||||||
|
|
||||||
|
g_free (truncated_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
run_search (XedView *view,
|
forward_search_finished (GtkSourceSearchContext *search_context,
|
||||||
gboolean wrap_around,
|
GAsyncResult *result,
|
||||||
gboolean search_backwards,
|
XedView *view)
|
||||||
gboolean jump_to_next_result)
|
|
||||||
{
|
{
|
||||||
XedDocument *doc;
|
gboolean found;
|
||||||
GtkTextIter start_iter;
|
GtkSourceBuffer *buffer;
|
||||||
GtkTextIter end_iter;
|
|
||||||
GtkTextIter match_start;
|
GtkTextIter match_start;
|
||||||
GtkTextIter match_end;
|
GtkTextIter match_end;
|
||||||
gboolean found = FALSE;
|
|
||||||
|
|
||||||
doc = XED_DOCUMENT(gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
|
found = gtk_source_search_context_forward_finish (search_context, result, &match_start, &match_end, NULL);
|
||||||
gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), &start_iter, &end_iter);
|
buffer = gtk_source_search_context_get_buffer (search_context);
|
||||||
|
|
||||||
if (!search_backwards)
|
|
||||||
{
|
|
||||||
if (jump_to_next_result)
|
|
||||||
{
|
|
||||||
found = xed_document_search_forward (doc, &end_iter, NULL, &match_start, &match_end);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
found = xed_document_search_forward (doc, &start_iter, NULL, &match_start, &match_end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
found = xed_document_search_backward (doc, NULL, &start_iter, &match_start, &match_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found && wrap_around)
|
|
||||||
{
|
|
||||||
if (!search_backwards)
|
|
||||||
{
|
|
||||||
/* FIXME: set the end_inter */
|
|
||||||
found = xed_document_search_forward (doc, NULL, NULL, &match_start, &match_end);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* FIXME: set the start_inter */
|
|
||||||
found = xed_document_search_backward (doc, NULL, NULL, &match_start, &match_end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &match_start);
|
gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), &match_start, &match_end);
|
||||||
gtk_text_buffer_move_mark_by_name (GTK_TEXT_BUFFER (doc), "selection_bound", &match_end);
|
|
||||||
xed_view_scroll_to_cursor (view);
|
xed_view_scroll_to_cursor (view);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &start_iter);
|
GtkTextIter end_selection;
|
||||||
|
|
||||||
|
gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (buffer), NULL, &end_selection);
|
||||||
|
gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), &end_selection, &end_selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run_forward_search (XedWindow *window,
|
||||||
|
gboolean jump_to_next_result)
|
||||||
|
{
|
||||||
|
XedView *view;
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
GtkTextIter start_at;
|
||||||
|
GtkTextIter end_at;
|
||||||
|
GtkSourceSearchContext *search_context;
|
||||||
|
|
||||||
|
view = xed_window_get_active_view (window);
|
||||||
|
|
||||||
|
if (view == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
|
||||||
|
search_context = _xed_document_get_search_context (XED_DOCUMENT (buffer));
|
||||||
|
|
||||||
|
if (search_context == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_text_buffer_get_selection_bounds (buffer, &start_at, &end_at);
|
||||||
|
|
||||||
|
if (jump_to_next_result)
|
||||||
|
{
|
||||||
|
gtk_source_search_context_forward_async (search_context,
|
||||||
|
&end_at,
|
||||||
|
NULL,
|
||||||
|
(GAsyncReadyCallback)forward_search_finished,
|
||||||
|
view);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gtk_source_search_context_forward_async (search_context,
|
||||||
|
&start_at,
|
||||||
|
NULL,
|
||||||
|
(GAsyncReadyCallback)forward_search_finished,
|
||||||
|
view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
backward_search_finished (GtkSourceSearchContext *search_context,
|
||||||
|
GAsyncResult *result,
|
||||||
|
XedView *view)
|
||||||
|
{
|
||||||
|
gboolean found;
|
||||||
|
GtkTextIter match_start;
|
||||||
|
GtkTextIter match_end;
|
||||||
|
GtkSourceBuffer *buffer;
|
||||||
|
|
||||||
|
found = gtk_source_search_context_backward_finish (search_context, result, &match_start, &match_end, NULL);
|
||||||
|
buffer = gtk_source_search_context_get_buffer (search_context);
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), &match_start, &match_end);
|
||||||
|
xed_view_scroll_to_cursor (view);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GtkTextIter start_selection;
|
||||||
|
|
||||||
|
gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (buffer), &start_selection, NULL);
|
||||||
|
gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), &start_selection, &start_selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run_backward_search (XedWindow *window)
|
||||||
|
{
|
||||||
|
XedView *view;
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
GtkTextIter start_at;
|
||||||
|
GtkSourceSearchContext *search_context;
|
||||||
|
|
||||||
|
view = xed_window_get_active_view (window);
|
||||||
|
|
||||||
|
if (view == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
|
||||||
|
search_context = _xed_document_get_search_context (XED_DOCUMENT (buffer));
|
||||||
|
|
||||||
|
if (search_context == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_text_buffer_get_selection_bounds (buffer, &start_at, NULL);
|
||||||
|
gtk_source_search_context_backward_async (search_context,
|
||||||
|
&start_at,
|
||||||
|
NULL,
|
||||||
|
(GAsyncReadyCallback)backward_search_finished,
|
||||||
|
view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_occurrence_count (XedSearchbar *searchbar)
|
||||||
|
{
|
||||||
|
XedDocument *doc;
|
||||||
|
GtkSourceSearchContext *search_context;
|
||||||
|
GtkTextIter match_start;
|
||||||
|
GtkTextIter match_end;
|
||||||
|
gint count;
|
||||||
|
gint pos;
|
||||||
|
|
||||||
|
if (searchbar->priv->search_mode == SEARCH_MODE_REPLACE)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchbar->priv->update_occurrence_count_id = 0;
|
||||||
|
doc = xed_window_get_active_document (searchbar->window);
|
||||||
|
search_context = _xed_document_get_search_context (doc);
|
||||||
|
|
||||||
|
if (search_context == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = gtk_source_search_context_get_occurrences_count (search_context);
|
||||||
|
|
||||||
|
gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), &match_start, &match_end);
|
||||||
|
pos = gtk_source_search_context_get_occurrence_position (search_context, &match_start, &match_end);
|
||||||
|
|
||||||
|
if (count == -1 || pos == -1)
|
||||||
|
{
|
||||||
|
/* Wait for the buffer to be fully scanned */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
xed_statusbar_flash_message (XED_STATUSBAR (searchbar->window->priv->statusbar),
|
||||||
|
searchbar->window->priv->generic_message_cid,
|
||||||
|
_("No matches found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos == 0)
|
||||||
|
{
|
||||||
|
xed_statusbar_flash_message (XED_STATUSBAR (searchbar->window->priv->statusbar),
|
||||||
|
searchbar->window->priv->generic_message_cid,
|
||||||
|
ngettext ("%d match", "%d matches", count), count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xed_statusbar_flash_message (XED_STATUSBAR (searchbar->window->priv->statusbar),
|
||||||
|
searchbar->window->priv->generic_message_cid,
|
||||||
|
ngettext ("%d of %d match", "%d of %d matches",
|
||||||
|
pos),
|
||||||
|
pos, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
update_occurrence_count_id_cb (XedSearchbar *searchbar)
|
||||||
|
{
|
||||||
|
searchbar->priv->update_occurrence_count_id = 0;
|
||||||
|
update_occurrence_count (searchbar);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
install_occurrence_count_idle (XedSearchbar *searchbar)
|
||||||
|
{
|
||||||
|
if (searchbar->priv->update_occurrence_count_id == 0)
|
||||||
|
{
|
||||||
|
searchbar->priv->update_occurrence_count_id = g_idle_add ((GSourceFunc)update_occurrence_count_id_cb, searchbar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mark_set_cb (GtkTextBuffer *buffer,
|
||||||
|
GtkTextIter *location,
|
||||||
|
GtkTextMark *mark,
|
||||||
|
XedSearchbar *searchbar)
|
||||||
|
{
|
||||||
|
GtkTextMark *insert;
|
||||||
|
GtkTextMark *selection_bound;
|
||||||
|
|
||||||
|
insert = gtk_text_buffer_get_insert (buffer);
|
||||||
|
selection_bound = gtk_text_buffer_get_selection_bound (buffer);
|
||||||
|
|
||||||
|
if (mark == insert || mark == selection_bound)
|
||||||
|
{
|
||||||
|
install_occurrence_count_idle (searchbar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_find (XedSearchbar *searchbar,
|
do_find (XedSearchbar *searchbar,
|
||||||
gboolean search_backwards,
|
gboolean search_backwards,
|
||||||
gboolean jump_to_next_result)
|
gboolean jump_to_next_result)
|
||||||
{
|
{
|
||||||
XedView *active_view;
|
|
||||||
XedDocument *doc;
|
XedDocument *doc;
|
||||||
gchar *search_text;
|
GtkSourceSearchContext *search_context;
|
||||||
const gchar *entry_text;
|
GtkSourceSearchSettings *search_settings;
|
||||||
gboolean match_case;
|
|
||||||
gboolean entire_word;
|
|
||||||
gboolean wrap_around;
|
|
||||||
guint flags = 0;
|
|
||||||
guint old_flags = 0;
|
|
||||||
gboolean found;
|
|
||||||
|
|
||||||
/* TODO: make the searchbar insensitive when all the tabs are closed
|
search_settings = xed_searchbar_get_search_settings (searchbar);
|
||||||
* and assert here that the view is not NULL */
|
doc = xed_window_get_active_document (searchbar->window);
|
||||||
active_view = xed_window_get_active_view (searchbar->window);
|
search_context = _xed_document_get_search_context (doc);
|
||||||
if (active_view == NULL)
|
searchbar->priv->search_mode = SEARCH_MODE_SEARCH;
|
||||||
|
|
||||||
|
if (search_context == NULL || search_settings != gtk_source_search_context_get_settings (search_context))
|
||||||
{
|
{
|
||||||
return;
|
search_context = gtk_source_search_context_new (GTK_SOURCE_BUFFER (doc), search_settings);
|
||||||
|
|
||||||
|
_xed_document_set_search_context (doc, search_context);
|
||||||
|
|
||||||
|
g_signal_connect (GTK_TEXT_BUFFER (doc), "mark-set",
|
||||||
|
G_CALLBACK (mark_set_cb), searchbar);
|
||||||
|
|
||||||
|
g_signal_connect_swapped (search_context, "notify::occurrences-count",
|
||||||
|
G_CALLBACK (install_occurrence_count_idle), searchbar);
|
||||||
|
|
||||||
|
g_object_unref (search_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (active_view)));
|
if (search_backwards)
|
||||||
|
|
||||||
match_case = xed_searchbar_get_match_case (searchbar);
|
|
||||||
entire_word = xed_searchbar_get_entire_word (searchbar);
|
|
||||||
wrap_around = xed_searchbar_get_wrap_around (searchbar);
|
|
||||||
entry_text = xed_searchbar_get_search_text (searchbar);
|
|
||||||
|
|
||||||
XED_SEARCH_SET_CASE_SENSITIVE (flags, match_case);
|
|
||||||
XED_SEARCH_SET_ENTIRE_WORD (flags, entire_word);
|
|
||||||
|
|
||||||
search_text = xed_document_get_search_text (doc, &old_flags);
|
|
||||||
|
|
||||||
if ((search_text == NULL) || (strcmp (search_text, entry_text) != 0) || (flags != old_flags))
|
|
||||||
{
|
{
|
||||||
xed_document_set_search_text (doc, entry_text, flags);
|
run_backward_search (searchbar->window);
|
||||||
}
|
|
||||||
|
|
||||||
g_free (search_text);
|
|
||||||
|
|
||||||
found = run_search (active_view, wrap_around, search_backwards, jump_to_next_result);
|
|
||||||
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
text_found (searchbar->window, 0);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
text_not_found (searchbar->window, entry_text);
|
run_forward_search (searchbar->window, jump_to_next_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,21 +407,14 @@ void
|
||||||
xed_searchbar_find_again (XedSearchbar *searchbar,
|
xed_searchbar_find_again (XedSearchbar *searchbar,
|
||||||
gboolean backward)
|
gboolean backward)
|
||||||
{
|
{
|
||||||
XedView *active_view;
|
if (backward)
|
||||||
gboolean wrap_around = TRUE;
|
|
||||||
gpointer data;
|
|
||||||
|
|
||||||
active_view = xed_window_get_active_view (searchbar->window);
|
|
||||||
g_return_if_fail (active_view != NULL);
|
|
||||||
|
|
||||||
data = g_object_get_data (G_OBJECT (searchbar->window), XED_SEARCHBAR_KEY);
|
|
||||||
|
|
||||||
if (data != NULL)
|
|
||||||
{
|
{
|
||||||
wrap_around = xed_searchbar_get_wrap_around (XED_SEARCHBAR (data));
|
do_find (searchbar, TRUE, TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
do_find (searchbar, FALSE, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
run_search (active_view, wrap_around, backward, TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -279,69 +457,45 @@ get_selected_text (GtkTextBuffer *doc,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
replace_selected_text (GtkTextBuffer *buffer,
|
|
||||||
const gchar *replace)
|
|
||||||
{
|
|
||||||
g_return_if_fail (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL));
|
|
||||||
g_return_if_fail (replace != NULL);
|
|
||||||
|
|
||||||
gtk_text_buffer_begin_user_action (buffer);
|
|
||||||
gtk_text_buffer_delete_selection (buffer, FALSE, TRUE);
|
|
||||||
gtk_text_buffer_insert_at_cursor (buffer, replace, strlen (replace));
|
|
||||||
gtk_text_buffer_end_user_action (buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_replace (XedSearchbar *searchbar)
|
do_replace (XedSearchbar *searchbar)
|
||||||
{
|
{
|
||||||
XedDocument *doc;
|
XedDocument *doc;
|
||||||
const gchar *search_entry_text;
|
GtkSourceSearchContext *search_context;
|
||||||
const gchar *replace_entry_text;
|
const gchar *replace_entry_text;
|
||||||
gchar *unescaped_search_text;
|
|
||||||
gchar *unescaped_replace_text;
|
gchar *unescaped_replace_text;
|
||||||
gchar *selected_text = NULL;
|
GtkTextIter start;
|
||||||
gboolean match_case;
|
GtkTextIter end;
|
||||||
|
|
||||||
doc = xed_window_get_active_document (searchbar->window);
|
doc = xed_window_get_active_document (searchbar->window);
|
||||||
|
|
||||||
if (doc == NULL)
|
if (doc == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
search_entry_text = xed_searchbar_get_search_text (searchbar);
|
search_context = _xed_document_get_search_context (doc);
|
||||||
g_return_if_fail ((search_entry_text) != NULL);
|
|
||||||
g_return_if_fail ((*search_entry_text) != '\0');
|
if (search_context == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* replace text may be "", we just delete */
|
/* replace text may be "", we just delete */
|
||||||
replace_entry_text = xed_searchbar_get_replace_text (searchbar);
|
replace_entry_text = xed_searchbar_get_replace_text (searchbar);
|
||||||
g_return_if_fail ((replace_entry_text) != NULL);
|
g_return_if_fail ((replace_entry_text) != NULL);
|
||||||
|
|
||||||
unescaped_search_text = xed_utils_unescape_search_text (search_entry_text);
|
unescaped_replace_text = gtk_source_utils_unescape_search_text (replace_entry_text);
|
||||||
|
gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), &start, &end);
|
||||||
|
searchbar->priv->search_mode = SEARCH_MODE_REPLACE;
|
||||||
|
|
||||||
get_selected_text (GTK_TEXT_BUFFER (doc), &selected_text, NULL);
|
gtk_source_search_context_replace (search_context,
|
||||||
|
&start,
|
||||||
|
&end,
|
||||||
|
unescaped_replace_text,
|
||||||
|
-1,
|
||||||
|
NULL);
|
||||||
|
|
||||||
match_case = xed_searchbar_get_match_case (searchbar);
|
|
||||||
|
|
||||||
if ((selected_text == NULL) ||
|
|
||||||
(match_case && (strcmp (selected_text, unescaped_search_text) != 0)) ||
|
|
||||||
(!match_case && !g_utf8_caselessnmatch (selected_text,
|
|
||||||
unescaped_search_text,
|
|
||||||
strlen (selected_text),
|
|
||||||
strlen (unescaped_search_text)) != 0))
|
|
||||||
{
|
|
||||||
do_find (searchbar, FALSE, TRUE );
|
|
||||||
g_free (unescaped_search_text);
|
|
||||||
g_free (selected_text);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unescaped_replace_text = xed_utils_unescape_search_text (replace_entry_text);
|
|
||||||
replace_selected_text (GTK_TEXT_BUFFER (doc), unescaped_replace_text);
|
|
||||||
|
|
||||||
g_free (unescaped_search_text);
|
|
||||||
g_free (selected_text);
|
|
||||||
g_free (unescaped_replace_text);
|
g_free (unescaped_replace_text);
|
||||||
|
|
||||||
do_find (searchbar, FALSE, TRUE);
|
do_find (searchbar, FALSE, TRUE);
|
||||||
|
@ -350,38 +504,35 @@ do_replace (XedSearchbar *searchbar)
|
||||||
static void
|
static void
|
||||||
do_replace_all (XedSearchbar *searchbar)
|
do_replace_all (XedSearchbar *searchbar)
|
||||||
{
|
{
|
||||||
XedView *active_view;
|
|
||||||
XedDocument *doc;
|
XedDocument *doc;
|
||||||
const gchar *search_entry_text;
|
GtkSourceSearchContext *search_context;
|
||||||
const gchar *replace_entry_text;
|
const gchar *replace_entry_text;
|
||||||
gboolean match_case;
|
gchar *unescaped_replace_text;
|
||||||
gboolean entire_word;
|
|
||||||
guint flags = 0;
|
|
||||||
gint count;
|
gint count;
|
||||||
|
|
||||||
active_view = xed_window_get_active_view (searchbar->window);
|
doc = xed_window_get_active_document (searchbar->window);
|
||||||
if (active_view == NULL)
|
|
||||||
|
if (doc == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (active_view)));
|
search_context = _xed_document_get_search_context (doc);
|
||||||
|
|
||||||
search_entry_text = xed_searchbar_get_search_text (searchbar);
|
if (search_context == NULL)
|
||||||
g_return_if_fail ((search_entry_text) != NULL);
|
{
|
||||||
g_return_if_fail ((*search_entry_text) != '\0');
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* replace text may be "", we just delete all occurrences */
|
/* replace text may be "", we just delete all occurrences */
|
||||||
replace_entry_text = xed_searchbar_get_replace_text (searchbar);
|
replace_entry_text = xed_searchbar_get_replace_text (searchbar);
|
||||||
g_return_if_fail ((replace_entry_text) != NULL);
|
g_return_if_fail ((replace_entry_text) != NULL);
|
||||||
|
|
||||||
match_case = xed_searchbar_get_match_case (searchbar);
|
unescaped_replace_text = gtk_source_utils_unescape_search_text (replace_entry_text);
|
||||||
entire_word = xed_searchbar_get_entire_word (searchbar);
|
count = gtk_source_search_context_replace_all (search_context, unescaped_replace_text, -1, NULL);
|
||||||
|
searchbar->priv->search_mode = SEARCH_MODE_REPLACE;
|
||||||
|
|
||||||
XED_SEARCH_SET_CASE_SENSITIVE (flags, match_case);
|
g_free (unescaped_replace_text);
|
||||||
XED_SEARCH_SET_ENTIRE_WORD (flags, entire_word);
|
|
||||||
|
|
||||||
count = xed_document_replace_all (doc, search_entry_text, replace_entry_text, flags);
|
|
||||||
|
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
|
@ -389,49 +540,11 @@ do_replace_all (XedSearchbar *searchbar)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
text_not_found (searchbar->window, search_entry_text);
|
text_not_found (searchbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
insert_text_handler (GtkEditable *editable,
|
|
||||||
const gchar *text,
|
|
||||||
gint length,
|
|
||||||
gint *position,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
static gboolean insert_text = FALSE;
|
|
||||||
gchar *escaped_text;
|
|
||||||
gint new_len;
|
|
||||||
|
|
||||||
/* To avoid recursive behavior */
|
|
||||||
if (insert_text)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
escaped_text = xed_utils_escape_search_text (text);
|
|
||||||
|
|
||||||
new_len = strlen (escaped_text);
|
|
||||||
|
|
||||||
if (new_len == length)
|
|
||||||
{
|
|
||||||
g_free (escaped_text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
insert_text = TRUE;
|
|
||||||
|
|
||||||
g_signal_stop_emission_by_name (editable, "insert_text");
|
|
||||||
|
|
||||||
gtk_editable_insert_text (editable, escaped_text, new_len, position);
|
|
||||||
|
|
||||||
insert_text = FALSE;
|
|
||||||
|
|
||||||
g_free (escaped_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
search_text_entry_changed (GtkEditable *editable,
|
search_text_entry_changed (GtkEditable *editable,
|
||||||
XedSearchbar *searchbar)
|
XedSearchbar *searchbar)
|
||||||
|
@ -444,26 +557,38 @@ search_text_entry_changed (GtkEditable *editable,
|
||||||
if (*search_string != '\0')
|
if (*search_string != '\0')
|
||||||
{
|
{
|
||||||
search_buttons_set_sensitive (searchbar, TRUE);
|
search_buttons_set_sensitive (searchbar, TRUE);
|
||||||
do_find (searchbar, FALSE, FALSE);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
search_buttons_set_sensitive (searchbar, FALSE);
|
search_buttons_set_sensitive (searchbar, FALSE);
|
||||||
do_find (searchbar, FALSE, FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gtk_source_search_settings_get_regex_enabled (searchbar->priv->search_settings))
|
||||||
|
{
|
||||||
|
gtk_source_search_settings_set_search_text (searchbar->priv->search_settings, search_string);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gchar *unescaped_search_string;
|
||||||
|
|
||||||
|
unescaped_search_string = gtk_source_utils_unescape_search_text (search_string);
|
||||||
|
gtk_source_search_settings_set_search_text (searchbar->priv->search_settings, unescaped_search_string);
|
||||||
|
|
||||||
|
g_free (unescaped_search_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_find (searchbar, FALSE, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
remember_search_entry (XedSearchbar *searchbar)
|
remember_search_entry (XedSearchbar *searchbar)
|
||||||
{
|
{
|
||||||
const gchar *str;
|
const gchar *str;
|
||||||
|
|
||||||
str = gtk_entry_get_text (GTK_ENTRY(searchbar->priv->search_text_entry));
|
str = gtk_entry_get_text (GTK_ENTRY(searchbar->priv->search_text_entry));
|
||||||
if (*str != '\0')
|
if (*str != '\0')
|
||||||
{
|
{
|
||||||
gchar *text;
|
xed_history_entry_prepend_text (XED_HISTORY_ENTRY (searchbar->priv->search_entry), str);
|
||||||
text = xed_utils_unescape_search_text (str);
|
|
||||||
xed_history_entry_prepend_text (XED_HISTORY_ENTRY(searchbar->priv->search_entry), text);
|
|
||||||
g_free (text);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,13 +596,11 @@ static void
|
||||||
remember_replace_entry (XedSearchbar *searchbar)
|
remember_replace_entry (XedSearchbar *searchbar)
|
||||||
{
|
{
|
||||||
const gchar *str;
|
const gchar *str;
|
||||||
|
|
||||||
str = gtk_entry_get_text (GTK_ENTRY(searchbar->priv->replace_text_entry));
|
str = gtk_entry_get_text (GTK_ENTRY(searchbar->priv->replace_text_entry));
|
||||||
if (*str != '\0')
|
if (*str != '\0')
|
||||||
{
|
{
|
||||||
gchar *text;
|
xed_history_entry_prepend_text (XED_HISTORY_ENTRY(searchbar->priv->replace_entry), str);
|
||||||
text = xed_utils_unescape_search_text (str);
|
|
||||||
xed_history_entry_prepend_text (XED_HISTORY_ENTRY(searchbar->priv->replace_entry), text);
|
|
||||||
g_free (text);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,6 +684,7 @@ xed_searchbar_init (XedSearchbar *searchbar)
|
||||||
"grid", &searchbar->priv->grid,
|
"grid", &searchbar->priv->grid,
|
||||||
"search_label", &searchbar->priv->search_label,
|
"search_label", &searchbar->priv->search_label,
|
||||||
"replace_with_label", &searchbar->priv->replace_label,
|
"replace_with_label", &searchbar->priv->replace_label,
|
||||||
|
"regex_checkbutton", &searchbar->priv->regex_checkbutton,
|
||||||
"match_case_checkbutton", &searchbar->priv->match_case_checkbutton,
|
"match_case_checkbutton", &searchbar->priv->match_case_checkbutton,
|
||||||
"entire_word_checkbutton", &searchbar->priv->entire_word_checkbutton,
|
"entire_word_checkbutton", &searchbar->priv->entire_word_checkbutton,
|
||||||
"wrap_around_checkbutton", &searchbar->priv->wrap_around_checkbutton,
|
"wrap_around_checkbutton", &searchbar->priv->wrap_around_checkbutton,
|
||||||
|
@ -574,10 +698,8 @@ xed_searchbar_init (XedSearchbar *searchbar)
|
||||||
|
|
||||||
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (searchbar)), "xed-searchbar");
|
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (searchbar)), "xed-searchbar");
|
||||||
|
|
||||||
searchbar->priv->search_entry = xed_history_entry_new ("history-search-for", TRUE);
|
searchbar->priv->search_entry = xed_history_entry_new ("history-search-for", FALSE);
|
||||||
gtk_widget_set_hexpand (searchbar->priv->search_entry, TRUE);
|
gtk_widget_set_hexpand (searchbar->priv->search_entry, TRUE);
|
||||||
xed_history_entry_set_escape_func (XED_HISTORY_ENTRY (searchbar->priv->search_entry),
|
|
||||||
(XedHistoryEntryEscapeFunc) xed_utils_escape_search_text);
|
|
||||||
|
|
||||||
searchbar->priv->search_text_entry = xed_history_entry_get_entry (XED_HISTORY_ENTRY (searchbar->priv->search_entry));
|
searchbar->priv->search_text_entry = xed_history_entry_get_entry (XED_HISTORY_ENTRY (searchbar->priv->search_entry));
|
||||||
gtk_entry_set_activates_default (GTK_ENTRY (searchbar->priv->search_text_entry), TRUE);
|
gtk_entry_set_activates_default (GTK_ENTRY (searchbar->priv->search_text_entry), TRUE);
|
||||||
|
@ -585,9 +707,7 @@ xed_searchbar_init (XedSearchbar *searchbar)
|
||||||
gtk_widget_show (searchbar->priv->search_entry);
|
gtk_widget_show (searchbar->priv->search_entry);
|
||||||
gtk_grid_attach (GTK_GRID (searchbar->priv->grid), searchbar->priv->search_entry, 2, 0, 1, 1);
|
gtk_grid_attach (GTK_GRID (searchbar->priv->grid), searchbar->priv->search_entry, 2, 0, 1, 1);
|
||||||
|
|
||||||
searchbar->priv->replace_entry = xed_history_entry_new ("history-replace-with", TRUE);
|
searchbar->priv->replace_entry = xed_history_entry_new ("history-replace-with", FALSE);
|
||||||
xed_history_entry_set_escape_func (XED_HISTORY_ENTRY (searchbar->priv->replace_entry),
|
|
||||||
(XedHistoryEntryEscapeFunc) xed_utils_escape_search_text);
|
|
||||||
|
|
||||||
searchbar->priv->replace_text_entry = xed_history_entry_get_entry (
|
searchbar->priv->replace_text_entry = xed_history_entry_get_entry (
|
||||||
XED_HISTORY_ENTRY (searchbar->priv->replace_entry));
|
XED_HISTORY_ENTRY (searchbar->priv->replace_entry));
|
||||||
|
@ -620,12 +740,6 @@ xed_searchbar_init (XedSearchbar *searchbar)
|
||||||
|
|
||||||
g_object_unref (content);
|
g_object_unref (content);
|
||||||
|
|
||||||
g_signal_connect (searchbar->priv->search_text_entry, "insert_text",
|
|
||||||
G_CALLBACK (insert_text_handler), NULL);
|
|
||||||
|
|
||||||
g_signal_connect (searchbar->priv->replace_text_entry, "insert_text",
|
|
||||||
G_CALLBACK (insert_text_handler), NULL);
|
|
||||||
|
|
||||||
g_signal_connect (searchbar->priv->search_text_entry, "changed",
|
g_signal_connect (searchbar->priv->search_text_entry, "changed",
|
||||||
G_CALLBACK (search_text_entry_changed), searchbar);
|
G_CALLBACK (search_text_entry_changed), searchbar);
|
||||||
|
|
||||||
|
@ -653,27 +767,45 @@ xed_searchbar_init (XedSearchbar *searchbar)
|
||||||
|
|
||||||
g_signal_connect (searchbar->priv->match_case_checkbutton, "clicked",
|
g_signal_connect (searchbar->priv->match_case_checkbutton, "clicked",
|
||||||
G_CALLBACK (toggle_button_clicked_callback), searchbar);
|
G_CALLBACK (toggle_button_clicked_callback), searchbar);
|
||||||
|
|
||||||
|
searchbar->priv->search_settings = gtk_source_search_settings_new ();
|
||||||
|
|
||||||
|
g_object_bind_property (searchbar->priv->regex_checkbutton, "active",
|
||||||
|
searchbar->priv->search_settings, "regex-enabled",
|
||||||
|
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||||
|
|
||||||
|
g_object_bind_property (searchbar->priv->match_case_checkbutton, "active",
|
||||||
|
searchbar->priv->search_settings, "case-sensitive",
|
||||||
|
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||||
|
|
||||||
|
g_object_bind_property (searchbar->priv->entire_word_checkbutton, "active",
|
||||||
|
searchbar->priv->search_settings, "at-word-boundaries",
|
||||||
|
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||||
|
|
||||||
|
g_object_bind_property (searchbar->priv->wrap_around_checkbutton, "active",
|
||||||
|
searchbar->priv->search_settings, "wrap-around",
|
||||||
|
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
xed_searchbar_new (GtkWindow *parent,
|
xed_searchbar_new (GtkWindow *parent)
|
||||||
gboolean show_replace)
|
|
||||||
{
|
{
|
||||||
XedSearchbar *searchbar;
|
XedSearchbar *searchbar;
|
||||||
|
|
||||||
searchbar = g_object_new (XED_TYPE_SEARCHBAR, NULL);
|
searchbar = g_object_new (XED_TYPE_SEARCHBAR, NULL);
|
||||||
searchbar->window = XED_WINDOW (parent);
|
searchbar->window = XED_WINDOW (parent);
|
||||||
|
|
||||||
return GTK_WIDGET (searchbar);
|
return GTK_WIDGET (searchbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xed_searchbar_show (XedSearchbar *searchbar,
|
xed_searchbar_show (XedSearchbar *searchbar,
|
||||||
gboolean show_replace)
|
SearchMode search_mode)
|
||||||
{
|
{
|
||||||
XedDocument *doc;
|
XedDocument *doc;
|
||||||
gboolean selection_exists;
|
gboolean selection_exists;
|
||||||
gchar *find_text = NULL;
|
gchar *find_text = NULL;
|
||||||
const gchar *search_text = NULL;
|
gint sel_len = 0;
|
||||||
gint sel_len;
|
|
||||||
|
|
||||||
doc = xed_window_get_active_document (searchbar->window);
|
doc = xed_window_get_active_document (searchbar->window);
|
||||||
g_return_if_fail (doc != NULL);
|
g_return_if_fail (doc != NULL);
|
||||||
|
@ -682,28 +814,28 @@ xed_searchbar_show (XedSearchbar *searchbar,
|
||||||
|
|
||||||
if (selection_exists && find_text != NULL && sel_len < 80)
|
if (selection_exists && find_text != NULL && sel_len < 80)
|
||||||
{
|
{
|
||||||
/*
|
gchar *escaped_find_text;
|
||||||
* Special case: if the currently selected text
|
|
||||||
* is the same as the unescaped search text, use the
|
if (gtk_source_search_settings_get_regex_enabled (searchbar->priv->search_settings))
|
||||||
* same old search text. (Without this, if you e.g.
|
|
||||||
* search for '\n' and then open the search searchbar again,
|
|
||||||
* you'll get an unprintable single-character literal '\n' in the "search for" box).
|
|
||||||
*/
|
|
||||||
search_text = xed_searchbar_get_search_text (XED_SEARCHBAR (searchbar));
|
|
||||||
if (!(search_text != NULL && !strcmp (xed_utils_unescape_search_text (search_text), find_text)))
|
|
||||||
{
|
{
|
||||||
/* General case */
|
escaped_find_text = g_regex_escape_string (find_text, -1);
|
||||||
xed_searchbar_set_search_text (XED_SEARCHBAR (searchbar), find_text);
|
|
||||||
}
|
}
|
||||||
g_free (find_text);
|
else
|
||||||
}
|
{
|
||||||
else
|
escaped_find_text = gtk_source_utils_escape_search_text (find_text);
|
||||||
{
|
}
|
||||||
g_free (find_text);
|
|
||||||
|
xed_searchbar_set_search_text (XED_SEARCHBAR (searchbar), escaped_find_text);
|
||||||
|
|
||||||
|
g_free (escaped_find_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free (find_text);
|
||||||
|
|
||||||
gtk_revealer_set_transition_type (GTK_REVEALER (searchbar->priv->revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
|
gtk_revealer_set_transition_type (GTK_REVEALER (searchbar->priv->revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
|
||||||
gtk_revealer_set_reveal_child (GTK_REVEALER (searchbar->priv->revealer), TRUE);
|
gtk_revealer_set_reveal_child (GTK_REVEALER (searchbar->priv->revealer), TRUE);
|
||||||
if (show_replace)
|
|
||||||
|
if (search_mode == SEARCH_MODE_REPLACE)
|
||||||
{
|
{
|
||||||
gtk_widget_show (searchbar->priv->replace_label);
|
gtk_widget_show (searchbar->priv->replace_label);
|
||||||
gtk_widget_show (searchbar->priv->replace_entry);
|
gtk_widget_show (searchbar->priv->replace_entry);
|
||||||
|
@ -734,6 +866,7 @@ xed_searchbar_hide (XedSearchbar *searchbar)
|
||||||
|
|
||||||
// focus document
|
// focus document
|
||||||
active_view = xed_window_get_active_view (searchbar->window);
|
active_view = xed_window_get_active_view (searchbar->window);
|
||||||
|
|
||||||
if (active_view != NULL)
|
if (active_view != NULL)
|
||||||
{
|
{
|
||||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||||
|
@ -743,84 +876,35 @@ xed_searchbar_hide (XedSearchbar *searchbar)
|
||||||
_xed_cmd_search_clear_highlight (searchbar->window);
|
_xed_cmd_search_clear_highlight (searchbar->window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
xed_searchbar_set_search_text (XedSearchbar *searchbar,
|
|
||||||
const gchar *text)
|
|
||||||
{
|
|
||||||
g_return_if_fail (XED_IS_SEARCHBAR (searchbar));
|
|
||||||
g_return_if_fail (text != NULL);
|
|
||||||
gtk_entry_set_text (GTK_ENTRY (searchbar->priv->search_text_entry), text);
|
|
||||||
search_buttons_set_sensitive (searchbar, (text != '\0'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The text must be unescaped before searching.
|
|
||||||
*/
|
|
||||||
const gchar *
|
|
||||||
xed_searchbar_get_search_text (XedSearchbar *searchbar)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), NULL);
|
|
||||||
return gtk_entry_get_text (GTK_ENTRY (searchbar->priv->search_text_entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
xed_searchbar_set_replace_text (XedSearchbar *searchbar,
|
|
||||||
const gchar *text)
|
|
||||||
{
|
|
||||||
g_return_if_fail (XED_IS_SEARCHBAR (searchbar));
|
|
||||||
g_return_if_fail (text != NULL);
|
|
||||||
|
|
||||||
gtk_entry_set_text (GTK_ENTRY (searchbar->priv->replace_text_entry), text);
|
|
||||||
}
|
|
||||||
|
|
||||||
const gchar *
|
const gchar *
|
||||||
xed_searchbar_get_replace_text (XedSearchbar *searchbar)
|
xed_searchbar_get_replace_text (XedSearchbar *searchbar)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), NULL);
|
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), NULL);
|
||||||
|
|
||||||
return gtk_entry_get_text (GTK_ENTRY (searchbar->priv->replace_text_entry));
|
return gtk_entry_get_text (GTK_ENTRY (searchbar->priv->replace_text_entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
GtkSourceSearchSettings *
|
||||||
xed_searchbar_set_match_case (XedSearchbar *searchbar,
|
xed_searchbar_get_search_settings (XedSearchbar *searchbar)
|
||||||
gboolean match_case)
|
|
||||||
{
|
{
|
||||||
g_return_if_fail (XED_IS_SEARCHBAR (searchbar));
|
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), NULL);
|
||||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (searchbar->priv->match_case_checkbutton), match_case);
|
|
||||||
|
return searchbar->priv->search_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
const gchar *
|
||||||
xed_searchbar_get_match_case (XedSearchbar *searchbar)
|
xed_searchbar_get_search_text (XedSearchbar *searchbar)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), FALSE);
|
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), NULL);
|
||||||
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (searchbar->priv->match_case_checkbutton));
|
|
||||||
|
return gtk_entry_get_text (GTK_ENTRY (searchbar->priv->search_text_entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xed_searchbar_set_entire_word (XedSearchbar *searchbar,
|
xed_searchbar_set_search_text (XedSearchbar *searchbar,
|
||||||
gboolean entire_word)
|
const gchar *search_text)
|
||||||
{
|
{
|
||||||
g_return_if_fail (XED_IS_SEARCHBAR (searchbar));
|
g_return_if_fail (XED_IS_SEARCHBAR (searchbar));
|
||||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (searchbar->priv->entire_word_checkbutton), entire_word);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gtk_entry_set_text (GTK_ENTRY (searchbar->priv->search_text_entry), search_text);
|
||||||
xed_searchbar_get_entire_word (XedSearchbar *searchbar)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), FALSE);
|
|
||||||
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (searchbar->priv->entire_word_checkbutton));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
xed_searchbar_set_wrap_around (XedSearchbar *searchbar,
|
|
||||||
gboolean wrap_around)
|
|
||||||
{
|
|
||||||
g_return_if_fail (XED_IS_SEARCHBAR (searchbar));
|
|
||||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (searchbar->priv->wrap_around_checkbutton), wrap_around);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
xed_searchbar_get_wrap_around (XedSearchbar *searchbar)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), FALSE);
|
|
||||||
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (searchbar->priv->wrap_around_checkbutton));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#define __XED_SEARCHBAR_H__
|
#define __XED_SEARCHBAR_H__
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
#include <gtksourceview/gtksource.h>
|
||||||
#include "xed-window.h"
|
#include "xed-window.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -36,38 +37,29 @@ struct _XedSearchbarClass
|
||||||
gboolean (* show_replace) (XedSearchbar *dlg);
|
gboolean (* show_replace) (XedSearchbar *dlg);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
typedef enum
|
||||||
{
|
{
|
||||||
XED_SEARCHBAR_FIND_RESPONSE = 100,
|
SEARCH_MODE_SEARCH,
|
||||||
XED_SEARCHBAR_REPLACE_RESPONSE,
|
SEARCH_MODE_REPLACE
|
||||||
XED_SEARCHBAR_REPLACE_ALL_RESPONSE
|
} SearchMode;
|
||||||
};
|
|
||||||
|
|
||||||
GType xed_searchbar_get_type (void) G_GNUC_CONST;
|
GType xed_searchbar_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
GtkWidget *xed_searchbar_new (GtkWindow *parent, gboolean show_replace);
|
GtkWidget *xed_searchbar_new (GtkWindow *parent);
|
||||||
|
|
||||||
void xed_searchbar_hide (XedSearchbar *searchbar);
|
void xed_searchbar_hide (XedSearchbar *searchbar);
|
||||||
void xed_searchbar_show (XedSearchbar *searchbar, gboolean show_replace);
|
void xed_searchbar_show (XedSearchbar *searchbar, SearchMode search_mode);
|
||||||
void xed_searchbar_find_again (XedSearchbar *searchbar, gboolean backward);
|
void xed_searchbar_find_again (XedSearchbar *searchbar, gboolean backward);
|
||||||
|
|
||||||
void xed_searchbar_set_search_text (XedSearchbar *searchbar, const gchar *text);
|
|
||||||
const gchar *xed_searchbar_get_search_text (XedSearchbar *searchbar);
|
|
||||||
|
|
||||||
void xed_searchbar_set_replace_text (XedSearchbar *searchbar, const gchar *text);
|
|
||||||
const gchar *xed_searchbar_get_replace_text (XedSearchbar *searchbar);
|
const gchar *xed_searchbar_get_replace_text (XedSearchbar *searchbar);
|
||||||
|
const gchar *xed_searchbar_get_search_text (XedSearchbar *searchbar);
|
||||||
|
|
||||||
void xed_searchbar_set_match_case (XedSearchbar *searchbar, gboolean match_case);
|
|
||||||
gboolean xed_searchbar_get_match_case (XedSearchbar *searchbar);
|
|
||||||
|
|
||||||
void xed_searchbar_set_entire_word (XedSearchbar *searchbar, gboolean entire_word);
|
|
||||||
gboolean xed_searchbar_get_entire_word (XedSearchbar *searchbar);
|
|
||||||
|
|
||||||
void xed_searchbar_set_backwards (XedSearchbar *searchbar, gboolean backwards);
|
|
||||||
gboolean xed_searchbar_get_backwards (XedSearchbar *searchbar);
|
gboolean xed_searchbar_get_backwards (XedSearchbar *searchbar);
|
||||||
|
|
||||||
void xed_searchbar_set_wrap_around (XedSearchbar *searchbar, gboolean wrap_around);
|
GtkSourceSearchSettings *xed_searchbar_get_search_settings (XedSearchbar *searchbar);
|
||||||
gboolean xed_searchbar_get_wrap_around (XedSearchbar *searchbar);
|
|
||||||
|
void xed_searchbar_set_search_text (XedSearchbar *searchbar,
|
||||||
|
const gchar *search_text);
|
||||||
|
|
||||||
void xed_searchbar_set_parse_escapes (XedSearchbar *searchbar, gboolean parse_escapes);
|
void xed_searchbar_set_parse_escapes (XedSearchbar *searchbar, gboolean parse_escapes);
|
||||||
gboolean xed_searchbar_get_parse_escapes (XedSearchbar *searchbar);
|
gboolean xed_searchbar_get_parse_escapes (XedSearchbar *searchbar);
|
||||||
|
|
|
@ -112,6 +112,26 @@
|
||||||
<object class="GtkBox" id="box1">
|
<object class="GtkBox" id="box1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkToggleButton" id="regex_checkbutton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Regular expression</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="image4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">xapp-use-regex-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkToggleButton" id="match_case_checkbutton">
|
<object class="GtkToggleButton" id="match_case_checkbutton">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -130,7 +150,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">0</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -151,7 +171,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">1</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -172,7 +192,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="position">2</property>
|
<property name="position">3</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<style>
|
<style>
|
||||||
|
|
137
xed/xed-utils.c
137
xed/xed-utils.c
|
@ -44,6 +44,7 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gi18n.h>
|
#include <glib/gi18n.h>
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
#include <gtksourceview/gtksource.h>
|
||||||
|
|
||||||
#include "xed-utils.h"
|
#include "xed-utils.h"
|
||||||
|
|
||||||
|
@ -276,142 +277,6 @@ xed_utils_set_atk_relation (GtkWidget *obj1,
|
||||||
g_object_unref (G_OBJECT (relation));
|
g_object_unref (G_OBJECT (relation));
|
||||||
}
|
}
|
||||||
|
|
||||||
gchar *
|
|
||||||
xed_utils_escape_search_text (const gchar* text)
|
|
||||||
{
|
|
||||||
GString *str;
|
|
||||||
gint length;
|
|
||||||
const gchar *p;
|
|
||||||
const gchar *end;
|
|
||||||
|
|
||||||
if (text == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
xed_debug_message (DEBUG_SEARCH, "Text: %s", text);
|
|
||||||
|
|
||||||
length = strlen (text);
|
|
||||||
|
|
||||||
/* no escape when typing.
|
|
||||||
* The short circuit works only for ascii, but we only
|
|
||||||
* care about not escaping a single '\' */
|
|
||||||
if (length == 1)
|
|
||||||
{
|
|
||||||
return g_strdup (text);
|
|
||||||
}
|
|
||||||
|
|
||||||
str = g_string_new ("");
|
|
||||||
|
|
||||||
p = text;
|
|
||||||
end = text + length;
|
|
||||||
|
|
||||||
while (p != end)
|
|
||||||
{
|
|
||||||
const gchar *next;
|
|
||||||
next = g_utf8_next_char (p);
|
|
||||||
|
|
||||||
switch (*p)
|
|
||||||
{
|
|
||||||
case '\n':
|
|
||||||
g_string_append (str, "\\n");
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
g_string_append (str, "\\r");
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
g_string_append (str, "\\t");
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
g_string_append (str, "\\\\");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_string_append_len (str, p, next - p);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_string_free (str, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
gchar *
|
|
||||||
xed_utils_unescape_search_text (const gchar *text)
|
|
||||||
{
|
|
||||||
GString *str;
|
|
||||||
gint length;
|
|
||||||
gboolean drop_prev = FALSE;
|
|
||||||
const gchar *cur;
|
|
||||||
const gchar *end;
|
|
||||||
const gchar *prev;
|
|
||||||
|
|
||||||
if (text == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
length = strlen (text);
|
|
||||||
|
|
||||||
str = g_string_new ("");
|
|
||||||
|
|
||||||
cur = text;
|
|
||||||
end = text + length;
|
|
||||||
prev = NULL;
|
|
||||||
|
|
||||||
while (cur != end)
|
|
||||||
{
|
|
||||||
const gchar *next;
|
|
||||||
next = g_utf8_next_char (cur);
|
|
||||||
|
|
||||||
if (prev && (*prev == '\\'))
|
|
||||||
{
|
|
||||||
switch (*cur)
|
|
||||||
{
|
|
||||||
case 'n':
|
|
||||||
str = g_string_append (str, "\n");
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
str = g_string_append (str, "\r");
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
str = g_string_append (str, "\t");
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
str = g_string_append (str, "\\");
|
|
||||||
drop_prev = TRUE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
str = g_string_append (str, "\\");
|
|
||||||
str = g_string_append_len (str, cur, next - cur);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (*cur != '\\')
|
|
||||||
{
|
|
||||||
str = g_string_append_len (str, cur, next - cur);
|
|
||||||
}
|
|
||||||
else if ((next == end) && (*cur == '\\'))
|
|
||||||
{
|
|
||||||
str = g_string_append (str, "\\");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!drop_prev)
|
|
||||||
{
|
|
||||||
prev = cur;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
prev = NULL;
|
|
||||||
drop_prev = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_string_free (str, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
xed_warning (GtkWindow *parent,
|
xed_warning (GtkWindow *parent,
|
||||||
const gchar *format,
|
const gchar *format,
|
||||||
|
|
|
@ -85,10 +85,6 @@ void xed_utils_set_atk_relation (GtkWidget *obj1,
|
||||||
GtkWidget *obj2,
|
GtkWidget *obj2,
|
||||||
AtkRelationType rel_type);
|
AtkRelationType rel_type);
|
||||||
|
|
||||||
gchar *xed_utils_escape_search_text (const gchar *text);
|
|
||||||
|
|
||||||
gchar *xed_utils_unescape_search_text (const gchar *text);
|
|
||||||
|
|
||||||
void xed_warning (GtkWindow *parent,
|
void xed_warning (GtkWindow *parent,
|
||||||
const gchar *format,
|
const gchar *format,
|
||||||
...) G_GNUC_PRINTF(2, 3);
|
...) G_GNUC_PRINTF(2, 3);
|
||||||
|
|
|
@ -55,56 +55,12 @@ document_read_only_notify_handler (XedDocument *document,
|
||||||
gtk_text_view_set_editable (GTK_TEXT_VIEW (view), !xed_document_get_readonly (document));
|
gtk_text_view_set_editable (GTK_TEXT_VIEW (view), !xed_document_get_readonly (document));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
search_highlight_updated_cb (XedDocument *doc,
|
|
||||||
GtkTextIter *start,
|
|
||||||
GtkTextIter *end,
|
|
||||||
XedView *view)
|
|
||||||
{
|
|
||||||
GdkRectangle visible_rect;
|
|
||||||
GdkRectangle updated_rect;
|
|
||||||
GdkRectangle redraw_rect;
|
|
||||||
gint y;
|
|
||||||
gint height;
|
|
||||||
GtkTextView *text_view;
|
|
||||||
|
|
||||||
text_view = GTK_TEXT_VIEW(view);
|
|
||||||
|
|
||||||
g_return_if_fail(xed_document_get_enable_search_highlighting (XED_DOCUMENT (gtk_text_view_get_buffer (text_view))));
|
|
||||||
|
|
||||||
/* get visible area */
|
|
||||||
gtk_text_view_get_visible_rect (text_view, &visible_rect);
|
|
||||||
|
|
||||||
/* get updated rectangle */
|
|
||||||
gtk_text_view_get_line_yrange (text_view, start, &y, &height);
|
|
||||||
updated_rect.y = y;
|
|
||||||
gtk_text_view_get_line_yrange (text_view, end, &y, &height);
|
|
||||||
updated_rect.height = y + height - updated_rect.y;
|
|
||||||
updated_rect.x = visible_rect.x;
|
|
||||||
updated_rect.width = visible_rect.width;
|
|
||||||
|
|
||||||
/* intersect both rectangles to see whether we need to queue a redraw */
|
|
||||||
if (gdk_rectangle_intersect (&updated_rect, &visible_rect, &redraw_rect))
|
|
||||||
{
|
|
||||||
GdkRectangle widget_rect;
|
|
||||||
gtk_text_view_buffer_to_window_coords (text_view, GTK_TEXT_WINDOW_WIDGET, redraw_rect.x, redraw_rect.y,
|
|
||||||
&widget_rect.x, &widget_rect.y);
|
|
||||||
|
|
||||||
widget_rect.width = redraw_rect.width;
|
|
||||||
widget_rect.height = redraw_rect.height;
|
|
||||||
|
|
||||||
gtk_widget_queue_draw_area (GTK_WIDGET(text_view), widget_rect.x, widget_rect.y, widget_rect.width,
|
|
||||||
widget_rect.height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
current_buffer_removed (XedView *view)
|
current_buffer_removed (XedView *view)
|
||||||
{
|
{
|
||||||
if (view->priv->current_buffer != NULL)
|
if (view->priv->current_buffer != NULL)
|
||||||
{
|
{
|
||||||
g_signal_handlers_disconnect_by_func(view->priv->current_buffer, document_read_only_notify_handler, view);
|
g_signal_handlers_disconnect_by_func(view->priv->current_buffer, document_read_only_notify_handler, view);
|
||||||
g_signal_handlers_disconnect_by_func(view->priv->current_buffer, search_highlight_updated_cb, view);
|
|
||||||
g_object_unref (view->priv->current_buffer);
|
g_object_unref (view->priv->current_buffer);
|
||||||
view->priv->current_buffer = NULL;
|
view->priv->current_buffer = NULL;
|
||||||
}
|
}
|
||||||
|
@ -136,9 +92,9 @@ on_notify_buffer_cb (XedView *view,
|
||||||
GtkTextBuffer *buffer;
|
GtkTextBuffer *buffer;
|
||||||
|
|
||||||
current_buffer_removed (view);
|
current_buffer_removed (view);
|
||||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view));
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
|
||||||
|
|
||||||
if (buffer == NULL || !XED_IS_DOCUMENT(buffer))
|
if (buffer == NULL || !XED_IS_DOCUMENT (buffer))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -146,9 +102,7 @@ on_notify_buffer_cb (XedView *view,
|
||||||
view->priv->current_buffer = g_object_ref (buffer);
|
view->priv->current_buffer = g_object_ref (buffer);
|
||||||
g_signal_connect(buffer, "notify::read-only", G_CALLBACK (document_read_only_notify_handler), view);
|
g_signal_connect(buffer, "notify::read-only", G_CALLBACK (document_read_only_notify_handler), view);
|
||||||
|
|
||||||
gtk_text_view_set_editable (GTK_TEXT_VIEW(view), !xed_document_get_readonly (XED_DOCUMENT(buffer)));
|
gtk_text_view_set_editable (GTK_TEXT_VIEW (view), !xed_document_get_readonly (XED_DOCUMENT(buffer)));
|
||||||
|
|
||||||
g_signal_connect(buffer, "search_highlight_updated", G_CALLBACK (search_highlight_updated_cb), view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -306,35 +260,6 @@ xed_view_focus_out (GtkWidget *widget,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xed_view_draw (GtkWidget *widget,
|
|
||||||
cairo_t *cr)
|
|
||||||
{
|
|
||||||
GtkTextView *text_view;
|
|
||||||
XedDocument *doc;
|
|
||||||
GdkWindow *window;
|
|
||||||
|
|
||||||
text_view = GTK_TEXT_VIEW(widget);
|
|
||||||
|
|
||||||
doc = XED_DOCUMENT(gtk_text_view_get_buffer (text_view));
|
|
||||||
window = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT);
|
|
||||||
|
|
||||||
if (gtk_cairo_should_draw_window (cr, window) && xed_document_get_enable_search_highlighting (doc))
|
|
||||||
{
|
|
||||||
GdkRectangle visible_rect;
|
|
||||||
GtkTextIter iter1, iter2;
|
|
||||||
|
|
||||||
gtk_text_view_get_visible_rect (text_view, &visible_rect);
|
|
||||||
gtk_text_view_get_line_at_y (text_view, &iter1, visible_rect.y, NULL);
|
|
||||||
gtk_text_view_get_line_at_y (text_view, &iter2, visible_rect.y + visible_rect.height, NULL);
|
|
||||||
gtk_text_iter_forward_line (&iter2);
|
|
||||||
|
|
||||||
_xed_document_search_region (doc, &iter1, &iter2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GTK_WIDGET_CLASS (xed_view_parent_class)->draw (widget, cr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GdkAtom
|
static GdkAtom
|
||||||
drag_get_uri_target (GtkWidget *widget,
|
drag_get_uri_target (GtkWidget *widget,
|
||||||
GdkDragContext *context)
|
GdkDragContext *context)
|
||||||
|
@ -615,7 +540,6 @@ xed_view_class_init (XedViewClass *klass)
|
||||||
object_class->constructed = xed_view_constructed;
|
object_class->constructed = xed_view_constructed;
|
||||||
|
|
||||||
widget_class->focus_out_event = xed_view_focus_out;
|
widget_class->focus_out_event = xed_view_focus_out;
|
||||||
widget_class->draw = xed_view_draw;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Override the gtk_text_view_drag_motion and drag_drop
|
* Override the gtk_text_view_drag_motion and drag_drop
|
||||||
|
|
|
@ -660,7 +660,7 @@ set_sensitivity_according_to_tab (XedWindow *window,
|
||||||
action = gtk_action_group_get_action (window->priv->action_group, "SearchReplace");
|
action = gtk_action_group_get_action (window->priv->action_group, "SearchReplace");
|
||||||
gtk_action_set_sensitive (action, state_normal && editable);
|
gtk_action_set_sensitive (action, state_normal && editable);
|
||||||
|
|
||||||
b = xed_document_get_can_search_again (doc);
|
b = TRUE;
|
||||||
action = gtk_action_group_get_action (window->priv->action_group, "SearchFindNext");
|
action = gtk_action_group_get_action (window->priv->action_group, "SearchFindNext");
|
||||||
gtk_action_set_sensitive (action, (state_normal || state == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
|
gtk_action_set_sensitive (action, (state_normal || state == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
|
||||||
|
|
||||||
|
@ -1715,7 +1715,7 @@ create_statusbar (XedWindow *window,
|
||||||
xed_debug (DEBUG_WINDOW);
|
xed_debug (DEBUG_WINDOW);
|
||||||
|
|
||||||
window->priv->statusbar = xed_statusbar_new ();
|
window->priv->statusbar = xed_statusbar_new ();
|
||||||
window->priv->searchbar = xed_searchbar_new (GTK_WINDOW (window), TRUE);
|
window->priv->searchbar = xed_searchbar_new (GTK_WINDOW (window));
|
||||||
|
|
||||||
window->priv->generic_message_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->priv->statusbar),
|
window->priv->generic_message_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->priv->statusbar),
|
||||||
"generic_message");
|
"generic_message");
|
||||||
|
@ -2781,9 +2781,9 @@ fullscreen_controls_build (XedWindow *window)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
can_search_again (XedDocument *doc,
|
search_text_notify_cb (XedDocument *doc,
|
||||||
GParamSpec *pspec,
|
GParamSpec *pspec,
|
||||||
XedWindow *window)
|
XedWindow *window)
|
||||||
{
|
{
|
||||||
gboolean sensitive;
|
gboolean sensitive;
|
||||||
GtkAction *action;
|
GtkAction *action;
|
||||||
|
@ -2793,7 +2793,7 @@ can_search_again (XedDocument *doc,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sensitive = xed_document_get_can_search_again (doc);
|
sensitive = TRUE;
|
||||||
|
|
||||||
action = gtk_action_group_get_action (window->priv->action_group, "SearchFindNext");
|
action = gtk_action_group_get_action (window->priv->action_group, "SearchFindNext");
|
||||||
gtk_action_set_sensitive (action, sensitive);
|
gtk_action_set_sensitive (action, sensitive);
|
||||||
|
@ -2948,7 +2948,7 @@ notebook_tab_added (XedNotebook *notebook,
|
||||||
g_signal_connect(tab, "notify::state", G_CALLBACK (sync_state), window);
|
g_signal_connect(tab, "notify::state", G_CALLBACK (sync_state), window);
|
||||||
|
|
||||||
g_signal_connect(doc, "cursor-moved", G_CALLBACK (update_cursor_position_statusbar), window);
|
g_signal_connect(doc, "cursor-moved", G_CALLBACK (update_cursor_position_statusbar), window);
|
||||||
g_signal_connect(doc, "notify::can-search-again", G_CALLBACK (can_search_again), window);
|
g_signal_connect(doc, "notify::search-text", G_CALLBACK (search_text_notify_cb), window);
|
||||||
g_signal_connect(doc, "notify::can-undo", G_CALLBACK (can_undo), window);
|
g_signal_connect(doc, "notify::can-undo", G_CALLBACK (can_undo), window);
|
||||||
g_signal_connect(doc, "notify::can-redo", G_CALLBACK (can_redo), window);
|
g_signal_connect(doc, "notify::can-redo", G_CALLBACK (can_redo), window);
|
||||||
g_signal_connect(doc, "notify::has-selection", G_CALLBACK (selection_changed), window);
|
g_signal_connect(doc, "notify::has-selection", G_CALLBACK (selection_changed), window);
|
||||||
|
@ -2986,7 +2986,7 @@ notebook_tab_removed (XedNotebook *notebook,
|
||||||
g_signal_handlers_disconnect_by_func(tab, G_CALLBACK (sync_name), window);
|
g_signal_handlers_disconnect_by_func(tab, G_CALLBACK (sync_name), window);
|
||||||
g_signal_handlers_disconnect_by_func(tab, G_CALLBACK (sync_state), window);
|
g_signal_handlers_disconnect_by_func(tab, G_CALLBACK (sync_state), window);
|
||||||
g_signal_handlers_disconnect_by_func(doc, G_CALLBACK (update_cursor_position_statusbar), window);
|
g_signal_handlers_disconnect_by_func(doc, G_CALLBACK (update_cursor_position_statusbar), window);
|
||||||
g_signal_handlers_disconnect_by_func(doc, G_CALLBACK (can_search_again), window);
|
g_signal_handlers_disconnect_by_func(doc, G_CALLBACK (search_text_notify_cb), window);
|
||||||
g_signal_handlers_disconnect_by_func(doc, G_CALLBACK (can_undo), window);
|
g_signal_handlers_disconnect_by_func(doc, G_CALLBACK (can_undo), window);
|
||||||
g_signal_handlers_disconnect_by_func(doc, G_CALLBACK (can_redo), window);
|
g_signal_handlers_disconnect_by_func(doc, G_CALLBACK (can_redo), window);
|
||||||
g_signal_handlers_disconnect_by_func(doc, G_CALLBACK (selection_changed), window);
|
g_signal_handlers_disconnect_by_func(doc, G_CALLBACK (selection_changed), window);
|
||||||
|
|
|
@ -1,646 +0,0 @@
|
||||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
|
||||||
*
|
|
||||||
* xedtextregion.h - GtkTextMark based region utility functions
|
|
||||||
*
|
|
||||||
* This file is part of the GtkSourceView widget
|
|
||||||
*
|
|
||||||
* Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "xedtextregion.h"
|
|
||||||
|
|
||||||
|
|
||||||
#undef ENABLE_DEBUG
|
|
||||||
/*
|
|
||||||
#define ENABLE_DEBUG
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef ENABLE_DEBUG
|
|
||||||
#define DEBUG(x) (x)
|
|
||||||
#else
|
|
||||||
#define DEBUG(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct _Subregion {
|
|
||||||
GtkTextMark *start;
|
|
||||||
GtkTextMark *end;
|
|
||||||
} Subregion;
|
|
||||||
|
|
||||||
struct _XedTextRegion {
|
|
||||||
GtkTextBuffer *buffer;
|
|
||||||
GList *subregions;
|
|
||||||
guint32 time_stamp;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _XedTextRegionIteratorReal XedTextRegionIteratorReal;
|
|
||||||
|
|
||||||
struct _XedTextRegionIteratorReal {
|
|
||||||
XedTextRegion *region;
|
|
||||||
guint32 region_time_stamp;
|
|
||||||
|
|
||||||
GList *subregions;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
Private interface
|
|
||||||
---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/* Find and return a subregion node which contains the given text
|
|
||||||
iter. If left_side is TRUE, return the subregion which contains
|
|
||||||
the text iter or which is the leftmost; else return the rightmost
|
|
||||||
subregion */
|
|
||||||
static GList *
|
|
||||||
find_nearest_subregion (XedTextRegion *region,
|
|
||||||
const GtkTextIter *iter,
|
|
||||||
GList *begin,
|
|
||||||
gboolean leftmost,
|
|
||||||
gboolean include_edges)
|
|
||||||
{
|
|
||||||
GList *l, *retval;
|
|
||||||
|
|
||||||
g_return_val_if_fail (region != NULL && iter != NULL, NULL);
|
|
||||||
|
|
||||||
if (!begin)
|
|
||||||
begin = region->subregions;
|
|
||||||
|
|
||||||
if (begin)
|
|
||||||
retval = begin->prev;
|
|
||||||
else
|
|
||||||
retval = NULL;
|
|
||||||
|
|
||||||
for (l = begin; l; l = l->next) {
|
|
||||||
GtkTextIter sr_iter;
|
|
||||||
Subregion *sr = l->data;
|
|
||||||
gint cmp;
|
|
||||||
|
|
||||||
if (!leftmost) {
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_iter, sr->end);
|
|
||||||
cmp = gtk_text_iter_compare (iter, &sr_iter);
|
|
||||||
if (cmp < 0 || (cmp == 0 && include_edges)) {
|
|
||||||
retval = l;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_iter, sr->start);
|
|
||||||
cmp = gtk_text_iter_compare (iter, &sr_iter);
|
|
||||||
if (cmp > 0 || (cmp == 0 && include_edges))
|
|
||||||
retval = l;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
Public interface
|
|
||||||
---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
XedTextRegion *
|
|
||||||
xed_text_region_new (GtkTextBuffer *buffer)
|
|
||||||
{
|
|
||||||
XedTextRegion *region;
|
|
||||||
|
|
||||||
g_return_val_if_fail (buffer != NULL, NULL);
|
|
||||||
|
|
||||||
region = g_new (XedTextRegion, 1);
|
|
||||||
region->buffer = buffer;
|
|
||||||
region->subregions = NULL;
|
|
||||||
region->time_stamp = 0;
|
|
||||||
|
|
||||||
return region;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
xed_text_region_destroy (XedTextRegion *region, gboolean delete_marks)
|
|
||||||
{
|
|
||||||
g_return_if_fail (region != NULL);
|
|
||||||
|
|
||||||
while (region->subregions) {
|
|
||||||
Subregion *sr = region->subregions->data;
|
|
||||||
if (delete_marks) {
|
|
||||||
gtk_text_buffer_delete_mark (region->buffer, sr->start);
|
|
||||||
gtk_text_buffer_delete_mark (region->buffer, sr->end);
|
|
||||||
}
|
|
||||||
g_free (sr);
|
|
||||||
region->subregions = g_list_delete_link (region->subregions,
|
|
||||||
region->subregions);
|
|
||||||
}
|
|
||||||
region->buffer = NULL;
|
|
||||||
region->time_stamp = 0;
|
|
||||||
|
|
||||||
g_free (region);
|
|
||||||
}
|
|
||||||
|
|
||||||
GtkTextBuffer *
|
|
||||||
xed_text_region_get_buffer (XedTextRegion *region)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (region != NULL, NULL);
|
|
||||||
|
|
||||||
return region->buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
xed_text_region_clear_zero_length_subregions (XedTextRegion *region)
|
|
||||||
{
|
|
||||||
GtkTextIter start, end;
|
|
||||||
GList *node;
|
|
||||||
|
|
||||||
g_return_if_fail (region != NULL);
|
|
||||||
|
|
||||||
for (node = region->subregions; node; ) {
|
|
||||||
Subregion *sr = node->data;
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &start, sr->start);
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &end, sr->end);
|
|
||||||
if (gtk_text_iter_equal (&start, &end)) {
|
|
||||||
gtk_text_buffer_delete_mark (region->buffer, sr->start);
|
|
||||||
gtk_text_buffer_delete_mark (region->buffer, sr->end);
|
|
||||||
g_free (sr);
|
|
||||||
if (node == region->subregions)
|
|
||||||
region->subregions = node = g_list_delete_link (node, node);
|
|
||||||
else
|
|
||||||
node = g_list_delete_link (node, node);
|
|
||||||
|
|
||||||
++region->time_stamp;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
xed_text_region_add (XedTextRegion *region,
|
|
||||||
const GtkTextIter *_start,
|
|
||||||
const GtkTextIter *_end)
|
|
||||||
{
|
|
||||||
GList *start_node, *end_node;
|
|
||||||
GtkTextIter start, end;
|
|
||||||
|
|
||||||
g_return_if_fail (region != NULL && _start != NULL && _end != NULL);
|
|
||||||
|
|
||||||
start = *_start;
|
|
||||||
end = *_end;
|
|
||||||
|
|
||||||
DEBUG (g_print ("---\n"));
|
|
||||||
DEBUG (xed_text_region_debug_print (region));
|
|
||||||
DEBUG (g_message ("region_add (%d, %d)",
|
|
||||||
gtk_text_iter_get_offset (&start),
|
|
||||||
gtk_text_iter_get_offset (&end)));
|
|
||||||
|
|
||||||
gtk_text_iter_order (&start, &end);
|
|
||||||
|
|
||||||
/* don't add zero-length regions */
|
|
||||||
if (gtk_text_iter_equal (&start, &end))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* find bounding subregions */
|
|
||||||
start_node = find_nearest_subregion (region, &start, NULL, FALSE, TRUE);
|
|
||||||
end_node = find_nearest_subregion (region, &end, start_node, TRUE, TRUE);
|
|
||||||
|
|
||||||
if (start_node == NULL || end_node == NULL || end_node == start_node->prev) {
|
|
||||||
/* create the new subregion */
|
|
||||||
Subregion *sr = g_new0 (Subregion, 1);
|
|
||||||
sr->start = gtk_text_buffer_create_mark (region->buffer, NULL, &start, TRUE);
|
|
||||||
sr->end = gtk_text_buffer_create_mark (region->buffer, NULL, &end, FALSE);
|
|
||||||
|
|
||||||
if (start_node == NULL) {
|
|
||||||
/* append the new region */
|
|
||||||
region->subregions = g_list_append (region->subregions, sr);
|
|
||||||
|
|
||||||
} else if (end_node == NULL) {
|
|
||||||
/* prepend the new region */
|
|
||||||
region->subregions = g_list_prepend (region->subregions, sr);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* we are in the middle of two subregions */
|
|
||||||
region->subregions = g_list_insert_before (region->subregions,
|
|
||||||
start_node, sr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
GtkTextIter iter;
|
|
||||||
Subregion *sr = start_node->data;
|
|
||||||
if (start_node != end_node) {
|
|
||||||
/* we need to merge some subregions */
|
|
||||||
GList *l = start_node->next;
|
|
||||||
Subregion *q;
|
|
||||||
|
|
||||||
gtk_text_buffer_delete_mark (region->buffer, sr->end);
|
|
||||||
while (l != end_node) {
|
|
||||||
q = l->data;
|
|
||||||
gtk_text_buffer_delete_mark (region->buffer, q->start);
|
|
||||||
gtk_text_buffer_delete_mark (region->buffer, q->end);
|
|
||||||
g_free (q);
|
|
||||||
l = g_list_delete_link (l, l);
|
|
||||||
}
|
|
||||||
q = l->data;
|
|
||||||
gtk_text_buffer_delete_mark (region->buffer, q->start);
|
|
||||||
sr->end = q->end;
|
|
||||||
g_free (q);
|
|
||||||
l = g_list_delete_link (l, l);
|
|
||||||
}
|
|
||||||
/* now move marks if that action expands the region */
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &iter, sr->start);
|
|
||||||
if (gtk_text_iter_compare (&iter, &start) > 0)
|
|
||||||
gtk_text_buffer_move_mark (region->buffer, sr->start, &start);
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &iter, sr->end);
|
|
||||||
if (gtk_text_iter_compare (&iter, &end) < 0)
|
|
||||||
gtk_text_buffer_move_mark (region->buffer, sr->end, &end);
|
|
||||||
}
|
|
||||||
|
|
||||||
++region->time_stamp;
|
|
||||||
|
|
||||||
DEBUG (xed_text_region_debug_print (region));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
xed_text_region_subtract (XedTextRegion *region,
|
|
||||||
const GtkTextIter *_start,
|
|
||||||
const GtkTextIter *_end)
|
|
||||||
{
|
|
||||||
GList *start_node, *end_node, *node;
|
|
||||||
GtkTextIter sr_start_iter, sr_end_iter;
|
|
||||||
gboolean done;
|
|
||||||
gboolean start_is_outside, end_is_outside;
|
|
||||||
Subregion *sr;
|
|
||||||
GtkTextIter start, end;
|
|
||||||
|
|
||||||
g_return_if_fail (region != NULL && _start != NULL && _end != NULL);
|
|
||||||
|
|
||||||
start = *_start;
|
|
||||||
end = *_end;
|
|
||||||
|
|
||||||
DEBUG (g_print ("---\n"));
|
|
||||||
DEBUG (xed_text_region_debug_print (region));
|
|
||||||
DEBUG (g_message ("region_substract (%d, %d)",
|
|
||||||
gtk_text_iter_get_offset (&start),
|
|
||||||
gtk_text_iter_get_offset (&end)));
|
|
||||||
|
|
||||||
gtk_text_iter_order (&start, &end);
|
|
||||||
|
|
||||||
/* find bounding subregions */
|
|
||||||
start_node = find_nearest_subregion (region, &start, NULL, FALSE, FALSE);
|
|
||||||
end_node = find_nearest_subregion (region, &end, start_node, TRUE, FALSE);
|
|
||||||
|
|
||||||
/* easy case first */
|
|
||||||
if (start_node == NULL || end_node == NULL || end_node == start_node->prev)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* deal with the start point */
|
|
||||||
start_is_outside = end_is_outside = FALSE;
|
|
||||||
|
|
||||||
sr = start_node->data;
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_start_iter, sr->start);
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_end_iter, sr->end);
|
|
||||||
|
|
||||||
if (gtk_text_iter_in_range (&start, &sr_start_iter, &sr_end_iter) &&
|
|
||||||
!gtk_text_iter_equal (&start, &sr_start_iter)) {
|
|
||||||
/* the starting point is inside the first subregion */
|
|
||||||
if (gtk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter) &&
|
|
||||||
!gtk_text_iter_equal (&end, &sr_end_iter)) {
|
|
||||||
/* the ending point is also inside the first
|
|
||||||
subregion: we need to split */
|
|
||||||
Subregion *new_sr = g_new0 (Subregion, 1);
|
|
||||||
new_sr->end = sr->end;
|
|
||||||
new_sr->start = gtk_text_buffer_create_mark (region->buffer,
|
|
||||||
NULL, &end, TRUE);
|
|
||||||
start_node = g_list_insert_before (start_node, start_node->next, new_sr);
|
|
||||||
|
|
||||||
sr->end = gtk_text_buffer_create_mark (region->buffer,
|
|
||||||
NULL, &start, FALSE);
|
|
||||||
|
|
||||||
/* no further processing needed */
|
|
||||||
DEBUG (g_message ("subregion splitted"));
|
|
||||||
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
/* the ending point is outside, so just move
|
|
||||||
the end of the subregion to the starting point */
|
|
||||||
gtk_text_buffer_move_mark (region->buffer, sr->end, &start);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* the starting point is outside (and so to the left)
|
|
||||||
of the first subregion */
|
|
||||||
DEBUG (g_message ("start is outside"));
|
|
||||||
|
|
||||||
start_is_outside = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deal with the end point */
|
|
||||||
if (start_node != end_node) {
|
|
||||||
sr = end_node->data;
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_start_iter, sr->start);
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_end_iter, sr->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gtk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter) &&
|
|
||||||
!gtk_text_iter_equal (&end, &sr_end_iter)) {
|
|
||||||
/* ending point is inside, move the start mark */
|
|
||||||
gtk_text_buffer_move_mark (region->buffer, sr->start, &end);
|
|
||||||
} else {
|
|
||||||
end_is_outside = TRUE;
|
|
||||||
DEBUG (g_message ("end is outside"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* finally remove any intermediate subregions */
|
|
||||||
done = FALSE;
|
|
||||||
node = start_node;
|
|
||||||
|
|
||||||
while (!done) {
|
|
||||||
if (node == end_node)
|
|
||||||
/* we are done, exit in the next iteration */
|
|
||||||
done = TRUE;
|
|
||||||
|
|
||||||
if ((node == start_node && !start_is_outside) ||
|
|
||||||
(node == end_node && !end_is_outside)) {
|
|
||||||
/* skip starting or ending node */
|
|
||||||
node = node->next;
|
|
||||||
} else {
|
|
||||||
GList *l = node->next;
|
|
||||||
sr = node->data;
|
|
||||||
gtk_text_buffer_delete_mark (region->buffer, sr->start);
|
|
||||||
gtk_text_buffer_delete_mark (region->buffer, sr->end);
|
|
||||||
g_free (sr);
|
|
||||||
region->subregions = g_list_delete_link (region->subregions,
|
|
||||||
node);
|
|
||||||
node = l;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++region->time_stamp;
|
|
||||||
|
|
||||||
DEBUG (xed_text_region_debug_print (region));
|
|
||||||
|
|
||||||
/* now get rid of empty subregions */
|
|
||||||
xed_text_region_clear_zero_length_subregions (region);
|
|
||||||
|
|
||||||
DEBUG (xed_text_region_debug_print (region));
|
|
||||||
}
|
|
||||||
|
|
||||||
gint
|
|
||||||
xed_text_region_subregions (XedTextRegion *region)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (region != NULL, 0);
|
|
||||||
|
|
||||||
return g_list_length (region->subregions);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
xed_text_region_nth_subregion (XedTextRegion *region,
|
|
||||||
guint subregion,
|
|
||||||
GtkTextIter *start,
|
|
||||||
GtkTextIter *end)
|
|
||||||
{
|
|
||||||
Subregion *sr;
|
|
||||||
|
|
||||||
g_return_val_if_fail (region != NULL, FALSE);
|
|
||||||
|
|
||||||
sr = g_list_nth_data (region->subregions, subregion);
|
|
||||||
if (sr == NULL)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (start)
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, start, sr->start);
|
|
||||||
if (end)
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, end, sr->end);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
XedTextRegion *
|
|
||||||
xed_text_region_intersect (XedTextRegion *region,
|
|
||||||
const GtkTextIter *_start,
|
|
||||||
const GtkTextIter *_end)
|
|
||||||
{
|
|
||||||
GList *start_node, *end_node, *node;
|
|
||||||
GtkTextIter sr_start_iter, sr_end_iter;
|
|
||||||
Subregion *sr, *new_sr;
|
|
||||||
gboolean done;
|
|
||||||
XedTextRegion *new_region;
|
|
||||||
GtkTextIter start, end;
|
|
||||||
|
|
||||||
g_return_val_if_fail (region != NULL && _start != NULL && _end != NULL, NULL);
|
|
||||||
|
|
||||||
start = *_start;
|
|
||||||
end = *_end;
|
|
||||||
|
|
||||||
gtk_text_iter_order (&start, &end);
|
|
||||||
|
|
||||||
/* find bounding subregions */
|
|
||||||
start_node = find_nearest_subregion (region, &start, NULL, FALSE, FALSE);
|
|
||||||
end_node = find_nearest_subregion (region, &end, start_node, TRUE, FALSE);
|
|
||||||
|
|
||||||
/* easy case first */
|
|
||||||
if (start_node == NULL || end_node == NULL || end_node == start_node->prev)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
new_region = xed_text_region_new (region->buffer);
|
|
||||||
done = FALSE;
|
|
||||||
|
|
||||||
sr = start_node->data;
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_start_iter, sr->start);
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_end_iter, sr->end);
|
|
||||||
|
|
||||||
/* starting node */
|
|
||||||
if (gtk_text_iter_in_range (&start, &sr_start_iter, &sr_end_iter)) {
|
|
||||||
new_sr = g_new0 (Subregion, 1);
|
|
||||||
new_region->subregions = g_list_prepend (new_region->subregions, new_sr);
|
|
||||||
|
|
||||||
new_sr->start = gtk_text_buffer_create_mark (new_region->buffer, NULL,
|
|
||||||
&start, TRUE);
|
|
||||||
if (start_node == end_node) {
|
|
||||||
/* things will finish shortly */
|
|
||||||
done = TRUE;
|
|
||||||
if (gtk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter))
|
|
||||||
new_sr->end = gtk_text_buffer_create_mark (new_region->buffer,
|
|
||||||
NULL, &end, FALSE);
|
|
||||||
else
|
|
||||||
new_sr->end = gtk_text_buffer_create_mark (new_region->buffer,
|
|
||||||
NULL, &sr_end_iter,
|
|
||||||
FALSE);
|
|
||||||
} else {
|
|
||||||
new_sr->end = gtk_text_buffer_create_mark (new_region->buffer, NULL,
|
|
||||||
&sr_end_iter, FALSE);
|
|
||||||
}
|
|
||||||
node = start_node->next;
|
|
||||||
} else {
|
|
||||||
/* start should be the same as the subregion, so copy it in the loop */
|
|
||||||
node = start_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!done) {
|
|
||||||
while (node != end_node) {
|
|
||||||
/* copy intermediate subregions verbatim */
|
|
||||||
sr = node->data;
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_start_iter,
|
|
||||||
sr->start);
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_end_iter, sr->end);
|
|
||||||
|
|
||||||
new_sr = g_new0 (Subregion, 1);
|
|
||||||
new_region->subregions = g_list_prepend (new_region->subregions, new_sr);
|
|
||||||
new_sr->start = gtk_text_buffer_create_mark (new_region->buffer, NULL,
|
|
||||||
&sr_start_iter, TRUE);
|
|
||||||
new_sr->end = gtk_text_buffer_create_mark (new_region->buffer, NULL,
|
|
||||||
&sr_end_iter, FALSE);
|
|
||||||
/* next node */
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ending node */
|
|
||||||
sr = node->data;
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_start_iter, sr->start);
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &sr_end_iter, sr->end);
|
|
||||||
|
|
||||||
new_sr = g_new0 (Subregion, 1);
|
|
||||||
new_region->subregions = g_list_prepend (new_region->subregions, new_sr);
|
|
||||||
|
|
||||||
new_sr->start = gtk_text_buffer_create_mark (new_region->buffer, NULL,
|
|
||||||
&sr_start_iter, TRUE);
|
|
||||||
|
|
||||||
if (gtk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter))
|
|
||||||
new_sr->end = gtk_text_buffer_create_mark (new_region->buffer, NULL,
|
|
||||||
&end, FALSE);
|
|
||||||
else
|
|
||||||
new_sr->end = gtk_text_buffer_create_mark (new_region->buffer, NULL,
|
|
||||||
&sr_end_iter, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_region->subregions = g_list_reverse (new_region->subregions);
|
|
||||||
return new_region;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
check_iterator (XedTextRegionIteratorReal *real)
|
|
||||||
{
|
|
||||||
if ((real->region == NULL) ||
|
|
||||||
(real->region_time_stamp != real->region->time_stamp))
|
|
||||||
{
|
|
||||||
g_warning("Invalid iterator: either the iterator "
|
|
||||||
"is uninitialized, or the region "
|
|
||||||
"has been modified since the iterator "
|
|
||||||
"was created.");
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
xed_text_region_get_iterator (XedTextRegion *region,
|
|
||||||
XedTextRegionIterator *iter,
|
|
||||||
guint start)
|
|
||||||
{
|
|
||||||
XedTextRegionIteratorReal *real;
|
|
||||||
|
|
||||||
g_return_if_fail (region != NULL);
|
|
||||||
g_return_if_fail (iter != NULL);
|
|
||||||
|
|
||||||
real = (XedTextRegionIteratorReal *)iter;
|
|
||||||
|
|
||||||
/* region->subregions may be NULL, -> end iter */
|
|
||||||
|
|
||||||
real->region = region;
|
|
||||||
real->subregions = g_list_nth (region->subregions, start);
|
|
||||||
real->region_time_stamp = region->time_stamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
xed_text_region_iterator_is_end (XedTextRegionIterator *iter)
|
|
||||||
{
|
|
||||||
XedTextRegionIteratorReal *real;
|
|
||||||
|
|
||||||
g_return_val_if_fail (iter != NULL, FALSE);
|
|
||||||
|
|
||||||
real = (XedTextRegionIteratorReal *)iter;
|
|
||||||
g_return_val_if_fail (check_iterator (real), FALSE);
|
|
||||||
|
|
||||||
return (real->subregions == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
xed_text_region_iterator_next (XedTextRegionIterator *iter)
|
|
||||||
{
|
|
||||||
XedTextRegionIteratorReal *real;
|
|
||||||
|
|
||||||
g_return_val_if_fail (iter != NULL, FALSE);
|
|
||||||
|
|
||||||
real = (XedTextRegionIteratorReal *)iter;
|
|
||||||
g_return_val_if_fail (check_iterator (real), FALSE);
|
|
||||||
|
|
||||||
if (real->subregions != NULL) {
|
|
||||||
real->subregions = g_list_next (real->subregions);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
xed_text_region_iterator_get_subregion (XedTextRegionIterator *iter,
|
|
||||||
GtkTextIter *start,
|
|
||||||
GtkTextIter *end)
|
|
||||||
{
|
|
||||||
XedTextRegionIteratorReal *real;
|
|
||||||
Subregion *sr;
|
|
||||||
|
|
||||||
g_return_if_fail (iter != NULL);
|
|
||||||
|
|
||||||
real = (XedTextRegionIteratorReal *)iter;
|
|
||||||
g_return_if_fail (check_iterator (real));
|
|
||||||
g_return_if_fail (real->subregions != NULL);
|
|
||||||
|
|
||||||
sr = (Subregion*)real->subregions->data;
|
|
||||||
g_return_if_fail (sr != NULL);
|
|
||||||
|
|
||||||
if (start)
|
|
||||||
gtk_text_buffer_get_iter_at_mark (real->region->buffer, start, sr->start);
|
|
||||||
if (end)
|
|
||||||
gtk_text_buffer_get_iter_at_mark (real->region->buffer, end, sr->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
xed_text_region_debug_print (XedTextRegion *region)
|
|
||||||
{
|
|
||||||
GList *l;
|
|
||||||
|
|
||||||
g_return_if_fail (region != NULL);
|
|
||||||
|
|
||||||
g_print ("Subregions: ");
|
|
||||||
l = region->subregions;
|
|
||||||
while (l) {
|
|
||||||
Subregion *sr = l->data;
|
|
||||||
GtkTextIter iter1, iter2;
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &iter1, sr->start);
|
|
||||||
gtk_text_buffer_get_iter_at_mark (region->buffer, &iter2, sr->end);
|
|
||||||
g_print ("%d-%d ", gtk_text_iter_get_offset (&iter1),
|
|
||||||
gtk_text_iter_get_offset (&iter2));
|
|
||||||
l = l->next;
|
|
||||||
}
|
|
||||||
g_print ("\n");
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
|
||||||
*
|
|
||||||
* xedtextregion.h - GtkTextMark based region utility functions
|
|
||||||
*
|
|
||||||
* This file is part of the GtkSourceView widget
|
|
||||||
*
|
|
||||||
* Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __XED_TEXT_REGION_H__
|
|
||||||
#define __XED_TEXT_REGION_H__
|
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
typedef struct _XedTextRegion XedTextRegion;
|
|
||||||
typedef struct _XedTextRegionIterator XedTextRegionIterator;
|
|
||||||
|
|
||||||
struct _XedTextRegionIterator {
|
|
||||||
/* XedTextRegionIterator is an opaque datatype; ignore all these fields.
|
|
||||||
* Initialize the iter with xed_text_region_get_iterator
|
|
||||||
* function
|
|
||||||
*/
|
|
||||||
/*< private >*/
|
|
||||||
gpointer dummy1;
|
|
||||||
guint32 dummy2;
|
|
||||||
gpointer dummy3;
|
|
||||||
};
|
|
||||||
|
|
||||||
XedTextRegion *xed_text_region_new (GtkTextBuffer *buffer);
|
|
||||||
void xed_text_region_destroy (XedTextRegion *region,
|
|
||||||
gboolean delete_marks);
|
|
||||||
|
|
||||||
GtkTextBuffer *xed_text_region_get_buffer (XedTextRegion *region);
|
|
||||||
|
|
||||||
void xed_text_region_add (XedTextRegion *region,
|
|
||||||
const GtkTextIter *_start,
|
|
||||||
const GtkTextIter *_end);
|
|
||||||
|
|
||||||
void xed_text_region_subtract (XedTextRegion *region,
|
|
||||||
const GtkTextIter *_start,
|
|
||||||
const GtkTextIter *_end);
|
|
||||||
|
|
||||||
gint xed_text_region_subregions (XedTextRegion *region);
|
|
||||||
|
|
||||||
gboolean xed_text_region_nth_subregion (XedTextRegion *region,
|
|
||||||
guint subregion,
|
|
||||||
GtkTextIter *start,
|
|
||||||
GtkTextIter *end);
|
|
||||||
|
|
||||||
XedTextRegion *xed_text_region_intersect (XedTextRegion *region,
|
|
||||||
const GtkTextIter *_start,
|
|
||||||
const GtkTextIter *_end);
|
|
||||||
|
|
||||||
void xed_text_region_get_iterator (XedTextRegion *region,
|
|
||||||
XedTextRegionIterator *iter,
|
|
||||||
guint start);
|
|
||||||
|
|
||||||
gboolean xed_text_region_iterator_is_end (XedTextRegionIterator *iter);
|
|
||||||
|
|
||||||
/* Returns FALSE if iterator is the end iterator */
|
|
||||||
gboolean xed_text_region_iterator_next (XedTextRegionIterator *iter);
|
|
||||||
|
|
||||||
void xed_text_region_iterator_get_subregion (XedTextRegionIterator *iter,
|
|
||||||
GtkTextIter *start,
|
|
||||||
GtkTextIter *end);
|
|
||||||
|
|
||||||
void xed_text_region_debug_print (XedTextRegion *region);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* __XED_TEXT_REGION_H__ */
|
|
Loading…
Reference in New Issue