Merging search-regex branch

svn merge -r 893:900 svn+ssh://svn.berlios.de/svnroot/repos/ggap/moo/branches/search-regex
master
Yevgen Muntyan 2005-11-14 03:08:24 +00:00
parent f4a2e8a2f3
commit e05a644874
28 changed files with 2643 additions and 2459 deletions

View File

@ -12,6 +12,7 @@ Editor
Terminal
========
0. FIX IT!
1. Think about profiles, can they help?
2. Terminal settings.

View File

@ -11,8 +11,8 @@ mooedit_srcdir = $(srcdir)/$(mooedit)
mooedit_glade = $(mooedit)/glade
moo_extra_dist += \
$(mooedit_glade)/mooeditgotoline.glade \
$(mooedit_glade)/mooeditfind.glade \
$(mooedit_glade)/mootextgotoline.glade \
$(mooedit_glade)/mootextfind.glade \
$(mooedit_glade)/mooeditprefs.glade \
$(mooedit_glade)/mooeditcolorsprefs.glade \
$(mooedit_glade)/moopluginprefs.glade
@ -86,7 +86,7 @@ mooedit_include_headers = \
$(mooedit)/mooedit.h \
$(mooedit)/mooeditor.h \
$(mooedit)/mooeditprefs.h \
$(mooedit)/mooeditsearch.h \
$(mooedit)/mootextsearch.h \
$(mooedit)/mooeditwindow.h \
$(mooedit)/mooindenter.h \
$(mooedit)/moolang.h \
@ -106,8 +106,6 @@ mooedit_noinst_headers = \
$(mooedit)/mooeditcolorsprefs-glade.h \
$(mooedit)/mooeditdialogs.h \
$(mooedit)/mooeditfileops.h \
$(mooedit)/mooeditfind-glade.h \
$(mooedit)/mooeditgotoline-glade.h \
$(mooedit)/mooeditprefs-glade.h \
$(mooedit)/moohighlighter.h \
$(mooedit)/moolang-aux.h \
@ -116,6 +114,9 @@ mooedit_noinst_headers = \
$(mooedit)/moolang-strings.h \
$(mooedit)/moolinebuffer.h \
$(mooedit)/moopluginprefs-glade.h \
$(mooedit)/mootextfind-glade.h \
$(mooedit)/mootextfind.h \
$(mooedit)/mootextgotoline-glade.h \
$(mooedit)/mootextbtree.h \
$(mooedit)/mootextview-private.h
@ -128,12 +129,12 @@ mooedit_sources = \
$(mooedit)/mooedit.c \
$(mooedit)/mooeditdialogs.c \
$(mooedit)/mooeditfileops.c \
$(mooedit)/mooeditfind.c \
$(mooedit)/mootextfind.c \
$(mooedit)/mooeditinput.c \
$(mooedit)/mooeditor.c \
$(mooedit)/mooeditprefs.c \
$(mooedit)/mooeditprefspage.c \
$(mooedit)/mooeditsearch.c \
$(mooedit)/mootextsearch.c \
$(mooedit)/mooeditwindow.c \
$(mooedit)/moohighlighter.c \
$(mooedit)/mooindenter.c \
@ -151,20 +152,20 @@ mooedit_sources = \
$(mooedit)/mootextview.c
mooedit_built_sources = \
$(mooedit)/mooeditgotoline-glade.h \
$(mooedit)/mooeditfind-glade.h \
$(mooedit)/mootextgotoline-glade.h \
$(mooedit)/mootextfind-glade.h \
$(mooedit)/moopluginprefs-glade.h \
$(mooedit)/mooeditprefs-glade.h \
$(mooedit)/mooeditcolorsprefs-glade.h
$(mooedit)/mooeditgotoline-glade.h: $(mooedit_srcdir)/glade/mooeditgotoline.glade $(XML2H)
sh $(XML2H) MOO_EDIT_GOTO_LINE_GLADE_UI $(mooedit_srcdir)/glade/mooeditgotoline.glade \
> $(mooedit)/mooeditgotoline-glade.h
$(mooedit)/mootextgotoline-glade.h: $(mooedit_srcdir)/glade/mootextgotoline.glade $(XML2H)
sh $(XML2H) MOO_TEXT_GOTO_LINE_GLADE_UI $(mooedit_srcdir)/glade/mootextgotoline.glade \
> $(mooedit)/mootextgotoline-glade.h
$(mooedit)/mooeditfind-glade.h: $(mooedit_srcdir)/glade/mooeditfind.glade $(XML2H)
sh $(XML2H) MOO_EDIT_FIND_GLADE_UI $(mooedit_srcdir)/glade/mooeditfind.glade \
> $(mooedit)/mooeditfind-glade.h
$(mooedit)/mootextfind-glade.h: $(mooedit_srcdir)/glade/mootextfind.glade $(XML2H)
sh $(XML2H) MOO_TEXT_FIND_GLADE_UI $(mooedit_srcdir)/glade/mootextfind.glade \
> $(mooedit)/mootextfind-glade.h
$(mooedit)/mooeditprefs-glade.h: $(mooedit_srcdir)/glade/mooeditprefs.glade $(XML2H)
sh $(XML2H) MOO_EDIT_PREFS_GLADE_UI $(mooedit_srcdir)/glade/mooeditprefs.glade \

View File

@ -64,14 +64,14 @@
</child>
<child>
<widget class="GtkVBox" id="vbox1">
<widget class="GtkVBox" id="vbox">
<property name="border_width">3</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">3</property>
<child>
<widget class="GtkFrame" id="frame1">
<widget class="GtkFrame" id="find_frame">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="label_yalign">0.5</property>
@ -117,7 +117,7 @@
</child>
<child>
<widget class="GtkEntry" id="text_to_find">
<widget class="GtkEntry" id="search_entry">
<property name="visible">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
@ -141,7 +141,7 @@
<property name="spacing">0</property>
<child>
<widget class="GtkCheckButton" id="regular_expression">
<widget class="GtkCheckButton" id="regex">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Regular expression </property>
@ -258,7 +258,7 @@
</child>
<child>
<widget class="GtkEntry" id="replacement_text">
<widget class="GtkEntry" id="replace_entry">
<property name="visible">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
@ -282,10 +282,10 @@
<property name="spacing">0</property>
<child>
<widget class="GtkCheckButton" id="use_placeholders">
<widget class="GtkCheckButton" id="repl_literal">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Use placeholders </property>
<property name="label" translatable="yes">Literal replacement</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">False</property>
@ -338,7 +338,7 @@
</child>
<child>
<widget class="GtkFrame" id="frame2">
<widget class="GtkFrame" id="options_frame">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="label_yalign">0.5</property>
@ -366,7 +366,7 @@
<property name="column_spacing">3</property>
<child>
<widget class="GtkCheckButton" id="whole_words_only">
<widget class="GtkCheckButton" id="whole_words">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Whole words only</property>
@ -410,7 +410,7 @@
</child>
<child>
<widget class="GtkCheckButton" id="selected_text">
<widget class="GtkCheckButton" id="selected">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Selected text</property>
@ -453,7 +453,7 @@
</child>
<child>
<widget class="GtkCheckButton" id="find_backwards">
<widget class="GtkCheckButton" id="backwards">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Find backwards</property>
@ -474,7 +474,7 @@
</child>
<child>
<widget class="GtkCheckButton" id="dont_prompt_on_replace">
<widget class="GtkCheckButton" id="dont_prompt">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Don't prompt on replace</property>
@ -570,7 +570,7 @@
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">False</property>
<property name="response_id">3</property>
<property name="response_id">2</property>
</widget>
</child>
@ -583,7 +583,7 @@
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">False</property>
<property name="response_id">4</property>
<property name="response_id">3</property>
</widget>
</child>
@ -596,7 +596,7 @@
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">False</property>
<property name="response_id">2</property>
<property name="response_id">1</property>
</widget>
</child>
@ -609,7 +609,7 @@
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">False</property>
<property name="response_id">-6</property>
<property name="response_id">0</property>
</widget>
</child>
</widget>

View File

@ -20,7 +20,6 @@
#define __MOO_EDIT_PRIVATE_H__
#include "mooedit/mooeditor.h"
#include "mooedit/mooeditsearch.h"
#include "mooedit/mootextview.h"
G_BEGIN_DECLS

View File

