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.
|
||||
IGNORE_HFILES += \
|
||||
bacon-message-connection.h \
|
||||
xedtextregion.h \
|
||||
sexy-icon-entry.h
|
||||
|
||||
# Images to copy into HTML directory.
|
||||
|
|
|
@ -36,7 +36,6 @@ xed_app_activatable_get_type
|
|||
|
||||
<SECTION>
|
||||
<FILE>xed-document</FILE>
|
||||
XedSearchFlags
|
||||
XedDocumentPrivate
|
||||
<TITLE>XedDocument</TITLE>
|
||||
XedDocument
|
||||
|
@ -58,21 +57,7 @@ xed_document_is_untouched
|
|||
xed_document_is_untitled
|
||||
xed_document_get_deleted
|
||||
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_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>
|
||||
XED_DOCUMENT
|
||||
XED_IS_DOCUMENT
|
||||
|
@ -517,8 +502,6 @@ g_utf8_caselessnmatch
|
|||
xed_utils_set_atk_name_description
|
||||
xed_utils_set_atk_relation
|
||||
xed_utils_uri_exists
|
||||
xed_utils_escape_search_text
|
||||
xed_utils_unescape_search_text
|
||||
xed_utils_get_stdin
|
||||
xed_warning
|
||||
xed_utils_make_valid_utf8
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <xed/xed-debug.h>
|
||||
#include <xed/xed-statusbar.h>
|
||||
#include <xed/xed-utils.h>
|
||||
#include <gtksourceview/gtksource.h>
|
||||
|
||||
#include "xed-spell-checker.h"
|
||||
#include "xed-spell-checker-dialog.h"
|
||||
|
@ -704,7 +705,8 @@ change_all_cb (XedSpellCheckerDialog *dlg,
|
|||
CheckRange *range;
|
||||
gchar *w = NULL;
|
||||
GtkTextIter start, end;
|
||||
gint flags = 0;
|
||||
GtkSourceSearchSettings *search_settings;
|
||||
GtkSourceSearchContext *search_context;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
|
@ -739,16 +741,24 @@ change_all_cb (XedSpellCheckerDialog *dlg,
|
|||
|
||||
g_free (w);
|
||||
|
||||
XED_SEARCH_SET_CASE_SENSITIVE (flags, TRUE);
|
||||
XED_SEARCH_SET_ENTIRE_WORD (flags, TRUE);
|
||||
search_settings = gtk_source_search_settings_new ();
|
||||
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 */
|
||||
xed_document_replace_all (doc, word, change, flags);
|
||||
search_context = gtk_source_search_context_new (GTK_SOURCE_BUFFER (doc), search_settings);
|
||||
|
||||
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));
|
||||
|
||||
/* go to next misspelled word */
|
||||
ignore_cb (dlg, word, view);
|
||||
|
||||
g_object_unref (search_settings);
|
||||
g_object_unref (search_context);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "xed-spell-utils.h"
|
||||
#include <gtksourceview/gtksourcebuffer.h>
|
||||
#include <gtksourceview/gtksource.h>
|
||||
|
||||
gboolean
|
||||
xed_spell_utils_is_digit (const char *text, gssize length)
|
||||
|
|
|
@ -60,7 +60,6 @@ NOINST_H_FILES = \
|
|||
xed-settings.h \
|
||||
xed-status-combo-box.h \
|
||||
xed-tab-label.h \
|
||||
xedtextregion.h \
|
||||
xed-ui.h \
|
||||
xed-utils.h \
|
||||
xed-view-frame.h \
|
||||
|
@ -146,8 +145,7 @@ libxed_c_files = \
|
|||
xed-view-activatable.c \
|
||||
xed-view-frame.c \
|
||||
xed-window.c \
|
||||
xed-window-activatable.c \
|
||||
xedtextregion.c
|
||||
xed-window-activatable.c
|
||||
|
||||
libxed_la_SOURCES = \
|
||||
$(BUILT_SOURCES) \
|
||||
|
|
|
@ -14,18 +14,25 @@
|
|||
#include "xed-searchbar.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
|
||||
_xed_cmd_search_find (GtkAction *action,
|
||||
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
|
||||
_xed_cmd_search_replace (GtkAction *action,
|
||||
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
|
||||
|
@ -54,7 +61,7 @@ _xed_cmd_search_clear_highlight (XedWindow *window)
|
|||
doc = xed_window_get_active_document (window);
|
||||
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-marshal.h"
|
||||
#include "xed-enum-types.h"
|
||||
#include "xedtextregion.h"
|
||||
|
||||
#ifndef ENABLE_GVFS_METADATA
|
||||
#include "xed-metadata-manager.h"
|
||||
|
@ -86,14 +85,6 @@ static void xed_document_save_real (XedDocument *doc,
|
|||
GFile *location,
|
||||
const XedEncoding *encoding,
|
||||
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
|
||||
{
|
||||
|
@ -113,9 +104,7 @@ struct _XedDocumentPrivate
|
|||
GTimeVal mtime;
|
||||
GTimeVal time_of_last_save_or_load;
|
||||
|
||||
guint search_flags;
|
||||
gchar *search_text;
|
||||
gint num_of_lines_search_text;
|
||||
GtkSourceSearchContext *search_context;
|
||||
|
||||
XedDocumentNewlineType newline_type;
|
||||
|
||||
|
@ -129,10 +118,6 @@ struct _XedDocumentPrivate
|
|||
/* Saving stuff */
|
||||
XedDocumentSaver *saver;
|
||||
|
||||
/* Search highlighting support variables */
|
||||
XedTextRegion *to_search_region;
|
||||
GtkTextTag *found_tag;
|
||||
|
||||
GtkTextTag *error_tag;
|
||||
|
||||
/* Mount operation factory */
|
||||
|
@ -158,8 +143,6 @@ enum
|
|||
PROP_MIME_TYPE,
|
||||
PROP_READ_ONLY,
|
||||
PROP_ENCODING,
|
||||
PROP_CAN_SEARCH_AGAIN,
|
||||
PROP_ENABLE_SEARCH_HIGHLIGHTING,
|
||||
PROP_NEWLINE_TYPE
|
||||
};
|
||||
|
||||
|
@ -172,7 +155,6 @@ enum
|
|||
SAVE,
|
||||
SAVING,
|
||||
SAVED,
|
||||
SEARCH_HIGHLIGHT_UPDATED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
@ -284,6 +266,7 @@ xed_document_dispose (GObject *object)
|
|||
g_clear_object (&doc->priv->editor_settings);
|
||||
g_clear_object (&doc->priv->metadata_info);
|
||||
g_clear_object (&doc->priv->location);
|
||||
g_clear_object (&doc->priv->search_context);
|
||||
|
||||
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->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);
|
||||
}
|
||||
|
@ -342,12 +318,6 @@ xed_document_get_property (GObject *object,
|
|||
case PROP_ENCODING:
|
||||
g_value_set_boxed (value, doc->priv->encoding);
|
||||
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:
|
||||
g_value_set_enum (value, doc->priv->newline_type);
|
||||
break;
|
||||
|
@ -386,9 +356,6 @@ xed_document_set_property (GObject *object,
|
|||
case PROP_CONTENT_TYPE:
|
||||
xed_document_set_content_type (doc, g_value_get_string (value));
|
||||
break;
|
||||
case PROP_ENABLE_SEARCH_HIGHLIGHTING:
|
||||
xed_document_set_enable_search_highlighting (doc, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_NEWLINE_TYPE:
|
||||
xed_document_set_newline_type (doc, g_value_get_enum (value));
|
||||
break;
|
||||
|
@ -498,22 +465,6 @@ xed_document_class_init (XedDocumentClass *klass)
|
|||
G_PARAM_READABLE |
|
||||
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:
|
||||
*
|
||||
|
@ -643,18 +594,6 @@ xed_document_class_init (XedDocumentClass *klass)
|
|||
1,
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -925,20 +864,12 @@ xed_document_init (XedDocument *doc)
|
|||
"highlight-matching-brackets",
|
||||
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);
|
||||
if (style_scheme != NULL)
|
||||
{
|
||||
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::location", G_CALLBACK (on_location_changed), NULL);
|
||||
}
|
||||
|
@ -1807,448 +1738,6 @@ xed_document_goto_line_offset (XedDocument *doc,
|
|||
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
|
||||
get_style_colors (XedDocument *doc,
|
||||
const gchar *style_name,
|
||||
|
@ -2393,14 +1882,6 @@ sync_tag_style (XedDocument *doc,
|
|||
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
|
||||
text_tag_set_highest_priority (GtkTextTag *tag,
|
||||
GtkTextBuffer *buffer)
|
||||
|
@ -2413,200 +1894,6 @@ text_tag_set_highest_priority (GtkTextTag *tag,
|
|||
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:
|
||||
* @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);
|
||||
}
|
||||
|
||||
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
|
||||
xed_document_set_newline_type (XedDocument *doc,
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
* @XED_DOCUMENT_SAVE_IGNORE_MTIME: save file despite external modifications.
|
||||
|
@ -142,11 +133,6 @@ struct _XedDocumentClass
|
|||
|
||||
void (* saved) (XedDocument *document,
|
||||
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_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,
|
||||
GtkSourceLanguage *lang);
|
||||
GtkSourceLanguage
|
||||
|
@ -258,13 +217,6 @@ GtkSourceLanguage
|
|||
const XedEncoding
|
||||
*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,
|
||||
XedDocumentNewlineType newline_type);
|
||||
|
||||
|
@ -299,27 +251,6 @@ void _xed_document_apply_error_style (XedDocument *doc,
|
|||
gboolean _xed_document_check_externally_modified
|
||||
(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,
|
||||
gpointer userdata);
|
||||
|
||||
|
@ -331,6 +262,11 @@ GMountOperation
|
|||
*_xed_document_create_mount_operation
|
||||
(XedDocument *doc);
|
||||
|
||||
void _xed_document_set_search_context (XedDocument *doc,
|
||||
GtkSourceSearchContext *search_context);
|
||||
|
||||
GtkSourceSearchContext *_xed_document_get_search_context (XedDocument *doc);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_DOCUMENT_H__ */
|
||||
|
|
|
@ -516,54 +516,3 @@ xed_history_entry_get_entry (XedHistoryEntry *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);
|
||||
|
||||
typedef gchar * (* XedHistoryEntryEscapeFunc) (const gchar *str);
|
||||
void xed_history_entry_set_escape_func (XedHistoryEntry *entry,
|
||||
XedHistoryEntryEscapeFunc escape_func);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#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))
|
||||
|
||||
/* Signals */
|
||||
// typedef enum
|
||||
// {
|
||||
// SEARCH,
|
||||
// REPLACE
|
||||
// } SearchMode;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
SHOW_REPLACE,
|
||||
|
@ -37,6 +43,7 @@ struct _XedSearchbarPrivate
|
|||
GtkWidget *replace_label;
|
||||
GtkWidget *replace_entry;
|
||||
GtkWidget *replace_text_entry;
|
||||
GtkWidget *regex_checkbutton;
|
||||
GtkWidget *match_case_checkbutton;
|
||||
GtkWidget *entire_word_checkbutton;
|
||||
GtkWidget *wrap_around_checkbutton;
|
||||
|
@ -45,15 +52,38 @@ struct _XedSearchbarPrivate
|
|||
GtkWidget *replace_button;
|
||||
GtkWidget *replace_all_button;
|
||||
GtkWidget *close_button;
|
||||
|
||||
GtkSourceSearchSettings *search_settings;
|
||||
SearchMode search_mode;
|
||||
|
||||
guint update_occurrence_count_id;
|
||||
};
|
||||
|
||||
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
|
||||
xed_searchbar_class_init (XedSearchbarClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = xed_searchbar_dispose;
|
||||
|
||||
g_type_class_add_private (object_class, sizeof(XedSearchbarPrivate));
|
||||
}
|
||||
|
||||
|
@ -91,130 +121,285 @@ text_found (XedWindow *window,
|
|||
}
|
||||
|
||||
static void
|
||||
text_not_found (XedWindow *window,
|
||||
const gchar *text)
|
||||
text_not_found (XedSearchbar *searchbar)
|
||||
{
|
||||
gchar *searched;
|
||||
const gchar *search_text;
|
||||
gchar *truncated_text;
|
||||
|
||||
searched = xed_utils_str_end_truncate (text, MAX_MSG_LENGTH);
|
||||
xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
|
||||
window->priv->generic_message_cid,
|
||||
_("\"%s\" not found"), searched);
|
||||
g_free (searched);
|
||||
search_text = xed_searchbar_get_search_text (searchbar);
|
||||
truncated_text = xed_utils_str_end_truncate (search_text, MAX_MSG_LENGTH);
|
||||
|
||||
xed_statusbar_flash_message (XED_STATUSBAR (searchbar->window->priv->statusbar),
|
||||
searchbar->window->priv->generic_message_cid,
|
||||
_("\"%s\" not found"), truncated_text);
|
||||
|
||||
g_free (truncated_text);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
run_search (XedView *view,
|
||||
gboolean wrap_around,
|
||||
gboolean search_backwards,
|
||||
gboolean jump_to_next_result)
|
||||
forward_search_finished (GtkSourceSearchContext *search_context,
|
||||
GAsyncResult *result,
|
||||
XedView *view)
|
||||
{
|
||||
XedDocument *doc;
|
||||
GtkTextIter start_iter;
|
||||
GtkTextIter end_iter;
|
||||
gboolean found;
|
||||
GtkSourceBuffer *buffer;
|
||||
GtkTextIter match_start;
|
||||
GtkTextIter match_end;
|
||||
gboolean found = FALSE;
|
||||
|
||||
doc = XED_DOCUMENT(gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
|
||||
gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), &start_iter, &end_iter);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
found = gtk_source_search_context_forward_finish (search_context, result, &match_start, &match_end, NULL);
|
||||
buffer = gtk_source_search_context_get_buffer (search_context);
|
||||
|
||||
if (found)
|
||||
{
|
||||
gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &match_start);
|
||||
gtk_text_buffer_move_mark_by_name (GTK_TEXT_BUFFER (doc), "selection_bound", &match_end);
|
||||
gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), &match_start, &match_end);
|
||||
xed_view_scroll_to_cursor (view);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
do_find (XedSearchbar *searchbar,
|
||||
gboolean search_backwards,
|
||||
gboolean jump_to_next_result)
|
||||
{
|
||||
XedView *active_view;
|
||||
XedDocument *doc;
|
||||
gchar *search_text;
|
||||
const gchar *entry_text;
|
||||
gboolean match_case;
|
||||
gboolean entire_word;
|
||||
gboolean wrap_around;
|
||||
guint flags = 0;
|
||||
guint old_flags = 0;
|
||||
gboolean found;
|
||||
GtkSourceSearchContext *search_context;
|
||||
GtkSourceSearchSettings *search_settings;
|
||||
|
||||
/* TODO: make the searchbar insensitive when all the tabs are closed
|
||||
* and assert here that the view is not NULL */
|
||||
active_view = xed_window_get_active_view (searchbar->window);
|
||||
if (active_view == NULL)
|
||||
search_settings = xed_searchbar_get_search_settings (searchbar);
|
||||
doc = xed_window_get_active_document (searchbar->window);
|
||||
search_context = _xed_document_get_search_context (doc);
|
||||
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)));
|
||||
|
||||
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))
|
||||
if (search_backwards)
|
||||
{
|
||||
xed_document_set_search_text (doc, entry_text, flags);
|
||||
}
|
||||
|
||||
g_free (search_text);
|
||||
|
||||
found = run_search (active_view, wrap_around, search_backwards, jump_to_next_result);
|
||||
|
||||
if (found)
|
||||
{
|
||||
text_found (searchbar->window, 0);
|
||||
run_backward_search (searchbar->window);
|
||||
}
|
||||
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,
|
||||
gboolean backward)
|
||||
{
|
||||
XedView *active_view;
|
||||
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)
|
||||
if (backward)
|
||||
{
|
||||
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
|
||||
|
@ -279,69 +457,45 @@ get_selected_text (GtkTextBuffer *doc,
|
|||
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
|
||||
do_replace (XedSearchbar *searchbar)
|
||||
{
|
||||
XedDocument *doc;
|
||||
const gchar *search_entry_text;
|
||||
GtkSourceSearchContext *search_context;
|
||||
const gchar *replace_entry_text;
|
||||
gchar *unescaped_search_text;
|
||||
gchar *unescaped_replace_text;
|
||||
gchar *selected_text = NULL;
|
||||
gboolean match_case;
|
||||
GtkTextIter start;
|
||||
GtkTextIter end;
|
||||
|
||||
doc = xed_window_get_active_document (searchbar->window);
|
||||
|
||||
if (doc == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
search_entry_text = xed_searchbar_get_search_text (searchbar);
|
||||
g_return_if_fail ((search_entry_text) != NULL);
|
||||
g_return_if_fail ((*search_entry_text) != '\0');
|
||||
search_context = _xed_document_get_search_context (doc);
|
||||
|
||||
if (search_context == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* replace text may be "", we just delete */
|
||||
replace_entry_text = xed_searchbar_get_replace_text (searchbar);
|
||||
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);
|
||||
|
||||
do_find (searchbar, FALSE, TRUE);
|
||||
|
@ -350,38 +504,35 @@ do_replace (XedSearchbar *searchbar)
|
|||
static void
|
||||
do_replace_all (XedSearchbar *searchbar)
|
||||
{
|
||||
XedView *active_view;
|
||||
XedDocument *doc;
|
||||
const gchar *search_entry_text;
|
||||
GtkSourceSearchContext *search_context;
|
||||
const gchar *replace_entry_text;
|
||||
gboolean match_case;
|
||||
gboolean entire_word;
|
||||
guint flags = 0;
|
||||
gchar *unescaped_replace_text;
|
||||
gint count;
|
||||
|
||||
active_view = xed_window_get_active_view (searchbar->window);
|
||||
if (active_view == NULL)
|
||||
doc = xed_window_get_active_document (searchbar->window);
|
||||
|
||||
if (doc == NULL)
|
||||
{
|
||||
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);
|
||||
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 all occurrences */
|
||||
replace_entry_text = xed_searchbar_get_replace_text (searchbar);
|
||||
g_return_if_fail ((replace_entry_text) != NULL);
|
||||
|
||||
match_case = xed_searchbar_get_match_case (searchbar);
|
||||
entire_word = xed_searchbar_get_entire_word (searchbar);
|
||||
unescaped_replace_text = gtk_source_utils_unescape_search_text (replace_entry_text);
|
||||
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);
|
||||
XED_SEARCH_SET_ENTIRE_WORD (flags, entire_word);
|
||||
|
||||
count = xed_document_replace_all (doc, search_entry_text, replace_entry_text, flags);
|
||||
g_free (unescaped_replace_text);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
|
@ -389,49 +540,11 @@ do_replace_all (XedSearchbar *searchbar)
|
|||
}
|
||||
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
|
||||
search_text_entry_changed (GtkEditable *editable,
|
||||
XedSearchbar *searchbar)
|
||||
|
@ -444,26 +557,38 @@ search_text_entry_changed (GtkEditable *editable,
|
|||
if (*search_string != '\0')
|
||||
{
|
||||
search_buttons_set_sensitive (searchbar, TRUE);
|
||||
do_find (searchbar, FALSE, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
remember_search_entry (XedSearchbar *searchbar)
|
||||
{
|
||||
const gchar *str;
|
||||
|
||||
str = gtk_entry_get_text (GTK_ENTRY(searchbar->priv->search_text_entry));
|
||||
if (*str != '\0')
|
||||
{
|
||||
gchar *text;
|
||||
text = xed_utils_unescape_search_text (str);
|
||||
xed_history_entry_prepend_text (XED_HISTORY_ENTRY(searchbar->priv->search_entry), text);
|
||||
g_free (text);
|
||||
xed_history_entry_prepend_text (XED_HISTORY_ENTRY (searchbar->priv->search_entry), str);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -471,13 +596,11 @@ static void
|
|||
remember_replace_entry (XedSearchbar *searchbar)
|
||||
{
|
||||
const gchar *str;
|
||||
|
||||
str = gtk_entry_get_text (GTK_ENTRY(searchbar->priv->replace_text_entry));
|
||||
if (*str != '\0')
|
||||
{
|
||||
gchar *text;
|
||||
text = xed_utils_unescape_search_text (str);
|
||||
xed_history_entry_prepend_text (XED_HISTORY_ENTRY(searchbar->priv->replace_entry), text);
|
||||
g_free (text);
|
||||
xed_history_entry_prepend_text (XED_HISTORY_ENTRY(searchbar->priv->replace_entry), str);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,6 +684,7 @@ xed_searchbar_init (XedSearchbar *searchbar)
|
|||
"grid", &searchbar->priv->grid,
|
||||
"search_label", &searchbar->priv->search_label,
|
||||
"replace_with_label", &searchbar->priv->replace_label,
|
||||
"regex_checkbutton", &searchbar->priv->regex_checkbutton,
|
||||
"match_case_checkbutton", &searchbar->priv->match_case_checkbutton,
|
||||
"entire_word_checkbutton", &searchbar->priv->entire_word_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");
|
||||
|
||||
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);
|
||||
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));
|
||||
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_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);
|
||||
xed_history_entry_set_escape_func (XED_HISTORY_ENTRY (searchbar->priv->replace_entry),
|
||||
(XedHistoryEntryEscapeFunc) xed_utils_escape_search_text);
|
||||
searchbar->priv->replace_entry = xed_history_entry_new ("history-replace-with", FALSE);
|
||||
|
||||
searchbar->priv->replace_text_entry = xed_history_entry_get_entry (
|
||||
XED_HISTORY_ENTRY (searchbar->priv->replace_entry));
|
||||
|
@ -620,12 +740,6 @@ xed_searchbar_init (XedSearchbar *searchbar)
|
|||
|
||||
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_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_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 *
|
||||
xed_searchbar_new (GtkWindow *parent,
|
||||
gboolean show_replace)
|
||||
xed_searchbar_new (GtkWindow *parent)
|
||||
{
|
||||
XedSearchbar *searchbar;
|
||||
|
||||
searchbar = g_object_new (XED_TYPE_SEARCHBAR, NULL);
|
||||
searchbar->window = XED_WINDOW (parent);
|
||||
|
||||
return GTK_WIDGET (searchbar);
|
||||
}
|
||||
|
||||
void
|
||||
xed_searchbar_show (XedSearchbar *searchbar,
|
||||
gboolean show_replace)
|
||||
SearchMode search_mode)
|
||||
{
|
||||
XedDocument *doc;
|
||||
gboolean selection_exists;
|
||||
gchar *find_text = NULL;
|
||||
const gchar *search_text = NULL;
|
||||
gint sel_len;
|
||||
gint sel_len = 0;
|
||||
|
||||
doc = xed_window_get_active_document (searchbar->window);
|
||||
g_return_if_fail (doc != NULL);
|
||||
|
@ -682,28 +814,28 @@ xed_searchbar_show (XedSearchbar *searchbar,
|
|||
|
||||
if (selection_exists && find_text != NULL && sel_len < 80)
|
||||
{
|
||||
/*
|
||||
* Special case: if the currently selected text
|
||||
* is the same as the unescaped search text, use the
|
||||
* 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)))
|
||||
gchar *escaped_find_text;
|
||||
|
||||
if (gtk_source_search_settings_get_regex_enabled (searchbar->priv->search_settings))
|
||||
{
|
||||
/* General case */
|
||||
xed_searchbar_set_search_text (XED_SEARCHBAR (searchbar), find_text);
|
||||
escaped_find_text = g_regex_escape_string (find_text, -1);
|
||||
}
|
||||
g_free (find_text);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_free (find_text);
|
||||
else
|
||||
{
|
||||
escaped_find_text = gtk_source_utils_escape_search_text (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_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_entry);
|
||||
|
@ -734,6 +866,7 @@ xed_searchbar_hide (XedSearchbar *searchbar)
|
|||
|
||||
// focus document
|
||||
active_view = xed_window_get_active_view (searchbar->window);
|
||||
|
||||
if (active_view != NULL)
|
||||
{
|
||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||
|
@ -743,84 +876,35 @@ xed_searchbar_hide (XedSearchbar *searchbar)
|
|||
_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 *
|
||||
xed_searchbar_get_replace_text (XedSearchbar *searchbar)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), NULL);
|
||||
|
||||
return gtk_entry_get_text (GTK_ENTRY (searchbar->priv->replace_text_entry));
|
||||
}
|
||||
|
||||
void
|
||||
xed_searchbar_set_match_case (XedSearchbar *searchbar,
|
||||
gboolean match_case)
|
||||
GtkSourceSearchSettings *
|
||||
xed_searchbar_get_search_settings (XedSearchbar *searchbar)
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCHBAR (searchbar));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (searchbar->priv->match_case_checkbutton), match_case);
|
||||
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), NULL);
|
||||
|
||||
return searchbar->priv->search_settings;
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_searchbar_get_match_case (XedSearchbar *searchbar)
|
||||
const gchar *
|
||||
xed_searchbar_get_search_text (XedSearchbar *searchbar)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_SEARCHBAR (searchbar), FALSE);
|
||||
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (searchbar->priv->match_case_checkbutton));
|
||||
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_entire_word (XedSearchbar *searchbar,
|
||||
gboolean entire_word)
|
||||
xed_searchbar_set_search_text (XedSearchbar *searchbar,
|
||||
const gchar *search_text)
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCHBAR (searchbar));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (searchbar->priv->entire_word_checkbutton), entire_word);
|
||||
}
|
||||
|
||||
gboolean
|
||||
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));
|
||||
gtk_entry_set_text (GTK_ENTRY (searchbar->priv->search_text_entry), search_text);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#define __XED_SEARCHBAR_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gtksourceview/gtksource.h>
|
||||
#include "xed-window.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
@ -36,38 +37,29 @@ struct _XedSearchbarClass
|
|||
gboolean (* show_replace) (XedSearchbar *dlg);
|
||||
};
|
||||
|
||||
enum
|
||||
typedef enum
|
||||
{
|
||||
XED_SEARCHBAR_FIND_RESPONSE = 100,
|
||||
XED_SEARCHBAR_REPLACE_RESPONSE,
|
||||
XED_SEARCHBAR_REPLACE_ALL_RESPONSE
|
||||
};
|
||||
SEARCH_MODE_SEARCH,
|
||||
SEARCH_MODE_REPLACE
|
||||
} SearchMode;
|
||||
|
||||
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_show (XedSearchbar *searchbar, gboolean show_replace);
|
||||
void xed_searchbar_find_again (XedSearchbar *searchbar, gboolean backward);
|
||||
void xed_searchbar_show (XedSearchbar *searchbar, SearchMode search_mode);
|
||||
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_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);
|
||||
|
||||
void xed_searchbar_set_wrap_around (XedSearchbar *searchbar, gboolean wrap_around);
|
||||
gboolean xed_searchbar_get_wrap_around (XedSearchbar *searchbar);
|
||||
GtkSourceSearchSettings *xed_searchbar_get_search_settings (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);
|
||||
gboolean xed_searchbar_get_parse_escapes (XedSearchbar *searchbar);
|
||||
|
|
|
@ -112,6 +112,26 @@
|
|||
<object class="GtkBox" id="box1">
|
||||
<property name="visible">True</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>
|
||||
<object class="GtkToggleButton" id="match_case_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
|
@ -130,7 +150,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -151,7 +171,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -172,7 +192,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
|
|
137
xed/xed-utils.c
137
xed/xed-utils.c
|
@ -44,6 +44,7 @@
|
|||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gtksourceview/gtksource.h>
|
||||
|
||||
#include "xed-utils.h"
|
||||
|
||||
|
@ -276,142 +277,6 @@ xed_utils_set_atk_relation (GtkWidget *obj1,
|
|||
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
|
||||
xed_warning (GtkWindow *parent,
|
||||
const gchar *format,
|
||||
|
|
|
@ -85,10 +85,6 @@ void xed_utils_set_atk_relation (GtkWidget *obj1,
|
|||
GtkWidget *obj2,
|
||||
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,
|
||||
const gchar *format,
|
||||
...) 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));
|
||||
}
|
||||
|
||||
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
|
||||
current_buffer_removed (XedView *view)
|
||||
{
|
||||
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, search_highlight_updated_cb, view);
|
||||
g_object_unref (view->priv->current_buffer);
|
||||
view->priv->current_buffer = NULL;
|
||||
}
|
||||
|
@ -136,9 +92,9 @@ on_notify_buffer_cb (XedView *view,
|
|||
GtkTextBuffer *buffer;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -146,9 +102,7 @@ on_notify_buffer_cb (XedView *view,
|
|||
view->priv->current_buffer = g_object_ref (buffer);
|
||||
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)));
|
||||
|
||||
g_signal_connect(buffer, "search_highlight_updated", G_CALLBACK (search_highlight_updated_cb), view);
|
||||
gtk_text_view_set_editable (GTK_TEXT_VIEW (view), !xed_document_get_readonly (XED_DOCUMENT(buffer)));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -306,35 +260,6 @@ xed_view_focus_out (GtkWidget *widget,
|
|||
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
|
||||
drag_get_uri_target (GtkWidget *widget,
|
||||
GdkDragContext *context)
|
||||
|
@ -615,7 +540,6 @@ xed_view_class_init (XedViewClass *klass)
|
|||
object_class->constructed = xed_view_constructed;
|
||||
|
||||
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
|
||||
|
|
|
@ -660,7 +660,7 @@ set_sensitivity_according_to_tab (XedWindow *window,
|
|||
action = gtk_action_group_get_action (window->priv->action_group, "SearchReplace");
|
||||
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");
|
||||
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);
|
||||
|
||||
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),
|
||||
"generic_message");
|
||||
|
@ -2781,9 +2781,9 @@ fullscreen_controls_build (XedWindow *window)
|
|||
}
|
||||
|
||||
static void
|
||||
can_search_again (XedDocument *doc,
|
||||
GParamSpec *pspec,
|
||||
XedWindow *window)
|
||||
search_text_notify_cb (XedDocument *doc,
|
||||
GParamSpec *pspec,
|
||||
XedWindow *window)
|
||||
{
|
||||
gboolean sensitive;
|
||||
GtkAction *action;
|
||||
|
@ -2793,7 +2793,7 @@ can_search_again (XedDocument *doc,
|
|||
return;
|
||||
}
|
||||
|
||||
sensitive = xed_document_get_can_search_again (doc);
|
||||
sensitive = TRUE;
|
||||
|
||||
action = gtk_action_group_get_action (window->priv->action_group, "SearchFindNext");
|
||||
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(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-redo", G_CALLBACK (can_redo), 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_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 (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_redo), 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