@ -16,10 +16,11 @@
#include "mooedit/mooeditdialogs.h"
#include "mooedit/mooedit-private.h"
#include "mooedit/mooeditprefs.h"
#include "mooedit/mooeditfind-glade.h"
#include "mooedit/mootextfind-glade.h"
#include "mooutils/moodialogs.h"
#include "mooutils/moostock.h"
#include "mooutils/mooglade.h"
#include "mooutils/eggregex.h"
#include <gtk/gtk.h>
@ -576,24 +577,38 @@ moo_edit_file_modified_on_disk_dialog (MooEdit *edit)
/* Search dialogs
*/
static GtkWindow *
get_parent_window (GtkWidget *widget)
{
if (widget)
{
widget = gtk_widget_get_toplevel (widget);
if (GTK_WIDGET_TOPLEVEL (widget))
return GTK_WINDOW (widget);
}
return NULL;
}
void
moo_text_nothing_found_dialog (MooTextView *view,
moo_text_nothing_found_dialog (GtkWidget *parent,
const char *text,
gboolean regex)
{
GtkWindow *parent_window;
GtkWidget *dialog;
char *msg_text;
g_return_if_fail (MOO_IS_TEXT_VIEW (view) && text != NULL);
g_return_if_fail (text != NULL);
if (regex)
msg_text = g_strdup_printf ("Search pattern '%s' not found!", text);
else
msg_text = g_strdup_printf ("Search string '%s' not found!", text);
parent_window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL,
dialog = gtk_message_dialog_new (get_parent_window (parent),
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO, GTK_BUTTONS_NONE,
msg_text);
gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CLOSE,
@ -608,16 +623,13 @@ moo_text_nothing_found_dialog (MooTextView *view,
gboolean
moo_text_search_from_beginning_dialog (MooTextView *view,
gboolean backwards)
moo_text_search_from_start_dialog (GtkWidget *widget,
gboolean backwards)
{
GtkWindow *parent_window;
GtkWidget *dialog;
int response;
const char *msg;
g_return_val_if_fail (MOO_IS_TEXT_VIEW (view), FALSE);
if (backwards)
msg = "Beginning of document reached.\n"
"Continue from the end?";
@ -625,8 +637,7 @@ moo_text_search_from_beginning_dialog (MooTextView *view,
msg = "End of document reached.\n"
"Continue from the beginning?";
parent_window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL,
dialog = gtk_message_dialog_new (get_parent_window (widget), GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
msg);
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
@ -649,31 +660,34 @@ moo_text_search_from_beginning_dialog (MooTextView *view,
void
moo_text_regex_error_dialog (MooTextView *view,
GError *err)
moo_text_regex_error_dialog (GtkWidget *parent,
GError *error)
{
GtkWindow *parent_window;
GtkWidget *dialog;
char *msg_text = NULL;
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
if (err) {
if (err->domain != EGG_REGEX_ERROR)
if (error)
{
if (error->domain != EGG_REGEX_ERROR)
{
g_warning ("%s: unknown error domain", G_STRLOC);
else if (err->code != EGG_REGEX_ERROR_COMPILE &&
err->code != EGG_REGEX_ERROR_OPTIMIZE &&
err->code != EGG_REGEX_ERROR_REPLACE)
g_warning ("%s: unknown error code", G_STRLOC);
}
else if (error->code != EGG_REGEX_ERROR_COMPILE &&
error->code != EGG_REGEX_ERROR_OPTIMIZE &&
error->code != EGG_REGEX_ERROR_REPLACE)
{
g_warning ("%s: unknown error code", G_STRLOC);
}
msg_text = g_strdup (err->message);
msg_text = g_strdup (error->message);
}
else
{
msg_text = g_strdup_printf ("Invalid regular expression");
}
if (!msg_text)
msg_text = g_strdup_printf ("Invalid regular expression");
parent_window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL,
dialog = gtk_message_dialog_new (get_parent_window (parent),
GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE,
msg_text);
gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CLOSE,
@ -688,15 +702,12 @@ moo_text_regex_error_dialog (MooTextView *view,
void
moo_text_replaced_n_dialog (MooTextView *view,
guint n)
moo_text_replaced_n_dialog (GtkWidget *parent,
guint n)
{
GtkWindow *parent_window;
GtkWidget *dialog;
char *msg_text;
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
if (!n)
msg_text = g_strdup_printf ("No replacement made");
else if (n == 1)
@ -704,8 +715,8 @@ moo_text_replaced_n_dialog (MooTextView *view,
else
msg_text = g_strdup_printf ("%d replacements made", n);
parent_window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL,
dialog = gtk_message_dialog_new (get_parent_window (parent),
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO, GTK_BUTTONS_NONE,
msg_text);
gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CLOSE,
@ -720,22 +731,17 @@ moo_text_replaced_n_dialog (MooTextView *view,
GtkWidget*
moo_text_prompt_on_replace_dialog (MooTextView *view)
moo_text_prompt_on_replace_dialog (GtkWidget *parent)
{
GtkWidget *dialog;
GtkWindow *parent_window;
MooGladeXML *xml;
g_return_val_if_fail (MOO_IS_TEXT_VIEW (view), NULL);
xml = moo_glade_xml_new_from_buf (MOO_EDIT_FIND_GLADE_UI, -1,
xml = moo_glade_xml_new_from_buf (MOO_TEXT_FIND_GLADE_UI, -1,
"prompt_on_replace_dialog", NULL);
dialog = moo_glade_xml_get_widget (xml, "prompt_on_replace_dialog");
moo_glade_xml_unref (xml);
parent_window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
gtk_window_set_transient_for (GTK_WINDOW (dialog), get_parent_window (parent));
return dialog;
}

View File

@ -54,17 +54,19 @@ void moo_edit_reload_error_dialog (GtkWidget *widget,
const char *err_msg);
void moo_text_nothing_found_dialog (MooTextView *view,
void moo_text_nothing_found_dialog (GtkWidget *parent,
const char *text,
gboolean regex);
gboolean moo_text_search_from_beginning_dialog
(MooTextView *view,
gboolean moo_text_search_from_start_dialog (GtkWidget *parent,
gboolean backwards);
void moo_text_regex_error_dialog (MooTextView *view,
void moo_text_regex_error_dialog (GtkWidget *parent,
GError *error);
void moo_text_replaced_n_dialog (MooTextView *view,
gboolean moo_text_replace_from_start_dialog (GtkWidget *parent,
int replaced);
void moo_text_replaced_n_dialog (GtkWidget *parent,
guint n);
GtkWidget *moo_text_prompt_on_replace_dialog (MooTextView *view);
GtkWidget *moo_text_prompt_on_replace_dialog (GtkWidget *parent);
G_END_DECLS

View File

@ -1,923 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
*
* mooeditfind.c
*
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* 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.
*
* See COPYING file that comes with this distribution.
*/
#define MOOEDIT_COMPILATION
#include "mooedit/mootextview-private.h"
#include "mooedit/mooeditsearch.h"
#include "mooedit/mooeditprefs.h"
#include "mooedit/mooeditdialogs.h"
#include "mooedit/mooeditgotoline-glade.h"
#include "mooedit/mooeditfind-glade.h"
#include "mooutils/moohistoryentry.h"
#include "mooutils/moocompat.h"
#include "mooutils/mooglade.h"
static void
scroll_to_mark (MooTextView *view,
GtkTextMark *mark)
{
gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), mark, 0.2, FALSE, 0, 0);
}
/****************************************************************************/
/* Go to line
*/
static void update_spin_value (GtkRange *scale,
GtkSpinButton *spin);
static gboolean update_scale_value (GtkSpinButton *spin,
GtkRange *scale);
static void update_spin_value (GtkRange *scale,
GtkSpinButton *spin)
{
double value = gtk_range_get_value (scale);
g_signal_handlers_block_matched (spin, G_SIGNAL_MATCH_FUNC, 0, 0, 0,
(gpointer)update_scale_value, 0);
gtk_spin_button_set_value (spin, value);
g_signal_handlers_unblock_matched (spin, G_SIGNAL_MATCH_FUNC, 0, 0, 0,
(gpointer)update_scale_value, 0);
}
static gboolean update_scale_value (GtkSpinButton *spin,
GtkRange *scale)
{
double value = gtk_spin_button_get_value (spin);
g_signal_handlers_block_matched (scale, G_SIGNAL_MATCH_FUNC, 0, 0, 0,
(gpointer)update_spin_value, 0);
gtk_range_set_value (scale, value);
g_signal_handlers_unblock_matched (scale, G_SIGNAL_MATCH_FUNC, 0, 0, 0,
(gpointer)update_spin_value, 0);
return FALSE;
}
void
moo_text_view_goto_line (MooTextView *view,
int line)
{
GtkWidget *dialog;
GtkTextBuffer *buffer;
int line_count;
GtkTextIter iter;
GtkRange *scale;
GtkSpinButton *spin;
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
line_count = gtk_text_buffer_get_line_count (buffer);
if (line < 0 || line >= line_count)
{
MooGladeXML *xml;
xml = moo_glade_xml_new_from_buf (MOO_EDIT_GOTO_LINE_GLADE_UI,
-1, NULL, NULL);
g_return_if_fail (xml != NULL);
dialog = moo_glade_xml_get_widget (xml, "dialog");
#if GTK_CHECK_VERSION(2,6,0)
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
#endif /* GTK_CHECK_VERSION(2,6,0) */
gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
line = gtk_text_iter_get_line (&iter);
scale = moo_glade_xml_get_widget (xml, "scale");
gtk_range_set_range (scale, 1, line_count + 1);
gtk_range_set_value (scale, line + 1);
spin = moo_glade_xml_get_widget (xml, "spin");
gtk_entry_set_activates_default (GTK_ENTRY (spin), TRUE);
gtk_spin_button_set_range (spin, 1, line_count);
gtk_spin_button_set_value (spin, line + 1);
gtk_editable_select_region (GTK_EDITABLE (spin), 0, -1);
g_signal_connect (scale, "value-changed", G_CALLBACK (update_spin_value), spin);
g_signal_connect (spin, "value-changed", G_CALLBACK (update_scale_value), scale);
gtk_window_set_transient_for (GTK_WINDOW (dialog),
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))));
moo_glade_xml_unref (xml);
if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
{
gtk_widget_destroy (dialog);
return;
}
line = (int)gtk_spin_button_get_value (spin) - 1;
gtk_widget_destroy (dialog);
}
gtk_text_buffer_get_iter_at_line (buffer, &iter, line);
gtk_text_buffer_place_cursor (buffer, &iter);
scroll_to_mark (view, gtk_text_buffer_get_insert (buffer));
}
/****************************************************************************/
/* Search and replace
*/
static void set (GtkWidget *dialog,
gboolean regex,
gboolean case_sensitive,
gboolean whole_words,
gboolean from_cursor,
gboolean backwards,
gboolean selected,
gboolean dont_prompt_on_replace);
static void get (GtkWidget *dialog,
gboolean *regex,
gboolean *case_sensitive,
gboolean *whole_words,
gboolean *from_cursor,
gboolean *backwards,
gboolean *selected,
gboolean *dont_prompt_on_replace);
static const char *get_text (GtkWidget *dialog);
static const char *get_replace_with (GtkWidget *dialog);
static void set_text (GtkWidget *dialog,
const char *text);
static void set_replace_with (GtkWidget *dialog,
const char *text);
static GtkWidget *create_find_dialog (gboolean replace);
typedef struct {
MooTextView *view;
GtkWidget *dialog;
MooTextReplaceResponseType response;
} PromptFuncData;
static MooTextReplaceResponseType prompt_on_replace_func
(const char *text,
EggRegex *regex,
const char *replacement,
GtkTextIter *to_replace_start,
GtkTextIter *to_replace_end,
gpointer data);
static GtkWidget*
create_find_dialog (gboolean replace)
{
MooGladeXML *xml;
GtkWidget *dialog, *replace_frame, *dont_prompt_on_replace;
GtkButton *ok_btn;
MooHistoryEntry *text_to_find, *replacement_text;
xml = moo_glade_xml_new_empty ();
moo_glade_xml_map_id (xml, "text_to_find", MOO_TYPE_HISTORY_ENTRY);
moo_glade_xml_map_id (xml, "replacement_text", MOO_TYPE_HISTORY_ENTRY);
moo_glade_xml_parse_memory (xml, MOO_EDIT_FIND_GLADE_UI, -1, "dialog");
dialog = moo_glade_xml_get_widget (xml, "dialog");
g_return_val_if_fail (dialog != NULL, NULL);
g_object_set_data_full (G_OBJECT (dialog), "moo-dialog-xml",
xml, (GDestroyNotify) moo_glade_xml_unref);
replace_frame = moo_glade_xml_get_widget (xml, "replace_frame");
dont_prompt_on_replace = moo_glade_xml_get_widget (xml, "dont_prompt_on_replace");
ok_btn = moo_glade_xml_get_widget (xml, "ok_btn");
text_to_find = moo_glade_xml_get_widget (xml, "text_to_find");
replacement_text = moo_glade_xml_get_widget (xml, "replacement_text");
moo_history_entry_set_list (text_to_find, _moo_text_search_params->text_to_find_history);
moo_history_entry_set_list (replacement_text, _moo_text_search_params->replacement_history);
if (replace)
{
gtk_window_set_title (GTK_WINDOW (dialog), "Replace");
gtk_widget_show (replace_frame);
gtk_widget_show (dont_prompt_on_replace);
gtk_button_set_label (ok_btn, GTK_STOCK_FIND_AND_REPLACE);
}
else
{
gtk_window_set_title (GTK_WINDOW (dialog), "Find");
gtk_widget_hide (replace_frame);
gtk_widget_hide (dont_prompt_on_replace);
gtk_button_set_label (ok_btn, GTK_STOCK_FIND);
}
return dialog;
}
void
_moo_text_view_find (MooTextView *view)
{
GtkWidget *dialog;
gboolean regex, case_sensitive, whole_words, from_cursor, backwards, selected;
GtkTextIter sel_start, sel_end;
int response;
MooTextSearchOptions options;
const char *text;
GtkTextMark *insert;
GtkTextBuffer *buffer;
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
regex = _moo_text_search_params->regex;
case_sensitive = _moo_text_search_params->case_sensitive;
backwards = _moo_text_search_params->backwards;
whole_words = _moo_text_search_params->whole_words;
from_cursor = _moo_text_search_params->from_cursor;
selected = FALSE;
if (moo_prefs_get_bool (moo_edit_setting (MOO_EDIT_PREFS_SEARCH_SELECTED)) &&
gtk_text_buffer_get_selection_bounds (buffer, &sel_start, &sel_end) &&
ABS (gtk_text_iter_get_line (&sel_start) - gtk_text_iter_get_line (&sel_end) > 1))
selected = TRUE;
dialog = create_find_dialog (FALSE);
set (dialog, regex, case_sensitive, whole_words,
from_cursor, backwards, selected, FALSE);
if (gtk_text_buffer_get_selection_bounds (buffer, &sel_start, &sel_end) &&
gtk_text_iter_get_line (&sel_start) == gtk_text_iter_get_line (&sel_end))
{
char *selection = gtk_text_buffer_get_text (buffer, &sel_start, &sel_end, TRUE);
set_text (dialog, selection);
g_free (selection);
}
else if (_moo_text_search_params->text)
{
set_text (dialog, _moo_text_search_params->text);
}
gtk_window_set_transient_for (GTK_WINDOW (dialog),
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))));
response = gtk_dialog_run (GTK_DIALOG (dialog));
if (response != GTK_RESPONSE_OK)
{
gtk_widget_destroy (dialog);
return;
}
get (dialog, &regex, &case_sensitive, &whole_words,
&from_cursor, &backwards, &selected, NULL);
if (selected)
{
g_warning ("%s: searching in selected not imlemented\n", G_STRLOC);
gtk_widget_destroy (dialog);
return;
}
_moo_text_search_params->regex = regex;
_moo_text_search_params->case_sensitive = case_sensitive;
_moo_text_search_params->backwards = backwards;
_moo_text_search_params->whole_words = whole_words;
_moo_text_search_params->from_cursor = from_cursor;
_moo_text_search_params->last_search_stamp++;
view->priv->last_search_stamp = _moo_text_search_params->last_search_stamp;
g_free (_moo_text_search_params->text);
_moo_text_search_params->text = g_strdup (get_text (dialog));
text = _moo_text_search_params->text;
gtk_widget_destroy (dialog);
if (text && text[0])
moo_history_list_add (_moo_text_search_params->text_to_find_history, text);
options = 0;
if (regex)
options |= MOO_TEXT_SEARCH_REGEX;
if (backwards)
options |= MOO_TEXT_SEARCH_BACKWARDS;
if (!case_sensitive)
options |= MOO_TEXT_SEARCH_CASE_INSENSITIVE;
insert = gtk_text_buffer_get_insert (buffer);
{
GtkTextIter start, search_start, limit, match_start, match_end;
gboolean result;
GError *err = NULL;
if (from_cursor) {
gtk_text_buffer_get_iter_at_mark (buffer, &start, insert);
}
else {
if (backwards)
gtk_text_buffer_get_end_iter (buffer, &start);
else
gtk_text_buffer_get_start_iter (buffer, &start);
}
search_start = start;
if (backwards)
gtk_text_buffer_get_start_iter (buffer, &limit);
else
gtk_text_buffer_get_end_iter (buffer, &limit);
result = moo_text_search (&start, &limit, text,
&match_start, &match_end, options,
&err);
if (!result)
{
if (err) {
moo_text_regex_error_dialog (view, err);
g_error_free (err);
return;
}
if (!from_cursor) {
moo_text_nothing_found_dialog (view, text, regex);
return;
}
if ((backwards && gtk_text_iter_is_end (&start)) ||
(!backwards && gtk_text_iter_is_start (&start)))
{
moo_text_nothing_found_dialog (view, text, regex);
return;
}
if (!moo_text_search_from_beginning_dialog (view, backwards))
{
return;
}
if (backwards)
gtk_text_buffer_get_end_iter (buffer, &start);
else
gtk_text_buffer_get_start_iter (buffer, &start);
limit = search_start;
result = moo_text_search (&start, &limit, text,
&match_start, &match_end, options,
NULL);
if (!result) {
moo_text_nothing_found_dialog (view, text, regex);
return;
}
}
if (backwards)
gtk_text_iter_order (&match_end, &match_start);
if (!view->priv->last_found_start) {
view->priv->last_found_start =
gtk_text_buffer_create_mark (buffer, NULL, &match_start, TRUE);
view->priv->last_found_end =
gtk_text_buffer_create_mark (buffer, NULL, &match_end, TRUE);
}
else {
gtk_text_buffer_move_mark (buffer, view->priv->last_found_start,
&match_start);
gtk_text_buffer_move_mark (buffer, view->priv->last_found_end,
&match_end);
}
gtk_text_buffer_select_range (buffer, &match_end, &match_start);
scroll_to_mark (view, insert);
}
}
void
_moo_text_view_find_next (MooTextView *view)
{
gboolean regex, case_sensitive, whole_words, backwards;
MooTextSearchOptions options;
const char *text;
GtkTextMark *insert;
GtkTextBuffer *buffer;
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
if (_moo_text_search_params->last_search_stamp < 0 ||
!_moo_text_search_params->text)
return moo_text_view_find_interactive (view);
regex = _moo_text_search_params->regex;
case_sensitive = _moo_text_search_params->case_sensitive;
backwards = _moo_text_search_params->backwards;
whole_words = _moo_text_search_params->whole_words;
view->priv->last_search_stamp = _moo_text_search_params->last_search_stamp;
text = _moo_text_search_params->text;
options = 0;
if (regex) options |= MOO_TEXT_SEARCH_REGEX;
if (backwards) options |= MOO_TEXT_SEARCH_BACKWARDS;
if (!case_sensitive) options |= MOO_TEXT_SEARCH_CASE_INSENSITIVE;
insert = gtk_text_buffer_get_insert (buffer);
{
GtkTextIter start, search_start, match_start, match_end, limit;
gboolean result;
gtk_text_buffer_get_iter_at_mark (buffer, &start, insert);
search_start = start;
if (backwards)
gtk_text_buffer_get_start_iter (buffer, &limit);
else
gtk_text_buffer_get_end_iter (buffer, &limit);
result = moo_text_search (&start, &limit, text,
&match_start, &match_end, options,
NULL);
if (!result)
{
if ((backwards && gtk_text_iter_is_end (&start)) ||
(!backwards && gtk_text_iter_is_start (&start)))
{
moo_text_nothing_found_dialog (view, text, regex);
return;
}
if (!moo_text_search_from_beginning_dialog (view, backwards))
{
return;
}
if (backwards)
gtk_text_buffer_get_end_iter (buffer, &start);
else
gtk_text_buffer_get_start_iter (buffer, &start);
limit = search_start;
result = moo_text_search (&start, &search_start, text,
&match_start, &match_end, options,
NULL);
if (!result) {
moo_text_nothing_found_dialog (view, text, regex);
return;
}
}
if (backwards)
gtk_text_iter_order (&match_end, &match_start);
if (!view->priv->last_found_start) {
view->priv->last_found_start =
gtk_text_buffer_create_mark (buffer, NULL, &match_start, TRUE);
view->priv->last_found_end =
gtk_text_buffer_create_mark (buffer, NULL, &match_end, TRUE);
}
else {
gtk_text_buffer_move_mark (buffer, view->priv->last_found_start,
&match_start);
gtk_text_buffer_move_mark (buffer, view->priv->last_found_end,
&match_end);
}
gtk_text_buffer_select_range (buffer, &match_end, &match_start);
scroll_to_mark (view, insert);
}
}
void
_moo_text_view_find_previous (MooTextView *view)
{
gboolean regex, case_sensitive, whole_words, backwards;
MooTextSearchOptions options;
const char *text;
GtkTextMark *insert;
GtkTextBuffer *buffer;
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
if (_moo_text_search_params->last_search_stamp < 0 ||
!_moo_text_search_params->text)
return moo_text_view_find_interactive (view);
regex = _moo_text_search_params->regex;
case_sensitive = _moo_text_search_params->case_sensitive;
backwards = _moo_text_search_params->backwards;
whole_words = _moo_text_search_params->whole_words;
view->priv->last_search_stamp = _moo_text_search_params->last_search_stamp;
text = _moo_text_search_params->text;
options = 0;
if (regex) options |= MOO_TEXT_SEARCH_REGEX;
if (!backwards) options |= MOO_TEXT_SEARCH_BACKWARDS;
if (!case_sensitive) options |= MOO_TEXT_SEARCH_CASE_INSENSITIVE;
insert = gtk_text_buffer_get_insert (buffer);
{
GtkTextIter start, search_start, match_start, match_end, limit;
gboolean result;
gtk_text_buffer_get_iter_at_mark (buffer, &start, insert);
search_start = start;
if (!backwards)
gtk_text_buffer_get_start_iter (buffer, &limit);
else
gtk_text_buffer_get_end_iter (buffer, &limit);
result = moo_text_search (&start, &limit, text,
&match_start, &match_end, options,
NULL);
if (!result)
{
if ((!backwards && gtk_text_iter_is_end (&start)) ||
(backwards && gtk_text_iter_is_start (&start)))
{
moo_text_nothing_found_dialog (view, text, regex);
return;
}
if (!moo_text_search_from_beginning_dialog (view, !backwards))
{
return;
}
if (!backwards)
gtk_text_buffer_get_end_iter (buffer, &start);
else
gtk_text_buffer_get_start_iter (buffer, &start);
limit = search_start;
result = moo_text_search (&start, &search_start, text,
&match_start, &match_end, options,
NULL);
if (!result) {
moo_text_nothing_found_dialog (view, text, regex);
return;
}
}
if (!backwards)
gtk_text_iter_order (&match_end, &match_start);
if (!view->priv->last_found_start) {
view->priv->last_found_start =
gtk_text_buffer_create_mark (buffer, NULL, &match_start, TRUE);
view->priv->last_found_end =
gtk_text_buffer_create_mark (buffer, NULL, &match_end, TRUE);
}
else {
gtk_text_buffer_move_mark (buffer, view->priv->last_found_start,
&match_start);
gtk_text_buffer_move_mark (buffer, view->priv->last_found_end,
&match_end);
}
gtk_text_buffer_select_range (buffer, &match_end, &match_start);
scroll_to_mark (view, insert);
}
}
void
_moo_text_view_replace (MooTextView *view)
{
GtkWidget *dialog;
gboolean regex, case_sensitive, whole_words, from_cursor,
backwards, selected, dont_prompt_on_replace;
GtkTextIter sel_start, sel_end;
MooTextSearchOptions options;
const char *text, *replace_with;
GtkTextMark *insert;
GtkTextBuffer *buffer;
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
regex = _moo_text_search_params->regex;
case_sensitive = _moo_text_search_params->case_sensitive;
backwards = _moo_text_search_params->backwards;
whole_words = _moo_text_search_params->whole_words;
from_cursor = _moo_text_search_params->from_cursor;
dont_prompt_on_replace = _moo_text_search_params->dont_prompt_on_replace;
selected = FALSE;
if (moo_prefs_get_bool (moo_edit_setting (MOO_EDIT_PREFS_SEARCH_SELECTED)) &&
gtk_text_buffer_get_selection_bounds (buffer, &sel_start, &sel_end) &&
ABS (gtk_text_iter_get_line (&sel_start) - gtk_text_iter_get_line (&sel_end) > 1))
selected = TRUE;
dialog = create_find_dialog (TRUE);
set (dialog, regex, case_sensitive, whole_words,
from_cursor, backwards, selected, dont_prompt_on_replace);
if (gtk_text_buffer_get_selection_bounds (buffer, &sel_start, &sel_end) &&
gtk_text_iter_get_line (&sel_start) == gtk_text_iter_get_line (&sel_end))
{
char *selection = gtk_text_buffer_get_text (buffer, &sel_start, &sel_end, TRUE);
set_text (dialog, selection);
g_free (selection);
}
else if (_moo_text_search_params->text)
{
set_text (dialog, _moo_text_search_params->text);
}
if (_moo_text_search_params->replace_with)
set_replace_with (dialog, _moo_text_search_params->replace_with);
gtk_window_set_transient_for (GTK_WINDOW (dialog),
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))));
if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
{
gtk_widget_destroy (dialog);
return;
}
get (dialog, &regex, &case_sensitive, &whole_words,
&from_cursor, &backwards, &selected, &dont_prompt_on_replace);
if (selected)
{
g_warning ("%s: searching in selected not imlemented\n", G_STRLOC);
return;
}
_moo_text_search_params->regex = regex;
_moo_text_search_params->case_sensitive = case_sensitive;
_moo_text_search_params->backwards = backwards;
_moo_text_search_params->whole_words = whole_words;
_moo_text_search_params->from_cursor = from_cursor;
_moo_text_search_params->dont_prompt_on_replace = dont_prompt_on_replace;
_moo_text_search_params->last_search_stamp++;
view->priv->last_search_stamp = _moo_text_search_params->last_search_stamp;
g_free (_moo_text_search_params->text);
_moo_text_search_params->text = g_strdup (get_text (dialog));
text = _moo_text_search_params->text;
g_free (_moo_text_search_params->replace_with);
_moo_text_search_params->replace_with = g_strdup (get_replace_with (dialog));
replace_with = _moo_text_search_params->replace_with;
gtk_widget_destroy (dialog);
if (text && text[0])
moo_history_list_add (_moo_text_search_params->text_to_find_history, text);
if (replace_with && replace_with[0])
moo_history_list_add (_moo_text_search_params->replacement_history, replace_with);
options = 0;
if (regex) options |= MOO_TEXT_SEARCH_REGEX;
if (backwards) options |= MOO_TEXT_SEARCH_BACKWARDS;
if (!case_sensitive) options |= MOO_TEXT_SEARCH_CASE_INSENSITIVE;
insert = gtk_text_buffer_get_insert (buffer);
G_STMT_START {
GtkTextIter start, limit;
gboolean result;
GError *err = NULL;
PromptFuncData data = {view, NULL, MOO_TEXT_REPLACE};
if (from_cursor) {
gtk_text_buffer_get_iter_at_mark (buffer, &start, insert);
}
else {
if (backwards)
gtk_text_buffer_get_end_iter (buffer, &start);
else
gtk_text_buffer_get_start_iter (buffer, &start);
}
if (backwards)
gtk_text_buffer_get_start_iter (buffer, &limit);
else
gtk_text_buffer_get_end_iter (buffer, &limit);
if (!dont_prompt_on_replace) {
result = moo_text_replace_all_interactive (&start, &limit, text,
replace_with,
options, &err,
prompt_on_replace_func,
&data);
}
else
result = moo_text_replace_all_interactive (&start, &limit, text,
replace_with, options,
&err, moo_text_replace_func_replace_all,
NULL);
g_return_if_fail (result != MOO_TEXT_REPLACE_INVALID_ARGS);
if (result == MOO_TEXT_REPLACE_REGEX_ERROR || err) {
moo_text_regex_error_dialog (view, err);
if (err) g_error_free (err);
return;
}
if (!from_cursor || data.response == MOO_TEXT_REPLACE_STOP) {
if (data.dialog) gtk_widget_destroy (data.dialog);
moo_text_replaced_n_dialog (view, result);
return;
}
if ((backwards && gtk_text_iter_is_end (&start)) ||
(!backwards && gtk_text_iter_is_start (&start)))
{
if (data.dialog) gtk_widget_destroy (data.dialog);
moo_text_replaced_n_dialog (view, result);
return;
}
if (!moo_text_search_from_beginning_dialog (view, backwards))
{
if (data.dialog) gtk_widget_destroy (data.dialog);
moo_text_replaced_n_dialog (view, result);
return;
}
{
int result2;
if (backwards)
gtk_text_buffer_get_end_iter (buffer, &start);
else
gtk_text_buffer_get_start_iter (buffer, &start);
gtk_text_buffer_get_iter_at_mark (buffer, &limit, insert);
if (!dont_prompt_on_replace)
result2 = moo_text_replace_all_interactive (&start, &limit, text,
replace_with,
options, &err,
prompt_on_replace_func,
&data);
else
result2 = moo_text_replace_all_interactive (&start, &limit, text,
replace_with, options, &err,
moo_text_replace_func_replace_all,
NULL);
g_return_if_fail (result2 >= 0);
if (data.dialog) gtk_widget_destroy (data.dialog);
moo_text_replaced_n_dialog (view, result + result2);
}
} G_STMT_END;
}
static MooTextReplaceResponseType prompt_on_replace_func
(G_GNUC_UNUSED const char *text,
G_GNUC_UNUSED EggRegex *regex,
G_GNUC_UNUSED const char *replacement,
GtkTextIter *to_replace_start,
GtkTextIter *to_replace_end,
gpointer d)
{
PromptFuncData *data = (PromptFuncData*) d;
GtkTextBuffer *buffer;
int response;
buffer = gtk_text_iter_get_buffer (to_replace_end);
gtk_text_buffer_select_range (buffer, to_replace_end, to_replace_start);
scroll_to_mark (data->view, gtk_text_buffer_get_insert (buffer));
if (!data->dialog)
data->dialog = moo_text_prompt_on_replace_dialog (data->view);
response = gtk_dialog_run (GTK_DIALOG (data->dialog));
if (response == GTK_RESPONSE_DELETE_EVENT ||
response == GTK_RESPONSE_CANCEL)
data->response = MOO_TEXT_REPLACE_STOP;
else
data->response = (MooTextReplaceResponseType)response;
return data->response;
}
#define GET_WIDGET(name) \
GtkWidget *name = moo_glade_xml_get_widget (xml, #name);
#define GET_TOGGLE_BUTTON(name) \
GtkToggleButton *name = moo_glade_xml_get_widget (xml, #name);
static void set (GtkWidget *dialog,
gboolean regex,
gboolean casesensitive,
gboolean whole_words,
gboolean fromcursor,
gboolean backwards,
gboolean selected,
gboolean dontpromptonreplace)
{
MooGladeXML *xml = g_object_get_data (G_OBJECT (dialog), "moo-dialog-xml");
GET_TOGGLE_BUTTON (regular_expression);
GET_TOGGLE_BUTTON (case_sensitive);
GET_TOGGLE_BUTTON (whole_words_only);
GET_TOGGLE_BUTTON (from_cursor);
GET_TOGGLE_BUTTON (find_backwards);
GET_TOGGLE_BUTTON (selected_text);
GET_TOGGLE_BUTTON (dont_prompt_on_replace);
gtk_toggle_button_set_active (regular_expression, regex);
gtk_toggle_button_set_active (case_sensitive, casesensitive);
gtk_toggle_button_set_active (whole_words_only, whole_words);
gtk_toggle_button_set_active (from_cursor, fromcursor);
gtk_toggle_button_set_active (find_backwards, backwards);
gtk_toggle_button_set_active (selected_text, selected);
gtk_toggle_button_set_active (dont_prompt_on_replace, dontpromptonreplace);
}
static void get (GtkWidget *dialog,
gboolean *regex,
gboolean *casesensitive,
gboolean *whole_words,
gboolean *fromcursor,
gboolean *backwards,
gboolean *selected,
gboolean *dontpromptonreplace)
{
MooGladeXML *xml = g_object_get_data (G_OBJECT (dialog), "moo-dialog-xml");
GET_TOGGLE_BUTTON (regular_expression);
GET_TOGGLE_BUTTON (case_sensitive);
GET_TOGGLE_BUTTON (whole_words_only);
GET_TOGGLE_BUTTON (from_cursor);
GET_TOGGLE_BUTTON (find_backwards);
GET_TOGGLE_BUTTON (selected_text);
GET_TOGGLE_BUTTON (dont_prompt_on_replace);
if (regex) *regex = gtk_toggle_button_get_active (regular_expression);
if (casesensitive) *casesensitive = gtk_toggle_button_get_active (case_sensitive);
if (whole_words) *whole_words = gtk_toggle_button_get_active (whole_words_only);
if (fromcursor) *fromcursor = gtk_toggle_button_get_active (from_cursor);
if (backwards) *backwards = gtk_toggle_button_get_active (find_backwards);
if (selected) *selected = gtk_toggle_button_get_active (selected_text);
if (dontpromptonreplace) *dontpromptonreplace = gtk_toggle_button_get_active (dont_prompt_on_replace);
}
static void set_text (GtkWidget *dialog,
const char *text)
{
MooGladeXML *xml = g_object_get_data (G_OBJECT (dialog), "moo-dialog-xml");
GET_WIDGET (text_to_find);
moo_combo_entry_set_text (MOO_COMBO (text_to_find), text);
moo_combo_select_region (MOO_COMBO (text_to_find), 0, -1);
}
static void set_replace_with (GtkWidget *dialog,
const char *text)
{
MooGladeXML *xml = g_object_get_data (G_OBJECT (dialog), "moo-dialog-xml");
GET_WIDGET (replacement_text);
moo_combo_entry_set_text (MOO_COMBO (replacement_text), text);
}
static const char *get_text (GtkWidget *dialog)
{
MooGladeXML *xml = g_object_get_data (G_OBJECT (dialog), "moo-dialog-xml");
GET_WIDGET (text_to_find);
return moo_combo_entry_get_text (MOO_COMBO (text_to_find));
}
static const char *get_replace_with (GtkWidget *dialog)
{
MooGladeXML *xml = g_object_get_data (G_OBJECT (dialog), "moo-dialog-xml");
GET_WIDGET (replacement_text);
return moo_combo_entry_get_text (MOO_COMBO (replacement_text));
}

File diff suppressed because it is too large Load Diff

View File

@ -1,110 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
*
* mooeditsearch.h
*
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* 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.
*
* See COPYING file that comes with this distribution.
*/
#ifndef __MOO_EDIT_SEARCH_H__
#define __MOO_EDIT_SEARCH_H__
#include <mooedit/mooedit.h>
#include <mooedit/mootextview.h>
#include <mooutils/eggregex.h>
G_BEGIN_DECLS
#define MOO_TYPE_TEXT_SEARCH_OPTIONS (moo_text_search_options_get_type ())
#define MOO_TYPE_TEXT_REPLACE_RESPONSE_TYPE (moo_text_replace_response_type_get_type ())
GType moo_text_search_options_get_type (void) G_GNUC_UNUSED;
GType moo_text_replace_response_type_get_type (void) G_GNUC_UNUSED;
typedef enum {
MOO_TEXT_SEARCH_BACKWARDS = 1 << 0,
MOO_TEXT_SEARCH_CASE_INSENSITIVE = 1 << 1,
MOO_TEXT_SEARCH_REGEX = 1 << 2
} MooTextSearchOptions;
gboolean moo_text_search (const GtkTextIter *start,
const GtkTextIter *limit,
const char *text,
GtkTextIter *match_start,
GtkTextIter *match_end,
MooTextSearchOptions options,
GError **error);
gboolean moo_text_search_regex (const GtkTextIter *start,
const GtkTextIter *limit,
EggRegex *regex,
GtkTextIter *match_start,
GtkTextIter *match_end,
gboolean backwards);
#define MOO_TEXT_REPLACE_INVALID_ARGS ((int)-1)
#define MOO_TEXT_REPLACE_REGEX_ERROR ((int)-2)
/* Do not change numerical values!!! */
typedef enum {
MOO_TEXT_REPLACE_STOP = 0,
MOO_TEXT_REPLACE_AND_STOP = 1,
MOO_TEXT_REPLACE_SKIP = 2,
MOO_TEXT_REPLACE = 3,
MOO_TEXT_REPLACE_ALL = 4
} MooTextReplaceResponseType;
/* replacement is real replacement text when searching for regex */
typedef MooTextReplaceResponseType (* MooTextReplaceFunc) (const char *text,
EggRegex *regex,
const char *replacement,
GtkTextIter *to_replace_start,
GtkTextIter *to_replace_end,
gpointer data);
MooTextReplaceResponseType moo_text_replace_func_replace_all
(const char *text,
EggRegex *regex,
const char *replacement,
GtkTextIter *to_replace_start,
GtkTextIter *to_replace_end,
gpointer data);
int moo_text_replace_all_interactive(GtkTextIter *start,
GtkTextIter *end,
const char *text,
const char *replacement,
MooTextSearchOptions options,
GError **error,
MooTextReplaceFunc func,
gpointer data);
int moo_text_replace_regex_all_interactive
(GtkTextIter *start,
GtkTextIter *end,
EggRegex *regex,
const char *replacement,
gboolean backwards,
GError **error,
MooTextReplaceFunc func,
gpointer data);
void _moo_text_view_find (MooTextView *edit);
void _moo_text_view_replace (MooTextView *edit);
void _moo_text_view_find_next (MooTextView *edit);
void _moo_text_view_find_previous (MooTextView *edit);
G_END_DECLS
#endif /* __MOO_EDIT_SEARCH_H__ */

View File

@ -483,11 +483,12 @@ moo_rule_regex_new (const char *pattern,
regex = egg_regex_new (pattern, regex_compile_options,
regex_match_options, &error);
if (!regex)
if (error)
{
g_warning ("could not compile pattern '%s': %s",
pattern, error->message);
g_error_free (error);
egg_regex_unref (regex);
return NULL;
}

View File

@ -37,6 +37,9 @@ struct _MooTextBufferPrivate {
MooBracketMatchType bracket_found;
LineBuffer *line_buf;
int cursor_moved_frozen;
gboolean cursor_moved;
};
@ -67,9 +70,15 @@ static void moo_text_buffer_apply_tag (GtkTextBuffer *buffer,
static void moo_text_buffer_delete_range (GtkTextBuffer *buffer,
GtkTextIter *start,
GtkTextIter *end);
static void moo_text_buffer_begin_user_action (GtkTextBuffer *buffer);
static void moo_text_buffer_end_user_action (GtkTextBuffer *buffer);
static void moo_text_buffer_queue_highlight (MooTextBuffer *buffer);
static void cursor_moved (MooTextBuffer *buffer,
const GtkTextIter *iter);
static void freeze_cursor_moved (MooTextBuffer *buffer);
static void thaw_cursor_moved (MooTextBuffer *buffer);
enum {
CURSOR_MOVED,
@ -108,6 +117,8 @@ moo_text_buffer_class_init (MooTextBufferClass *klass)
buffer_class->insert_text = moo_text_buffer_insert_text;
buffer_class->delete_range = moo_text_buffer_delete_range;
buffer_class->apply_tag = moo_text_buffer_apply_tag;
buffer_class->begin_user_action = moo_text_buffer_begin_user_action;
buffer_class->end_user_action = moo_text_buffer_end_user_action;
klass->cursor_moved = moo_text_buffer_cursor_moved;
@ -162,7 +173,7 @@ moo_text_buffer_class_init (MooTextBufferClass *klass)
signals[CURSOR_MOVED] =
g_signal_new ("cursor-moved",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (MooTextBufferClass, cursor_moved),
NULL, NULL,
_moo_marshal_VOID__BOXED,
@ -209,6 +220,20 @@ moo_text_buffer_new (GtkTextTagTable *table)
}
static void
moo_text_buffer_begin_user_action (GtkTextBuffer *buffer)
{
moo_text_buffer_freeze (MOO_TEXT_BUFFER (buffer));
}
static void
moo_text_buffer_end_user_action (GtkTextBuffer *buffer)
{
moo_text_buffer_thaw (MOO_TEXT_BUFFER (buffer));
}
static void
moo_text_buffer_mark_set (GtkTextBuffer *text_buffer,
const GtkTextIter *iter,
@ -242,7 +267,7 @@ moo_text_buffer_mark_set (GtkTextBuffer *text_buffer,
}
if (mark == insert)
g_signal_emit (buffer, signals[CURSOR_MOVED], 0, iter);
cursor_moved (buffer, iter);
}
@ -282,7 +307,7 @@ moo_text_buffer_insert_text (GtkTextBuffer *text_buffer,
moo_text_buffer_queue_highlight (buffer);
g_signal_emit (buffer, signals[CURSOR_MOVED], 0, pos);
cursor_moved (buffer, pos);
if (!buffer->priv->has_text)
{
@ -300,11 +325,17 @@ moo_text_buffer_delete_range (GtkTextBuffer *text_buffer,
MooTextBuffer *buffer = MOO_TEXT_BUFFER (text_buffer);
int first_line, last_line;
gtk_text_buffer_remove_all_tags (text_buffer, start, end);
first_line = gtk_text_iter_get_line (start);
last_line = gtk_text_iter_get_line (end);
#define MANY_LINES 1000
if (buffer->priv->lang && buffer->priv->do_highlight &&
last_line - first_line > MANY_LINES)
{
gtk_text_buffer_remove_all_tags (text_buffer, start, end);
}
#undef MANY_LINES
GTK_TEXT_BUFFER_CLASS(moo_text_buffer_parent_class)->delete_range (text_buffer, start, end);
if (first_line < last_line)
@ -315,7 +346,7 @@ moo_text_buffer_delete_range (GtkTextBuffer *text_buffer,
moo_line_buffer_invalidate (buffer->priv->line_buf, first_line);
moo_text_buffer_queue_highlight (buffer);
g_signal_emit (buffer, signals[CURSOR_MOVED], 0, start);
cursor_moved (buffer, start);
if (buffer->priv->has_text)
{
@ -551,12 +582,60 @@ moo_text_buffer_apply_scheme (MooTextBuffer *buffer,
}
void
moo_text_buffer_freeze (MooTextBuffer *buffer)
{
g_return_if_fail (MOO_IS_TEXT_BUFFER (buffer));
freeze_cursor_moved (buffer);
}
void
moo_text_buffer_thaw (MooTextBuffer *buffer)
{
g_return_if_fail (MOO_IS_TEXT_BUFFER (buffer));
thaw_cursor_moved (buffer);
}
/*****************************************************************************/
/* Matching brackets
*/
#define FIND_BRACKETS_LIMIT 10000
static void
cursor_moved (MooTextBuffer *buffer,
const GtkTextIter *where)
{
if (!buffer->priv->cursor_moved_frozen)
g_signal_emit (buffer, signals[CURSOR_MOVED], 0, where);
else
buffer->priv->cursor_moved = TRUE;
}
static void
freeze_cursor_moved (MooTextBuffer *buffer)
{
buffer->priv->cursor_moved_frozen++;
}
static void
thaw_cursor_moved (MooTextBuffer *buffer)
{
g_return_if_fail (buffer->priv->cursor_moved_frozen > 0);
if (!--buffer->priv->cursor_moved_frozen && buffer->priv->cursor_moved)
{
GtkTextIter iter;
GtkTextMark *insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (buffer));
gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer), &iter, insert);
cursor_moved (buffer, &iter);
buffer->priv->cursor_moved = FALSE;
}
}
static void
moo_text_buffer_cursor_moved (MooTextBuffer *buffer,
const GtkTextIter *where)

View File

@ -70,6 +70,9 @@ void moo_text_buffer_set_brackets (MooTextBuffer *buf
void moo_text_buffer_set_check_brackets (MooTextBuffer *buffer,
gboolean check);
void moo_text_buffer_freeze (MooTextBuffer *buffer);
void moo_text_buffer_thaw (MooTextBuffer *buffer);
gboolean moo_text_buffer_has_text (MooTextBuffer *buffer);
gboolean moo_text_buffer_has_selection (MooTextBuffer *buffer);

1000
moo/mooedit/mootextfind.c Normal file

File diff suppressed because it is too large Load Diff

87
moo/mooedit/mootextfind.h Normal file
View File

@ -0,0 +1,87 @@
/*
* mootextfind.h
*
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* 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.
*
* See COPYING file that comes with this distribution.
*/
#ifndef __MOO_TEXT_FIND_H__
#define __MOO_TEXT_FIND_H__
#include <gtk/gtktextview.h>
#include <gtk/gtkdialog.h>
#include "mooutils/moohistorylist.h"
#include "mooutils/mooglade.h"
#include "mooutils/eggregex.h"
G_BEGIN_DECLS
#define MOO_TYPE_FIND (moo_find_get_type ())
#define MOO_FIND(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOO_TYPE_FIND, MooFind))
#define MOO_FIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_FIND, MooFindClass))
#define MOO_IS_FIND(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOO_TYPE_FIND))
#define MOO_IS_FIND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_FIND))
#define MOO_FIND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_FIND, MooFindClass))
typedef struct _MooFind MooFind;
typedef struct _MooFindClass MooFindClass;
typedef enum {
MOO_FIND_REGEX = 1 << 0,
MOO_FIND_CASELESS = 1 << 1,
MOO_FIND_IN_SELECTED = 1 << 2,
MOO_FIND_BACKWARDS = 1 << 3,
MOO_FIND_WHOLE_WORDS = 1 << 4,
MOO_FIND_FROM_CURSOR = 1 << 5,
MOO_FIND_DONT_PROMPT = 1 << 6,
MOO_FIND_REPL_LITERAL = 1 << 7
} MooFindFlags;
struct _MooFind
{
GtkDialog base;
MooGladeXML *xml;
EggRegex *regex;
guint replace : 1;
};
struct _MooFindClass
{
GtkDialogClass base_class;
};
GType moo_find_get_type (void) G_GNUC_CONST;
GtkWidget *moo_find_new (gboolean replace);
void moo_find_setup (MooFind *find,
GtkTextView *view);
gboolean moo_find_run (MooFind *find);
void moo_find_set_flags (MooFind *find,
MooFindFlags flags);
MooFindFlags moo_find_get_flags (MooFind *find);
/* returned string/regex must be freed/unrefed */
char *moo_find_get_text (MooFind *find);
EggRegex *moo_find_get_regex (MooFind *find);
char *moo_find_get_replacement (MooFind *find);
void moo_text_view_run_find (GtkTextView *view);
void moo_text_view_run_replace (GtkTextView *view);
void moo_text_view_run_find_next (GtkTextView *view);
void moo_text_view_run_find_prev (GtkTextView *view);
void moo_text_view_run_goto_line (GtkTextView *view);
G_END_DECLS
#endif /* __MOO_TEXT_FIND_H__ */

842
moo/mooedit/mootextsearch.c Normal file
View File

@ -0,0 +1,842 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
*
* mootextsearch.c
*
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* 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.
*
* See COPYING file that comes with this distribution.
*/
#include "mooedit/mootextsearch.h"
#include "mooedit/gtksourceiter.h"
#include <string.h>
gboolean
moo_text_search_regex_forward (const GtkTextIter *search_start,
const GtkTextIter *search_end,
EggRegex *regex,
GtkTextIter *match_start,
GtkTextIter *match_end,
char **string,
int *match_offset,
int *match_len)
{
GtkTextIter start, end;
GtkTextBuffer *buffer;
int start_offset;
char *text, *text_start;
g_return_val_if_fail (search_start != NULL, FALSE);
g_return_val_if_fail (match_start != NULL && match_end != NULL, FALSE);
g_return_val_if_fail (regex != NULL, FALSE);
buffer = gtk_text_iter_get_buffer (search_start);
start = *search_start;
start_offset = gtk_text_iter_get_line_offset (&start);
if (start_offset)
gtk_text_iter_set_line_offset (&start, 0);
end = *search_start;
if (!gtk_text_iter_ends_line (&end))
gtk_text_iter_forward_to_line_end (&end);
while (TRUE)
{
text = gtk_text_buffer_get_slice (buffer, &start, &end, TRUE);
text_start = g_utf8_offset_to_pointer (text, start_offset);
egg_regex_clear (regex);
if (egg_regex_match_extended (regex, text, -1, text_start - text, 0) > 0)
{
int start_pos, end_pos;
egg_regex_fetch_pos (regex, text, 0, &start_pos, &end_pos);
*match_start = start;
gtk_text_iter_forward_chars (match_start, g_utf8_pointer_to_offset (text, text + start_pos));
if (search_end && gtk_text_iter_compare (match_start, search_end) > 0)
{
g_free (text);
return FALSE;
}
*match_end = *match_start;
gtk_text_iter_forward_chars (match_end, g_utf8_pointer_to_offset (text + start_pos, text + end_pos));
if (string)
*string = text;
else
g_free (text);
if (match_offset)
*match_offset = start_pos;
if (match_len)
*match_len = end_pos - start_pos;
return TRUE;
}
start = end;
start_offset = 0;
if (!gtk_text_iter_forward_line (&start))
break;
if (search_end && gtk_text_iter_compare (&start, search_end) > 0)
break;
end = start;
if (!gtk_text_iter_ends_line (&end))
gtk_text_iter_forward_to_line_end (&end);
}
return FALSE;
}
static gboolean
find_last_match (EggRegex *regex,
const char *text,
EggRegexMatchFlags flags,
int *start_pos,
int *end_pos)
{
int len, start;
*start_pos = -1;
egg_regex_clear (regex);
len = strlen (text);
start = 0;
while (egg_regex_match_extended (regex, text, len, start, flags) > 0)
{
egg_regex_fetch_pos (regex, text, 0, start_pos, end_pos);
start = *start_pos + 1;
if (start >= len)
break;
}
return *start_pos >= 0;
}
gboolean
moo_text_search_regex_backward (const GtkTextIter *search_start,
const GtkTextIter *search_end,
EggRegex *regex,
GtkTextIter *match_start,
GtkTextIter *match_end,
char **string,
int *match_offset,
int *match_len)
{
GtkTextIter slice_start, slice_end;
GtkTextBuffer *buffer;
char *text;
EggRegexMatchFlags flags;
g_return_val_if_fail (search_start != NULL, FALSE);
g_return_val_if_fail (match_start != NULL && match_end != NULL, FALSE);
g_return_val_if_fail (regex != NULL, FALSE);
buffer = gtk_text_iter_get_buffer (search_start);
slice_start = *search_start;
slice_end = slice_start;
gtk_text_iter_backward_line (&slice_start);
flags = 0;
if (!gtk_text_iter_ends_line (&slice_end))
flags |= EGG_REGEX_MATCH_NOTEOL;
while (TRUE)
{
int start_pos, end_pos;
text = gtk_text_buffer_get_slice (buffer, &slice_start, &slice_end, TRUE);
if (find_last_match (regex, text, flags, &start_pos, &end_pos))
{
*match_start = slice_start;
gtk_text_iter_forward_chars (match_start, g_utf8_pointer_to_offset (text, text + start_pos));
if (search_end && gtk_text_iter_compare (match_start, search_end) < 0)
{
g_free (text);
return FALSE;
}
*match_end = *match_start;
gtk_text_iter_forward_chars (match_end, g_utf8_pointer_to_offset (text + start_pos, text + end_pos));
if (string)
*string = text;
else
g_free (text);
if (match_offset)
*match_offset = start_pos;
if (match_len)
*match_len = end_pos - start_pos;
return TRUE;
}
slice_end = slice_start;
flags = 0;
if (gtk_text_iter_is_start (&slice_end))
break;
if (search_end && gtk_text_iter_compare (&slice_end, search_end) < 0)
break;
gtk_text_iter_backward_line (&slice_start);
}
return FALSE;
}
static EggRegex *
get_regex (const char *pattern,
MooTextSearchFlags flags,
GError **error)
{
static EggRegex *saved_regex;
static char *saved_pattern;
static MooTextSearchFlags saved_flags;
GError *tmp_error = NULL;
if (!saved_pattern || strcmp (saved_pattern, pattern) || saved_flags != flags)
{
EggRegexCompileFlags re_flags = 0;
egg_regex_unref (saved_regex);
g_free (saved_pattern);
saved_pattern = g_strdup (pattern);
saved_flags = flags;
if (flags & MOO_TEXT_SEARCH_CASELESS)
re_flags |= EGG_REGEX_CASELESS;
saved_regex = egg_regex_new (saved_pattern, re_flags, 0, &tmp_error);
if (tmp_error)
{
g_free (saved_pattern);
saved_pattern = NULL;
g_propagate_error (error, tmp_error);
egg_regex_unref (saved_regex);
saved_regex = NULL;
return NULL;
}
egg_regex_optimize (saved_regex, error);
}
return saved_regex;
}
static gboolean
is_whole_word (const GtkTextIter *start,
const GtkTextIter *end)
{
GtkTextIter s = *start;
GtkTextIter e = *end;
gtk_text_iter_order (&s, &e);
if (!gtk_text_iter_starts_line (&s))
{
gunichar c;
gtk_text_iter_backward_char (&s);
c = gtk_text_iter_get_char (&s);
if (g_unichar_isalnum (c))
return FALSE;
}
if (!gtk_text_iter_ends_line (&e))
{
gunichar c = gtk_text_iter_get_char (&e);
if (g_unichar_isalnum (c))
return FALSE;
}
return TRUE;
}
gboolean
moo_text_search_forward (const GtkTextIter *start,
const char *str,
MooTextSearchFlags flags,
GtkTextIter *match_start,
GtkTextIter *match_end,
const GtkTextIter *end)
{
EggRegex *regex;
GError *error = NULL;
g_return_val_if_fail (start != NULL, FALSE);
g_return_val_if_fail (str != NULL, FALSE);
g_return_val_if_fail (match_start != NULL && match_end != NULL, FALSE);
if (!(flags & MOO_TEXT_SEARCH_REGEX))
{
GtkSourceSearchFlags gs_flags = 0;
GtkTextIter real_end, real_start;
if (flags & MOO_TEXT_SEARCH_CASELESS)
gs_flags |= GTK_SOURCE_SEARCH_CASE_INSENSITIVE;
/* http://bugzilla.gnome.org/show_bug.cgi?id=321299 */
if (!end || gtk_text_iter_is_end (end))
{
end = NULL;
}
else
{
real_end = *end;
gtk_text_iter_forward_char (&real_end);
end = &real_end;
}
if (!(flags & MOO_TEXT_SEARCH_WHOLE_WORDS))
return gtk_source_iter_forward_search (start, str, gs_flags,
match_start, match_end, end);
real_start = *start;
while (gtk_source_iter_forward_search (&real_start, str, gs_flags,
match_start, match_end, end))
{
if (is_whole_word (match_start, match_end))
return TRUE;
real_start = *match_end;
}
return FALSE;
}
regex = get_regex (str, flags, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
}
if (!regex)
return FALSE;
return moo_text_search_regex_forward (start, end, regex,
match_start, match_end,
NULL, NULL, NULL);
}
gboolean
moo_text_search_backward (const GtkTextIter *start,
const char *str,
MooTextSearchFlags flags,
GtkTextIter *match_start,
GtkTextIter *match_end,
const GtkTextIter *end)
{
EggRegex *regex;
GError *error = NULL;
g_return_val_if_fail (start != NULL, FALSE);
g_return_val_if_fail (str != NULL, FALSE);
g_return_val_if_fail (match_start != NULL && match_end != NULL, FALSE);
if (!(flags & MOO_TEXT_SEARCH_REGEX))
{
GtkSourceSearchFlags gs_flags = 0;
GtkTextIter real_start;
if (flags & MOO_TEXT_SEARCH_CASELESS)
gs_flags |= GTK_SOURCE_SEARCH_CASE_INSENSITIVE;
if (!(flags & MOO_TEXT_SEARCH_WHOLE_WORDS))
return gtk_source_iter_backward_search (start, str, gs_flags,
match_start, match_end, end);
real_start = *start;
while (gtk_source_iter_backward_search (&real_start, str, gs_flags,
match_start, match_end, end))
{
if (is_whole_word (match_start, match_end))
return TRUE;
real_start = *match_start;
}
return FALSE;
}
regex = get_regex (str, flags, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
}
if (!regex)
return FALSE;
return moo_text_search_regex_backward (start, end, regex,
match_start, match_end,
NULL, NULL, NULL);
}
static int
moo_text_replace_regex_all_real (GtkTextIter *start,
GtkTextIter *end,
EggRegex *regex,
const char *replacement,
gboolean replacement_literal,
MooTextReplaceFunc func,
gpointer func_data)
{
int count = 0;
GtkTextMark *end_mark;
GtkTextBuffer *buffer;
MooTextReplaceResponse response;
gboolean need_end_user_action = FALSE;
char *freeme = NULL;
const char *const_replacement = NULL;
GError *error = NULL;
gboolean was_zero_match = FALSE;
g_return_val_if_fail (start != NULL, 0);
g_return_val_if_fail (regex != NULL, 0);
g_return_val_if_fail (replacement != NULL, 0);
if (replacement_literal)
{
const_replacement = replacement;
}
else
{
freeme = egg_regex_try_eval_replacement (regex, replacement, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
return 0;
}
const_replacement = freeme;
}
buffer = gtk_text_iter_get_buffer (start);
if (end && !gtk_text_iter_is_end (end))
{
end_mark = gtk_text_buffer_create_mark (buffer, NULL, end, TRUE);
}
else
{
end = NULL;
end_mark = NULL;
}
if (func)
{
response = MOO_TEXT_REPLACE_DO_REPLACE;
}
else
{
gtk_text_buffer_begin_user_action (buffer);
need_end_user_action = TRUE;
response = MOO_TEXT_REPLACE_ALL;
}
while (TRUE)
{
GtkTextIter match_start, match_end;
char *freeme_here = NULL;
const char *real_replacement;
char *string;
GError *error = NULL;
int match_len;
if (!moo_text_search_regex_forward (start, end, regex, &match_start, &match_end,
&string, NULL, &match_len))
goto out;
if (!match_len)
{
if (was_zero_match && gtk_text_iter_equal (&match_start, start))
{
was_zero_match = FALSE;
g_free (string);
if (!gtk_text_iter_forward_char (start))
goto out;
continue;
}
was_zero_match = TRUE;
}
else
{
was_zero_match = FALSE;
}
if (const_replacement)
{
real_replacement = const_replacement;
g_free (string);
}
else
{
freeme_here = egg_regex_eval_replacement (regex, string, replacement, &error);
g_free (string);
if (!freeme_here)
{
g_warning ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
goto out;
}
real_replacement = freeme_here;
}
if (response != MOO_TEXT_REPLACE_ALL)
{
response = func (NULL, regex, real_replacement, &match_start, &match_end, func_data);
if (!response)
{
g_free (freeme_here);
goto out;
}
}
if (response != MOO_TEXT_REPLACE_SKIP && (match_len || *real_replacement))
{
count++;
if (response == MOO_TEXT_REPLACE_ALL)
{
if (!need_end_user_action)
{
gtk_text_buffer_begin_user_action (buffer);
need_end_user_action = TRUE;
}
}
else
{
gtk_text_buffer_begin_user_action (buffer);
}
gtk_text_buffer_delete (buffer, &match_start, &match_end);
gtk_text_buffer_insert (buffer, &match_end, real_replacement, -1);
if (response != MOO_TEXT_REPLACE_ALL)
gtk_text_buffer_end_user_action (buffer);
}
*start = match_end;
if (was_zero_match && !*real_replacement)
{
if (gtk_text_iter_is_end (start))
{
g_free (freeme_here);
goto out;
}
gtk_text_iter_forward_char (start);
was_zero_match = FALSE;
}
if (end)
gtk_text_buffer_get_iter_at_mark (buffer, end, end_mark);
g_free (freeme_here);
}
out:
if (end_mark)
gtk_text_buffer_delete_mark (buffer, end_mark);
if (need_end_user_action)
gtk_text_buffer_end_user_action (buffer);
g_free (freeme);
return count;
}
int
moo_text_replace_regex_all (GtkTextIter *start,
GtkTextIter *end,
EggRegex *regex,
const char *replacement,
gboolean replacement_literal)
{
g_return_val_if_fail (start != NULL, 0);
g_return_val_if_fail (regex != NULL, 0);
g_return_val_if_fail (replacement != NULL, 0);
return moo_text_replace_regex_all_real (start, end, regex, replacement,
replacement_literal, NULL, NULL);
}
int
moo_text_replace_regex_all_interactive (GtkTextIter *start,
GtkTextIter *end,
EggRegex *regex,
const char *replacement,
gboolean replacement_literal,
MooTextReplaceFunc func,
gpointer func_data)
{
g_return_val_if_fail (start != NULL, 0);
g_return_val_if_fail (regex != NULL, 0);
g_return_val_if_fail (replacement != NULL, 0);
g_return_val_if_fail (func != NULL, 0);
return moo_text_replace_regex_all_real (start, end, regex,
replacement, replacement_literal,
func, func_data);
}
int
moo_text_replace_all (GtkTextIter *start,
GtkTextIter *end,
const char *text,
const char *replacement,
MooTextSearchFlags flags)
{
int count = 0;
GtkTextMark *end_mark;
GtkTextBuffer *buffer;
g_return_val_if_fail (start != NULL, 0);
g_return_val_if_fail (text != NULL, 0);
g_return_val_if_fail (text[0] != 0, 0);
g_return_val_if_fail (replacement != NULL, 0);
if (flags & MOO_TEXT_SEARCH_REGEX)
{
GError *error = NULL;
EggRegex *regex = get_regex (text, flags, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
}
if (!regex)
return 0;
return moo_text_replace_regex_all (start, end, regex, replacement,
flags & MOO_TEXT_SEARCH_REPL_LITERAL);
}
buffer = gtk_text_iter_get_buffer (start);
gtk_text_buffer_begin_user_action (buffer);
if (!end || gtk_text_iter_is_end (end))
end = NULL;
else
gtk_text_iter_forward_char (end);
if (end)
end_mark = gtk_text_buffer_create_mark (buffer, NULL, end, TRUE);
else
end_mark = NULL;
while (TRUE)
{
GtkTextIter match_start, match_end;
if (!moo_text_search_forward (start, text, flags, &match_start, &match_end, end))
goto out;
count++;
gtk_text_buffer_delete (buffer, &match_start, &match_end);
gtk_text_buffer_insert (buffer, &match_end, replacement, -1);
*start = match_end;
if (end)
gtk_text_buffer_get_iter_at_mark (buffer, end, end_mark);
}
out:
if (end_mark)
gtk_text_buffer_delete_mark (buffer, end_mark);
gtk_text_buffer_end_user_action (buffer);
return count;
}
int
moo_text_replace_all_interactive (GtkTextIter *start,
GtkTextIter *end,
const char *text,
const char *replacement,
MooTextSearchFlags flags,
MooTextReplaceFunc func,
gpointer func_data)
{
int count = 0;
GtkTextMark *end_mark;
GtkTextBuffer *buffer;
MooTextReplaceResponse response = MOO_TEXT_REPLACE_DO_REPLACE;
gboolean need_end_user_action = FALSE;
g_return_val_if_fail (start != NULL, 0);
g_return_val_if_fail (text != NULL, 0);
g_return_val_if_fail (text[0] != 0, 0);
g_return_val_if_fail (replacement != NULL, 0);
g_return_val_if_fail (func != NULL, 0);
if (flags & MOO_TEXT_SEARCH_REGEX)
{
GError *error = NULL;
EggRegex *regex = get_regex (text, flags, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
}
if (!regex)
return 0;
return moo_text_replace_regex_all_interactive (start, end, regex, replacement,
flags & MOO_TEXT_SEARCH_REPL_LITERAL,
func, func_data);
}
buffer = gtk_text_iter_get_buffer (start);
if (!end || gtk_text_iter_is_end (end))
end = NULL;
else
gtk_text_iter_forward_char (end);
if (end)
end_mark = gtk_text_buffer_create_mark (buffer, NULL, end, TRUE);
else
end_mark = NULL;
while (TRUE)
{
GtkTextIter match_start, match_end;
if (!moo_text_search_forward (start, text, flags, &match_start, &match_end, end))
goto out;
if (response != MOO_TEXT_REPLACE_ALL)
{
response = func (text, NULL, replacement, &match_start, &match_end, func_data);
if (!response)
goto out;
}
if (response != MOO_TEXT_REPLACE_SKIP)
{
count++;
if (response == MOO_TEXT_REPLACE_ALL)
{
if (!need_end_user_action)
{
gtk_text_buffer_begin_user_action (buffer);
need_end_user_action = TRUE;
}
}
else
{
gtk_text_buffer_begin_user_action (buffer);
}
gtk_text_buffer_delete (buffer, &match_start, &match_end);
gtk_text_buffer_insert (buffer, &match_end, replacement, -1);
if (response != MOO_TEXT_REPLACE_ALL)
gtk_text_buffer_end_user_action (buffer);
}
*start = match_end;
if (end)
gtk_text_buffer_get_iter_at_mark (buffer, end, end_mark);
}
out:
if (end_mark)
gtk_text_buffer_delete_mark (buffer, end_mark);
if (need_end_user_action)
gtk_text_buffer_end_user_action (buffer);
return count;
}
GType
moo_text_search_flags_get_type (void)
{
static GType type = 0;
if (!type)
{
static const GFlagsValue values[] = {
{ MOO_TEXT_SEARCH_CASELESS, (char*)"MOO_TEXT_SEARCH_CASELESS", (char*)"caseless" },
{ MOO_TEXT_SEARCH_REGEX, (char*)"MOO_TEXT_SEARCH_REGEX", (char*)"regex" },
{ 0, NULL, NULL }
};
type = g_flags_register_static ("MooTextSearchFlags", values);
}
return type;
}
GType
moo_text_replace_response_get_type (void)
{
static GType type = 0;
if (!type)
{
static const GFlagsValue values[] = {
{ MOO_TEXT_REPLACE_STOP, (char*)"MOO_TEXT_REPLACE_STOP", (char*)"stop" },
{ MOO_TEXT_REPLACE_SKIP, (char*)"MOO_TEXT_REPLACE_SKIP", (char*)"skip" },
{ MOO_TEXT_REPLACE_DO_REPLACE, (char*)"MOO_TEXT_REPLACE_DO_REPLACE", (char*)"do-replace" },
{ MOO_TEXT_REPLACE_ALL, (char*)"MOO_TEXT_REPLACE_ALL", (char*)"all" },
{ 0, NULL, NULL }
};
type = g_flags_register_static ("MooTextReplaceResponse", values);
}
return type;
}

113
moo/mooedit/mootextsearch.h Normal file
View File

@ -0,0 +1,113 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
*
* mootextsearch.h
*
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* 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.
*
* See COPYING file that comes with this distribution.
*/
#ifndef __MOO_TEXT_SEARCH_H__
#define __MOO_TEXT_SEARCH_H__
#include <mooedit/mootextiter.h>
#include <mooutils/eggregex.h>
G_BEGIN_DECLS
#define MOO_TYPE_TEXT_SEARCH_FLAGS (moo_text_search_flags_get_type ())
#define MOO_TYPE_TEXT_REPLACE_RESPONSE (moo_text_replace_response_get_type ())
GType moo_text_search_flags_get_type (void) G_GNUC_CONST;
GType moo_text_replace_response_get_type (void) G_GNUC_CONST;
typedef enum {
MOO_TEXT_SEARCH_CASELESS = 1 << 0,
MOO_TEXT_SEARCH_REGEX = 1 << 1,
MOO_TEXT_SEARCH_WHOLE_WORDS = 1 << 2,
MOO_TEXT_SEARCH_REPL_LITERAL = 1 << 3
} MooTextSearchFlags;
typedef enum {
MOO_TEXT_REPLACE_STOP = 0,
MOO_TEXT_REPLACE_SKIP = 1,
MOO_TEXT_REPLACE_DO_REPLACE = 2,
MOO_TEXT_REPLACE_ALL = 3
} MooTextReplaceResponse;
/* replacement is evaluated in case of regex */
typedef MooTextReplaceResponse (*MooTextReplaceFunc) (const char *text,
EggRegex *regex,
const char *replacement,
const GtkTextIter *to_replace_start,
const GtkTextIter *to_replace_end,
gpointer user_data);
gboolean moo_text_search_forward (const GtkTextIter *start,
const char *str,
MooTextSearchFlags flags,
GtkTextIter *match_start,
GtkTextIter *match_end,
const GtkTextIter *end);
gboolean moo_text_search_backward (const GtkTextIter *start,
const char *str,
MooTextSearchFlags flags,
GtkTextIter *match_start,
GtkTextIter *match_end,
const GtkTextIter *end);
gboolean moo_text_search_regex_forward (const GtkTextIter *start,
const GtkTextIter *end,
EggRegex *regex,
GtkTextIter *match_start,
GtkTextIter *match_end,
char **string,
int *match_offset,
int *match_len);
gboolean moo_text_search_regex_backward (const GtkTextIter *start,
const GtkTextIter *end,
EggRegex *regex,
GtkTextIter *match_start,
GtkTextIter *match_end,
char **string,
int *match_offset,
int *match_len);
int moo_text_replace_regex_all (GtkTextIter *start,
GtkTextIter *end,
EggRegex *regex,
const char *replacement,
gboolean replacement_literal);
int moo_text_replace_all (GtkTextIter *start,
GtkTextIter *end,
const char *text,
const char *replacement,
MooTextSearchFlags flags);
int moo_text_replace_regex_all_interactive
(GtkTextIter *start,
GtkTextIter *end,
EggRegex *regex,
const char *replacement,
gboolean replacement_literal,
MooTextReplaceFunc func,
gpointer func_data);
int moo_text_replace_all_interactive (GtkTextIter *start,
GtkTextIter *end,
const char *text,
const char *replacement,
MooTextSearchFlags flags,
MooTextReplaceFunc func,
gpointer func_data);
G_END_DECLS
#endif /* __MOO_TEXT_SEARCH_H__ */

View File

@ -19,7 +19,6 @@
#ifndef __MOO_TEXT_VIEW_PRIVATE_H__
#define __MOO_TEXT_VIEW_PRIVATE_H__
#include "mooedit/mooeditsearch.h"
#include "mooedit/mootextview.h"
#include "mooutils/gtksourceundomanager.h"
#include "mooutils/moohistorylist.h"
@ -62,23 +61,6 @@ typedef enum {
} MooTextViewDragType;
typedef struct {
int last_search_stamp;
char *text;
char *replace_with;
gboolean regex;
gboolean case_sensitive;
gboolean backwards;
gboolean whole_words;
gboolean from_cursor;
gboolean dont_prompt_on_replace;
MooHistoryList *text_to_find_history;
MooHistoryList *replacement_history;
} MooTextSearchParams;
extern MooTextSearchParams *_moo_text_search_params;
struct _MooTextViewPrivate {
gboolean constructed;

View File

@ -16,6 +16,7 @@
#include "mooedit/mootextview-private.h"
#include "mooedit/mootextview.h"
#include "mooedit/mootextbuffer.h"
#include "mooedit/mootextfind.h"
#include "mooutils/moomarshals.h"
#include "mooutils/mooutils-gobject.h"
#include <string.h>
@ -23,10 +24,6 @@
#define LIGHT_BLUE "#EEF6FF"
MooTextSearchParams *_moo_text_search_params;
static MooTextSearchParams search_params;
static GObject *moo_text_view_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_param);
@ -60,7 +57,11 @@ static void cursor_moved (MooTextView *view,
static void proxy_prop_notify (MooTextView *view,
GParamSpec *pspec);
static void goto_line (MooTextView *view);
static void find_interactive (MooTextView *view);
static void replace_interactive (MooTextView *view);
static void find_next_interactive (MooTextView *view);
static void find_prev_interactive (MooTextView *view);
static void goto_line_interactive (MooTextView *view);
static void insert_text_cb (MooTextView *view,
GtkTextIter *iter,
@ -114,11 +115,6 @@ static void moo_text_view_class_init (MooTextViewClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkTextViewClass *text_view_class = GTK_TEXT_VIEW_CLASS (klass);
_moo_text_search_params = &search_params;
search_params.last_search_stamp = -1;
search_params.text_to_find_history = moo_history_list_new (NULL);
search_params.replacement_history = moo_history_list_new (NULL);
gobject_class->set_property = moo_text_view_set_property;
gobject_class->get_property = moo_text_view_get_property;
gobject_class->constructor = moo_text_view_constructor;
@ -137,11 +133,11 @@ static void moo_text_view_class_init (MooTextViewClass *klass)
klass->delete_selection = moo_text_view_delete_selection;
klass->extend_selection = _moo_text_view_extend_selection;
klass->find_interactive = _moo_text_view_find;
klass->find_next_interactive = _moo_text_view_find_next;
klass->find_prev_interactive = _moo_text_view_find_previous;
klass->replace_interactive = _moo_text_view_replace;
klass->goto_line_interactive = goto_line;
klass->find_interactive = find_interactive;
klass->find_next_interactive = find_next_interactive;
klass->find_prev_interactive = find_prev_interactive;
klass->replace_interactive = replace_interactive;
klass->goto_line_interactive = goto_line_interactive;
klass->undo = moo_text_view_undo;
klass->redo = moo_text_view_redo;
klass->char_inserted = moo_text_view_char_inserted;
@ -434,38 +430,34 @@ moo_text_view_delete_selection (MooTextView *view)
}
void
moo_text_view_find_interactive (MooTextView *view)
static void
find_interactive (MooTextView *view)
{
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
g_signal_emit (view, signals[FIND_INTERACTIVE], 0, NULL);
}
void
moo_text_view_replace_interactive (MooTextView *view)
{
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
g_signal_emit (view, signals[REPLACE_INTERACTIVE], 0, NULL);
}
void
moo_text_view_find_next_interactive (MooTextView *view)
{
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
g_signal_emit (view, signals[FIND_NEXT_INTERACTIVE], 0, NULL);
}
void
moo_text_view_find_prev_interactive (MooTextView *view)
{
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
g_signal_emit (view, signals[FIND_PREV_INTERACTIVE], 0, NULL);
moo_text_view_run_find (GTK_TEXT_VIEW (view));
}
static void
goto_line (MooTextView *view)
replace_interactive (MooTextView *view)
{
moo_text_view_goto_line (view, -1);
moo_text_view_run_replace (GTK_TEXT_VIEW (view));
}
static void
find_next_interactive (MooTextView *view)
{
moo_text_view_run_find_next (GTK_TEXT_VIEW (view));
}
static void
find_prev_interactive (MooTextView *view)
{
moo_text_view_run_find_prev (GTK_TEXT_VIEW (view));
}
static void
goto_line_interactive (MooTextView *view)
{
moo_text_view_run_goto_line (GTK_TEXT_VIEW (view));
}
@ -539,12 +531,12 @@ void
moo_text_view_redo (MooTextView *view)
{
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
// _moo_text_buffer_freeze_highlight (get_moo_buffer (view));
moo_text_buffer_freeze (get_moo_buffer (view));
gtk_source_undo_manager_redo (view->priv->undo_mgr);
gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
get_insert (view),
0, FALSE, 0, 0);
// _moo_text_buffer_thaw_highlight (get_moo_buffer (view));
moo_text_buffer_thaw (get_moo_buffer (view));
}
@ -552,12 +544,12 @@ void
moo_text_view_undo (MooTextView *view)
{
g_return_if_fail (MOO_IS_TEXT_VIEW (view));
// _moo_text_buffer_freeze_highlight (get_moo_buffer (view));
moo_text_buffer_freeze (get_moo_buffer (view));
gtk_source_undo_manager_undo (view->priv->undo_mgr);
gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
get_insert (view),
0, FALSE, 0, 0);
// _moo_text_buffer_thaw_highlight (get_moo_buffer (view));
moo_text_buffer_thaw (get_moo_buffer (view));
}
@ -1436,29 +1428,28 @@ moo_text_view_strip_whitespace (MooTextView *view)
gtk_text_iter_forward_line (&iter))
{
GtkTextIter end;
char *slice, *p;
int len;
if (gtk_text_iter_ends_line (&iter))
continue;
gtk_text_iter_forward_to_line_end (&iter);
end = iter;
gtk_text_iter_forward_to_line_end (&end);
do
slice = gtk_text_buffer_get_slice (buffer, &iter, &end, TRUE);
len = strlen (slice);
g_assert (len > 0);
for (p = slice + len; p > slice && (p[-1] == ' ' || p[-1] == '\t'); --p) ;
if (*p)
{
gunichar c;
gtk_text_iter_backward_char (&iter);
c = gtk_text_iter_get_char (&iter);
if (!g_unichar_isspace (c))
{
gtk_text_iter_forward_char (&iter);
break;
}
gtk_text_iter_forward_chars (&iter, g_utf8_pointer_to_offset (slice, p));
gtk_text_buffer_delete (buffer, &iter, &end);
}
while (!gtk_text_iter_starts_line (&iter));
gtk_text_buffer_delete (buffer, &iter, &end);
g_free (slice);
}
gtk_text_buffer_end_user_action (buffer);

View File

@ -100,10 +100,6 @@ void moo_text_view_undo (MooTextView *view);
void moo_text_view_start_not_undoable_action(MooTextView *view);
void moo_text_view_end_not_undoable_action (MooTextView *view);
void moo_text_view_find_interactive (MooTextView *view);
void moo_text_view_replace_interactive (MooTextView *view);
void moo_text_view_find_next_interactive (MooTextView *view);
void moo_text_view_find_prev_interactive (MooTextView *view);
void moo_text_view_goto_line (MooTextView *view,
int line);

View File

@ -88,11 +88,11 @@
<context style="Region Marker" eol-context="#pop" name="Region Marker">
</context>
<context style="Comment" eol-context="#pop" name="Commentar 1">
<IncludeRules from="##Misc##AlertRules"/>
<IncludeRules from="##Misc##CommonCommentRules"/>
</context>
<context style="Comment" eol-context="#stay" name="Commentar 2">
<TwoChars style="Comment" context="#pop" char1="*" char2="/" endRegion="Comment"/>
<IncludeRules from="##Misc##AlertRules"/>
<IncludeRules from="##Misc##CommonCommentRules"/>
</context>
<context style="Preprocessor" eol-context="#pop" name="Preprocessor">
<LineContinue style="Preprocessor" context="#stay"/>
@ -111,7 +111,7 @@
</context>
<context style="Comment" eol-context="#stay" name="Outscoped" >
<TwoChars style="Comment" context="Commentar 2" char1="/" char2="*" beginRegion="Comment"/>
<IncludeRules from="##Misc##AlertRules"/>
<IncludeRules from="##Misc##CommonCommentRules"/>
<Regex style="Comment" context="Outscoped intern" pattern="#\s*if" beginRegion="Outscoped" first-non-blank-only="true"/>
<Regex style="Preprocessor" context="#pop" pattern="#\s*(endif|else|elif)" endRegion="Outscoped" first-non-blank-only="true"/>
</context>
@ -137,7 +137,6 @@
<style name="Symbol" default-style="Normal"/>
<style name="Preprocessor" default-style="Others"/>
<style name="Prep. Lib" default-style="Others"/> <!--,Qt::darkYellow,Qt::yellow,false,false)); -->
<style name="Alert" default-style="Alert"/>
<style name="Region Marker" default-style="RegionMarker"/>
</styles>

View File

@ -6,6 +6,15 @@
<Keyword keyword="Alert" style="Alert"/>
</context>
<context name="LinkRules">
<Regex pattern="http://[^ ]*" style="Link"/>
</context>
<context name="CommonCommentRules">
<IncludeRules from="LinkRules"/>
<IncludeRules from="AlertRules"/>
</context>
<context name="ShebangRules">
<TwoChars char1="#" char2="!" bol-only="TRUE" first-line-only="TRUE" include-into-next="TRUE" context="Shebang" style="Shebang line"/>
</context>
@ -21,6 +30,7 @@
<styles>
<style name="Alert" default-style="Alert"/>
<style name="Link" underline="TRUE"/>
<style name="Shebang line" default-style="Comment" bold="TRUE" italic="FALSE"/>
</styles>
</language>

View File

@ -32,7 +32,7 @@ _moo_edit_mod_init (void)
if (!mod)
return FALSE;
// _moo_edit_add_constants (mod, "MOO_");
_moo_edit_add_constants (mod, "MOO_");
_moo_edit_register_classes (PyModule_GetDict (mod));
if (!PyErr_Occurred ())

View File

@ -149,17 +149,28 @@
)
)
(define-flags TextSearchOptions
(define-flags TextSearchFlags
(in-module "Moo")
(c-name "MooTextSearchOptions")
(gtype-id "MOO_TYPE_TEXT_SEARCH_OPTIONS")
(c-name "MooTextSearchFlags")
(gtype-id "MOO_TYPE_TEXT_SEARCH_FLAGS")
(values
'("backwards" "MOO_TEXT_SEARCH_BACKWARDS")
'("case-insensitive" "MOO_TEXT_SEARCH_CASE_INSENSITIVE")
'("caseless" "MOO_TEXT_SEARCH_CASELESS")
'("regex" "MOO_TEXT_SEARCH_REGEX")
)
)
(define-flags TextReplaceResponse
(in-module "Moo")
(c-name "MooTextReplaceResponse")
(gtype-id "MOO_TYPE_TEXT_REPLACE_RESPONSE")
(values
'("stop" "MOO_TEXT_REPLACE_STOP")
'("skip" "MOO_TEXT_REPLACE_SKIP")
'("do-replace" "MOO_TEXT_REPLACE_DO_REPLACE")
'("all" "MOO_TEXT_REPLACE_ALL")
)
)
(define-flags TextStyleMask
(in-module "Moo")
(c-name "MooTextStyleMask")
@ -420,80 +431,6 @@
;; From mooeditsearch.h
(define-function moo_text_search
(c-name "moo_text_search")
(return-type "gboolean")
(parameters
'("const-GtkTextIter*" "start")
'("const-GtkTextIter*" "limit")
'("const-char*" "text")
'("GtkTextIter*" "match_start")
'("GtkTextIter*" "match_end")
'("MooTextSearchOptions" "options")
'("GError**" "error")
)
)
(define-function moo_text_search_regex
(c-name "moo_text_search_regex")
(return-type "gboolean")
(parameters
'("const-GtkTextIter*" "start")
'("const-GtkTextIter*" "limit")
'("EggRegex*" "regex")
'("GtkTextIter*" "match_start")
'("GtkTextIter*" "match_end")
'("gboolean" "backwards")
)
)
(define-function moo_text_replace_func_replace_all
(c-name "moo_text_replace_func_replace_all")
(return-type "MooTextReplaceResponseType")
(parameters
'("const-char*" "text")
'("EggRegex*" "regex")
'("const-char*" "replacement")
'("GtkTextIter*" "to_replace_start")
'("GtkTextIter*" "to_replace_end")
'("gpointer" "data")
)
)
(define-function moo_text_replace_all_interactive
(c-name "moo_text_replace_all_interactive")
(return-type "int")
(parameters
'("GtkTextIter*" "start")
'("GtkTextIter*" "end")
'("const-char*" "text")
'("const-char*" "replacement")
'("MooTextSearchOptions" "options")
'("GError**" "error")
'("MooTextReplaceFunc" "func")
'("gpointer" "data")
)
)
(define-function moo_text_replace_regex_all_interactive
(c-name "moo_text_replace_regex_all_interactive")
(return-type "int")
(parameters
'("GtkTextIter*" "start")
'("GtkTextIter*" "end")
'("EggRegex*" "regex")
'("const-char*" "replacement")
'("gboolean" "backwards")
'("GError**" "error")
'("MooTextReplaceFunc" "func")
'("gpointer" "data")
)
)
;; From mooeditwindow.h
(define-method get_active_doc
@ -1148,38 +1085,14 @@
(return-type "none")
)
(define-method find_interactive
(of-object "MooTextView")
(c-name "moo_text_view_find_interactive")
(return-type "none")
)
(define-method replace_interactive
(of-object "MooTextView")
(c-name "moo_text_view_replace_interactive")
(return-type "none")
)
(define-method find_next_interactive
(of-object "MooTextView")
(c-name "moo_text_view_find_next_interactive")
(return-type "none")
)
(define-method find_prev_interactive
(of-object "MooTextView")
(c-name "moo_text_view_find_prev_interactive")
(return-type "none")
)
(define-method goto_line
(of-object "MooTextView")
(c-name "moo_text_view_goto_line")
(return-type "none")
(parameters
'("int" "line")
)
)
;; (define-method goto_line
;; (of-object "MooTextView")
;; (c-name "moo_text_view_goto_line")
;; (return-type "none")
;; (parameters
;; '("int" "line")
;; )
;; )
(define-method set_font_from_string
(of-object "MooTextView")
@ -1278,3 +1191,58 @@
'("MooLang*" "lang" (null-ok))
)
)
;; From mootextsearch.h
(define-function search_forward
(c-name "moo_text_search_forward")
(return-type "gboolean")
(parameters
'("const-GtkTextIter*" "start")
'("const-char*" "str")
'("MooTextSearchFlags" "flags")
'("GtkTextIter*" "match_start")
'("GtkTextIter*" "match_end")
'("const-GtkTextIter*" "end" (null-ok))
)
)
(define-function search_backward
(c-name "moo_text_search_backward")
(return-type "gboolean")
(parameters
'("const-GtkTextIter*" "start")
'("const-char*" "str")
'("MooTextSearchFlags" "flags")
'("GtkTextIter*" "match_start")
'("GtkTextIter*" "match_end")
'("const-GtkTextIter*" "end" (null-ok))
)
)
(define-function replace_all
(c-name "moo_text_replace_all")
(return-type "int")
(parameters
'("GtkTextIter*" "start")
'("GtkTextIter*" "end")
'("const-char*" "text")
'("const-char*" "replacement")
'("MooTextSearchFlags" "flags")
)
)
(define-function replace_all_interactive
(c-name "moo_text_replace_all_interactive")
(return-type "int")
(parameters
'("GtkTextIter*" "start")
'("GtkTextIter*" "end")
'("const-char*" "text")
'("const-char*" "replacement")
'("MooTextSearchFlags" "flags")
'("MooTextReplaceFunc" "func")
'("gpointer" "data")
)
)

View File

@ -4,7 +4,7 @@ headers
#define NO_IMPORT_PYGOBJECT
#include "pygobject.h"
#include "mooedit/mooeditor.h"
#include "mooedit/mooeditsearch.h"
#include "mooedit/mootextsearch.h"
#include "mooedit/mootextbuffer.h"
#include "mooedit/moocmdview.h"
#include "mooedit/mootextiter.h"
@ -185,3 +185,81 @@ _wrap_moo_line_view_get_line_data (PyObject *self, PyObject *args)
g_value_unset (&data);
return obj;
}
%%
override moo_text_search_forward varargs
static PyObject *
_wrap_moo_text_search_forward (G_GNUC_UNUSED PyObject *self, PyObject *args)
{
PyObject *py_start, *py_flags, *py_end = Py_None;
char *str;
int flags;
const GtkTextIter *start, *end = NULL;
GtkTextIter match_start, match_end;
if (!PyArg_ParseTuple(args, (char*) "OsO|O:search_forward", &py_start, &str, &py_flags, &py_end))
return NULL;
if (pyg_boxed_check (py_start, GTK_TYPE_TEXT_ITER))
start = pyg_boxed_get (py_start, GtkTextIter);
else
return_TypeErr ("start should be a GtkTextIter");
if (pyg_flags_get_value (MOO_TYPE_TEXT_SEARCH_FLAGS, py_flags, &flags))
return NULL;
if (pyg_boxed_check(py_end, GTK_TYPE_TEXT_ITER))
end = pyg_boxed_get(py_end, GtkTextIter);
else if (py_end != Py_None)
return_TypeErr ("end should be a GtkTextIter or None");
if (moo_text_search_forward (start, str, flags, &match_start, &match_end, end))
{
PyObject *ret = PyTuple_New (2);
PyTuple_SET_ITEM (ret, 0, pyg_boxed_new (GTK_TYPE_TEXT_ITER, &match_start, TRUE, TRUE));
PyTuple_SET_ITEM (ret, 1, pyg_boxed_new (GTK_TYPE_TEXT_ITER, &match_end, TRUE, TRUE));
return ret;
}
else
{
return_None;
}
}
%%
override moo_text_search_backward varargs
static PyObject *
_wrap_moo_text_search_backward (G_GNUC_UNUSED PyObject *self, PyObject *args)
{
PyObject *py_start, *py_flags, *py_end = Py_None;
char *str;
int flags;
const GtkTextIter *start, *end = NULL;
GtkTextIter match_start, match_end;
if (!PyArg_ParseTuple (args, (char*) "OsO|O:search_backward", &py_start, &str, &py_flags, &py_end))
return NULL;
if (pyg_boxed_check (py_start, GTK_TYPE_TEXT_ITER))
start = pyg_boxed_get (py_start, GtkTextIter);
else
return_TypeErr ("start should be a GtkTextIter");
if (pyg_flags_get_value (MOO_TYPE_TEXT_SEARCH_FLAGS, py_flags, &flags))
return NULL;
if (pyg_boxed_check(py_end, GTK_TYPE_TEXT_ITER))
end = pyg_boxed_get(py_end, GtkTextIter);
else if (py_end != Py_None)
return_TypeErr ("end should be a GtkTextIter or None");
if (moo_text_search_backward (start, str, flags, &match_start, &match_end, end))
{
PyObject *ret = PyTuple_New (2);
PyTuple_SET_ITEM (ret, 0, pyg_boxed_new (GTK_TYPE_TEXT_ITER, &match_start, TRUE, TRUE));
PyTuple_SET_ITEM (ret, 1, pyg_boxed_new (GTK_TYPE_TEXT_ITER, &match_end, TRUE, TRUE));
return ret;
}
else
{
return_None;
}
}

View File

@ -159,7 +159,7 @@ egg_regex_new (const gchar *pattern,
void
egg_regex_unref (EggRegex *regex)
{
if (--regex->ref_count)
if (!regex || --regex->ref_count)
return;
g_free (regex->pattern);
@ -172,10 +172,12 @@ egg_regex_unref (EggRegex *regex)
g_free (regex);
}
void
EggRegex *
egg_regex_ref (EggRegex *regex)
{
++regex->ref_count;
if (regex)
++regex->ref_count;
return regex;
}
void
@ -228,6 +230,8 @@ egg_regex_optimize (EggRegex *regex,
{
const gchar *errmsg;
g_return_if_fail (regex != NULL && regex->regex != NULL);
regex->extra = _pcre_study (regex->regex, 0, &errmsg);
if (errmsg)
@ -1115,9 +1119,15 @@ egg_regex_eval_replacement (EggRegex *regex,
GString *result;
GList *list;
g_return_val_if_fail (replacement != NULL, NULL);
if (!*replacement)
return g_strdup ("");
list = split_replacement (replacement, error);
if (!list) return NULL;
if (!list)
return NULL;
result = g_string_new (NULL);
interpolate_replacement (regex, string, result, list);
@ -1131,19 +1141,107 @@ egg_regex_eval_replacement (EggRegex *regex,
/**
* egg_regex_check_replacement:
* @replacement: replacement string
* @has_references: location for information about references
* @error: location to store error
*/
gboolean
egg_regex_check_replacement (const gchar *replacement,
GError **error)
egg_regex_check_replacement (const gchar *replacement,
gboolean *has_references,
GError **error)
{
GList *list;
GList *list, *l;
GError *tmp = NULL;
list = split_replacement (replacement, error);
list = split_replacement (replacement, &tmp);
if (!list) return FALSE;
if (tmp)
{
g_propagate_error (error, tmp);
return FALSE;
}
if (has_references)
{
*has_references = FALSE;
for (l = list; l != NULL; l = l->next)
{
InterpolationData *data = l->data;
if (data->type == REPL_TYPE_SYMBOLIC_REFERENCE ||
data->type == REPL_TYPE_NUMERIC_REFERENCE)
{
*has_references = TRUE;
break;
}
}
}
g_list_foreach (list, (GFunc)free_interpolation_data, NULL);
g_list_free (list);
return TRUE;
}
gchar*
egg_regex_try_eval_replacement (EggRegex *regex,
const gchar *replacement,
GError **error)
{
GList *list, *l;
GError *tmp = NULL;
GString *string;
gboolean result = TRUE;
InterpolationData *idata;
g_return_val_if_fail (regex != NULL, NULL);
g_return_val_if_fail (replacement != NULL, NULL);
if (!*replacement)
return g_strdup ("");
list = split_replacement (replacement, &tmp);
if (tmp)
{
g_propagate_error (error, tmp);
return NULL;
}
if (!list)
return g_strdup ("");
string = g_string_new (NULL);
for (l = list; l && result; l = l->next)
{
idata = l->data;
switch (idata->type)
{
case REPL_TYPE_STRING:
g_string_append (string, idata->text);
break;
case REPL_TYPE_CHARACTER:
g_string_append_c (string, idata->c);
break;
case REPL_TYPE_NUMERIC_REFERENCE:
case REPL_TYPE_SYMBOLIC_REFERENCE:
result = FALSE;
break;
}
}
g_list_foreach (list, (GFunc) free_interpolation_data, NULL);
g_list_free (list);
if (result)
{
return g_string_free (string, FALSE);
}
else
{
g_string_free (string, TRUE);
return NULL;
}
}

View File

@ -109,7 +109,8 @@ EggRegex *egg_regex_new (const gchar *pattern,
GError **error);
void egg_regex_optimize (EggRegex *regex,
GError **error);
void egg_regex_ref (EggRegex *regex);
/* ref() and unref() accept NULL */
EggRegex *egg_regex_ref (EggRegex *regex);
void egg_regex_unref (EggRegex *regex);
void egg_regex_free (EggRegex *regex);
/* FIXME */
@ -169,8 +170,12 @@ gchar *egg_regex_eval_replacement (EggRegex *regex,
const gchar *string,
const gchar *replacement,
GError **error);
gboolean egg_regex_check_replacement (const gchar *replacement,
GError **error);
gchar *egg_regex_try_eval_replacement (EggRegex *regex,
const gchar *replacement,
GError **error);
gboolean egg_regex_check_replacement (const gchar *replacement,
gboolean *has_references,
GError **error);
G_END_DECLS

View File

@ -33,6 +33,8 @@ struct _MooEntryPrivate {
gboolean enable_undo_menu;
guint user_action_stack;
guint use_ctrl_u : 1;
guint grab_selection : 1;
guint fool_entry : 1;
};
@ -50,6 +52,9 @@ static void moo_entry_get_property (GObject *object,
GValue *value,
GParamSpec *pspec);
static gboolean moo_entry_button_release (GtkWidget *widget,
GdkEventButton *event);
static void moo_entry_delete_to_start (MooEntry *entry);
static void moo_entry_populate_popup (GtkEntry *entry,
@ -78,6 +83,13 @@ static void moo_entry_insert_text (GtkEditable *editable,
static void moo_entry_delete_text (GtkEditable *editable,
gint start_pos,
gint end_pos);
static void moo_entry_set_selection_bounds (GtkEditable *editable,
gint start_pos,
gint end_pos);
static gboolean moo_entry_get_selection_bounds (GtkEditable *editable,
gint *start_pos,
gint *end_pos);
GType
@ -120,7 +132,8 @@ enum {
PROP_0,
PROP_UNDO_MANAGER,
PROP_ENABLE_UNDO,
PROP_ENABLE_UNDO_MENU
PROP_ENABLE_UNDO_MENU,
PROP_GRAB_SELECTION
};
enum {
@ -140,6 +153,7 @@ static void
moo_entry_class_init (MooEntryClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkEntryClass *entry_class = GTK_ENTRY_CLASS (klass);
GtkBindingSet *binding_set;
@ -147,6 +161,8 @@ moo_entry_class_init (MooEntryClass *klass)
gobject_class->set_property = moo_entry_set_property;
gobject_class->get_property = moo_entry_get_property;
widget_class->button_release_event = moo_entry_button_release;
entry_class->populate_popup = moo_entry_populate_popup;
entry_class->insert_at_cursor = moo_entry_insert_at_cursor;
entry_class->delete_from_cursor = moo_entry_delete_from_cursor;
@ -184,6 +200,14 @@ moo_entry_class_init (MooEntryClass *klass)
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_GRAB_SELECTION,
g_param_spec_boolean ("grab-selection",
"grab-selection",
"grab-selection",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
signals[UNDO] =
g_signal_new ("undo",
G_OBJECT_CLASS_TYPE (klass),
@ -249,6 +273,8 @@ moo_entry_editable_init (GtkEditableClass *klass)
klass->do_delete_text = moo_entry_do_delete_text;
klass->insert_text = moo_entry_insert_text;
klass->delete_text = moo_entry_delete_text;
klass->set_selection_bounds = moo_entry_set_selection_bounds;
klass->get_selection_bounds = moo_entry_get_selection_bounds;
}
@ -281,6 +307,11 @@ moo_entry_set_property (GObject *object,
g_object_notify (object, "enable-undo-menu");
break;
case PROP_GRAB_SELECTION:
entry->priv->grab_selection = g_value_get_boolean (value) ? TRUE : FALSE;
g_object_notify (object, "grab-selection");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -310,6 +341,10 @@ moo_entry_get_property (GObject *object,
g_value_set_object (value, entry->priv->undo_mgr);
break;
case PROP_GRAB_SELECTION:
g_value_set_boolean (value, entry->priv->grab_selection ? TRUE : FALSE);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -518,3 +553,48 @@ moo_entry_delete_to_start (MooEntry *entry)
gtk_editable_delete_text (GTK_EDITABLE (entry),
0, gtk_editable_get_position (GTK_EDITABLE (entry)));
}
/*********************************************************************/
/* Working around gtk idiotic selection business
*/
/* GtkEdiatble::delete_text and GtkWidget::realize might also require this hack */
static void
moo_entry_set_selection_bounds (GtkEditable *editable,
gint start_pos,
gint end_pos)
{
if (!MOO_ENTRY(editable)->priv->grab_selection)
MOO_ENTRY(editable)->priv->fool_entry = TRUE;
parent_editable_iface->set_selection_bounds (editable, start_pos, end_pos);
MOO_ENTRY(editable)->priv->fool_entry = FALSE;
}
static gboolean
moo_entry_get_selection_bounds (GtkEditable *editable,
gint *start_pos,
gint *end_pos)
{
if (MOO_ENTRY(editable)->priv->fool_entry)
return FALSE;
else
return parent_editable_iface->get_selection_bounds (editable, start_pos, end_pos);
}
static gboolean
moo_entry_button_release (GtkWidget *widget,
GdkEventButton *event)
{
gboolean result;
if (!MOO_ENTRY(widget)->priv->grab_selection)
MOO_ENTRY(widget)->priv->fool_entry = TRUE;
result = GTK_WIDGET_CLASS(moo_entry_parent_class)->button_release_event (widget, event);
MOO_ENTRY(widget)->priv->fool_entry = FALSE;
return result;
}