2005-09-09 02:40:10 -07:00
|
|
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
|
2005-09-09 02:54:58 -07:00
|
|
|
*
|
2005-09-09 02:40:10 -07:00
|
|
|
* mootextbuffer.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 MOOTEXT_BUFFER_COMPILATION
|
|
|
|
#include "mooedit/mootextbuffer.h"
|
|
|
|
#include "mooedit/mootextiter.h"
|
|
|
|
#include "mooutils/moomarshals.h"
|
|
|
|
|
|
|
|
|
|
|
|
struct _MooTextBufferPrivate {
|
|
|
|
MooEditLang *lang;
|
|
|
|
|
|
|
|
gboolean has_selection;
|
|
|
|
gboolean has_text;
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
gboolean check_brackets;
|
|
|
|
guint num_brackets;
|
|
|
|
gunichar *left_brackets, *right_brackets;
|
|
|
|
GtkTextTag *correct_match_tag;
|
|
|
|
GtkTextTag *incorrect_match_tag;
|
|
|
|
GtkTextMark *bracket_mark[4];
|
|
|
|
MooBracketMatchType bracket_found;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void moo_text_buffer_finalize (GObject *object);
|
|
|
|
|
|
|
|
static void moo_text_buffer_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void moo_text_buffer_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
|
|
|
static void moo_text_buffer_cursor_moved (MooTextBuffer *buffer,
|
2005-09-09 02:54:58 -07:00
|
|
|
const GtkTextIter *iter);
|
2005-09-09 02:40:10 -07:00
|
|
|
static void moo_text_buffer_mark_set (GtkTextBuffer *buffer,
|
|
|
|
const GtkTextIter *iter,
|
|
|
|
GtkTextMark *mark);
|
|
|
|
static void moo_text_buffer_insert_text (GtkTextBuffer *buffer,
|
|
|
|
GtkTextIter *pos,
|
|
|
|
const gchar *text,
|
|
|
|
gint length);
|
|
|
|
static void moo_text_buffer_delete_range (GtkTextBuffer *buffer,
|
|
|
|
GtkTextIter *start,
|
|
|
|
GtkTextIter *end);
|
|
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
CURSOR_MOVED,
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL];
|
|
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
PROP_0,
|
|
|
|
PROP_CHECK_BRACKETS,
|
|
|
|
PROP_BRACKET_MATCH_STYLE,
|
|
|
|
PROP_HAS_TEXT,
|
|
|
|
PROP_HAS_SELECTION
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* MOO_TYPE_TEXT_BUFFER */
|
|
|
|
G_DEFINE_TYPE (MooTextBuffer, moo_text_buffer, GTK_TYPE_SOURCE_BUFFER)
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
static void
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_class_init (MooTextBufferClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
GtkTextBufferClass *buffer_class = GTK_TEXT_BUFFER_CLASS (klass);
|
|
|
|
|
|
|
|
gobject_class->set_property = moo_text_buffer_set_property;
|
|
|
|
gobject_class->get_property = moo_text_buffer_get_property;
|
|
|
|
gobject_class->finalize = moo_text_buffer_finalize;
|
|
|
|
|
|
|
|
buffer_class->mark_set = moo_text_buffer_mark_set;
|
|
|
|
buffer_class->insert_text = moo_text_buffer_insert_text;
|
|
|
|
buffer_class->delete_range = moo_text_buffer_delete_range;
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
klass->cursor_moved = moo_text_buffer_cursor_moved;
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
g_object_class_install_property (gobject_class,
|
|
|
|
PROP_CHECK_BRACKETS,
|
|
|
|
g_param_spec_boolean ("check-brackets",
|
|
|
|
"check-brackets",
|
|
|
|
"check-brackets",
|
|
|
|
TRUE,
|
|
|
|
G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
|
|
|
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
|
|
PROP_BRACKET_MATCH_STYLE,
|
|
|
|
g_param_spec_boxed ("bracket-match-style",
|
|
|
|
"bracket-match-style",
|
|
|
|
"bracket-match-style",
|
|
|
|
GTK_TYPE_SOURCE_TAG_STYLE,
|
|
|
|
G_PARAM_CONSTRUCT | G_PARAM_WRITABLE));
|
|
|
|
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
|
|
PROP_HAS_TEXT,
|
|
|
|
g_param_spec_boolean ("has-text",
|
|
|
|
"has-text",
|
|
|
|
"has-text",
|
|
|
|
FALSE,
|
|
|
|
G_PARAM_READABLE));
|
|
|
|
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
|
|
PROP_HAS_SELECTION,
|
|
|
|
g_param_spec_boolean ("has-selection",
|
|
|
|
"has-selection",
|
|
|
|
"has-selection",
|
|
|
|
FALSE,
|
|
|
|
G_PARAM_READABLE));
|
|
|
|
|
|
|
|
signals[CURSOR_MOVED] =
|
|
|
|
g_signal_new ("cursor-moved",
|
|
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
|
|
|
G_STRUCT_OFFSET (MooTextBufferClass, cursor_moved),
|
|
|
|
NULL, NULL,
|
|
|
|
_moo_marshal_VOID__BOXED,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
GTK_TYPE_TEXT_ITER);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
static void
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_init (MooTextBuffer *buffer)
|
|
|
|
{
|
|
|
|
buffer->priv = g_new0 (MooTextBufferPrivate, 1);
|
|
|
|
buffer->priv->check_brackets = TRUE;
|
|
|
|
buffer->priv->bracket_found = MOO_BRACKET_MATCH_NONE;
|
|
|
|
moo_text_buffer_set_brackets (buffer, NULL);
|
|
|
|
gtk_source_buffer_set_check_brackets (GTK_SOURCE_BUFFER (buffer), FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
static void
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MooTextBuffer *buffer = MOO_TEXT_BUFFER (object);
|
|
|
|
|
|
|
|
if (buffer->priv->lang)
|
|
|
|
g_object_unref (buffer->priv->lang);
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-10 09:02:38 -07:00
|
|
|
g_free (buffer->priv->left_brackets);
|
|
|
|
g_free (buffer->priv->right_brackets);
|
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
g_free (buffer->priv);
|
|
|
|
buffer->priv = NULL;
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (moo_text_buffer_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
void
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_set_lang (MooTextBuffer *buffer,
|
|
|
|
MooEditLang *lang)
|
|
|
|
{
|
|
|
|
GtkTextTagTable *table;
|
|
|
|
|
|
|
|
g_return_if_fail (MOO_IS_TEXT_BUFFER (buffer));
|
|
|
|
|
|
|
|
if (lang == buffer->priv->lang)
|
|
|
|
return;
|
|
|
|
|
|
|
|
table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (buffer));
|
|
|
|
gtk_source_tag_table_remove_source_tags (GTK_SOURCE_TAG_TABLE (table));
|
|
|
|
|
|
|
|
if (buffer->priv->lang)
|
|
|
|
{
|
|
|
|
g_object_unref (buffer->priv->lang);
|
|
|
|
buffer->priv->lang = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lang)
|
|
|
|
{
|
|
|
|
GSList *tags;
|
|
|
|
gunichar escape_char;
|
|
|
|
|
|
|
|
buffer->priv->lang = lang;
|
|
|
|
g_object_ref (buffer->priv->lang);
|
|
|
|
|
|
|
|
tags = moo_edit_lang_get_tags (lang);
|
|
|
|
gtk_source_tag_table_add_tags (GTK_SOURCE_TAG_TABLE (table), tags);
|
|
|
|
g_slist_foreach (tags, (GFunc) g_object_unref, NULL);
|
|
|
|
g_slist_free (tags);
|
|
|
|
|
|
|
|
escape_char = moo_edit_lang_get_escape_char (lang);
|
|
|
|
gtk_source_buffer_set_escape_char (GTK_SOURCE_BUFFER (buffer),
|
|
|
|
escape_char);
|
|
|
|
|
|
|
|
moo_text_buffer_set_brackets (buffer, moo_edit_lang_get_brackets (lang));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gtk_source_buffer_set_escape_char (GTK_SOURCE_BUFFER (buffer), '\\');
|
|
|
|
moo_text_buffer_set_brackets (buffer, "{}()[]");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
static gboolean
|
2005-09-09 02:40:10 -07:00
|
|
|
find (gunichar *vec, guint size, gunichar c)
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
for (i = 0; i < size; ++i)
|
|
|
|
if (c == vec[i])
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
gboolean
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_iter_at_bracket (GtkTextIter *iter)
|
|
|
|
{
|
|
|
|
gunichar c;
|
|
|
|
GtkTextIter b;
|
|
|
|
MooTextBuffer *buffer;
|
|
|
|
|
|
|
|
buffer = MOO_TEXT_BUFFER (gtk_text_iter_get_buffer (iter));
|
|
|
|
g_return_val_if_fail (MOO_IS_TEXT_BUFFER (buffer), FALSE);
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
c = gtk_text_iter_get_char (iter);
|
|
|
|
|
|
|
|
if (find (buffer->priv->left_brackets, buffer->priv->num_brackets, c) ||
|
|
|
|
find (buffer->priv->right_brackets, buffer->priv->num_brackets, c))
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
b = *iter;
|
|
|
|
|
|
|
|
if (!gtk_text_iter_starts_line (&b) && gtk_text_iter_backward_char (&b))
|
|
|
|
{
|
|
|
|
c = gtk_text_iter_get_char (&b);
|
|
|
|
|
|
|
|
if (find (buffer->priv->left_brackets, buffer->priv->num_brackets, c) ||
|
|
|
|
find (buffer->priv->right_brackets, buffer->priv->num_brackets, c))
|
|
|
|
{
|
|
|
|
*iter = b;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
MooBracketMatchType
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_iter_find_matching_bracket (GtkTextIter *iter)
|
|
|
|
{
|
|
|
|
int addition = 0;
|
|
|
|
gunichar *same_direction = NULL, *inverse_direction = NULL;
|
|
|
|
guint to_find;
|
|
|
|
gunichar bracket = gtk_text_iter_get_char (iter);
|
|
|
|
gunichar bracket_to_find = 0;
|
|
|
|
const GtkTextTag *tag;
|
|
|
|
guint stack = 0;
|
|
|
|
GtkTextIter b;
|
|
|
|
|
|
|
|
MooTextBuffer *buffer = MOO_TEXT_BUFFER (gtk_text_iter_get_buffer (iter));
|
|
|
|
g_return_val_if_fail (MOO_IS_TEXT_BUFFER (buffer), MOO_BRACKET_MATCH_NOT_AT_BRACKET);
|
|
|
|
|
|
|
|
for (to_find = 0; to_find < buffer->priv->num_brackets; ++to_find)
|
|
|
|
if (bracket == buffer->priv->left_brackets[to_find])
|
|
|
|
{
|
|
|
|
bracket_to_find = buffer->priv->right_brackets[to_find];
|
|
|
|
addition = 1;
|
|
|
|
inverse_direction = buffer->priv->right_brackets;
|
|
|
|
same_direction = buffer->priv->left_brackets;
|
|
|
|
break;
|
|
|
|
}
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
if (to_find == buffer->priv->num_brackets)
|
|
|
|
for (to_find = 0; to_find < buffer->priv->num_brackets; ++to_find)
|
|
|
|
if (bracket == buffer->priv->right_brackets[to_find])
|
|
|
|
{
|
|
|
|
bracket_to_find = buffer->priv->left_brackets[to_find];
|
2005-09-12 07:02:06 -07:00
|
|
|
addition = -1;
|
2005-09-09 02:40:10 -07:00
|
|
|
same_direction = buffer->priv->right_brackets;
|
|
|
|
inverse_direction = buffer->priv->left_brackets;
|
|
|
|
break;
|
|
|
|
}
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
if (to_find == buffer->priv->num_brackets)
|
|
|
|
return MOO_BRACKET_MATCH_NOT_AT_BRACKET;
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
tag = gtk_source_iter_has_syntax_tag (iter);
|
|
|
|
stack = 0;
|
|
|
|
b = *iter;
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
while (gtk_text_iter_forward_chars (&b, addition))
|
|
|
|
{
|
|
|
|
if (tag == gtk_source_iter_has_syntax_tag (&b))
|
|
|
|
{
|
|
|
|
gunichar c = gtk_text_iter_get_char (&b);
|
|
|
|
if (c == bracket_to_find && !stack)
|
|
|
|
{
|
|
|
|
*iter = b;
|
|
|
|
return MOO_BRACKET_MATCH_CORRECT;
|
|
|
|
}
|
2005-09-09 02:54:58 -07:00
|
|
|
|
|
|
|
if (find (same_direction, buffer->priv->num_brackets, c))
|
2005-09-09 02:40:10 -07:00
|
|
|
{
|
|
|
|
++stack;
|
|
|
|
}
|
|
|
|
else if (find (inverse_direction, buffer->priv->num_brackets, c))
|
|
|
|
{
|
|
|
|
if (stack)
|
|
|
|
{
|
|
|
|
--stack;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*iter = b;
|
|
|
|
return MOO_BRACKET_MATCH_INCORRECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
return MOO_BRACKET_MATCH_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
static void
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_cursor_moved (MooTextBuffer *buffer,
|
|
|
|
const GtkTextIter *where)
|
|
|
|
{
|
|
|
|
GtkTextIter iter[4];
|
|
|
|
MooBracketMatchType bracket_match;
|
|
|
|
GtkTextTag *tag;
|
|
|
|
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (buffer);
|
|
|
|
int i;
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
g_return_if_fail (where != NULL);
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
switch (buffer->priv->bracket_found)
|
|
|
|
{
|
|
|
|
case MOO_BRACKET_MATCH_CORRECT:
|
|
|
|
tag = buffer->priv->correct_match_tag;
|
|
|
|
break;
|
|
|
|
case MOO_BRACKET_MATCH_INCORRECT:
|
|
|
|
tag = buffer->priv->incorrect_match_tag;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tag = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tag)
|
|
|
|
{
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
|
|
gtk_text_buffer_get_iter_at_mark (text_buffer, &iter[i],
|
2005-09-09 02:54:58 -07:00
|
|
|
buffer->priv->bracket_mark[i]);
|
2005-09-09 02:40:10 -07:00
|
|
|
gtk_text_buffer_remove_tag (text_buffer, tag, &iter[0], &iter[1]);
|
|
|
|
gtk_text_buffer_remove_tag (text_buffer, tag, &iter[2], &iter[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!buffer->priv->check_brackets)
|
|
|
|
return;
|
|
|
|
|
|
|
|
iter[0] = *where;
|
|
|
|
|
|
|
|
buffer->priv->bracket_found = MOO_BRACKET_MATCH_NONE;
|
|
|
|
|
|
|
|
if (!moo_text_iter_at_bracket (&iter[0]))
|
|
|
|
return;
|
|
|
|
|
|
|
|
iter[2] = iter[0];
|
|
|
|
bracket_match = moo_text_iter_find_matching_bracket (&iter[2]); /* TODO: max chars*/
|
|
|
|
|
|
|
|
buffer->priv->bracket_found = bracket_match;
|
|
|
|
|
|
|
|
switch (bracket_match)
|
|
|
|
{
|
|
|
|
case MOO_BRACKET_MATCH_CORRECT:
|
|
|
|
tag = buffer->priv->correct_match_tag;
|
|
|
|
break;
|
|
|
|
case MOO_BRACKET_MATCH_INCORRECT:
|
|
|
|
tag = buffer->priv->incorrect_match_tag;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tag = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tag != NULL)
|
|
|
|
{
|
|
|
|
iter[1] = iter[0];
|
|
|
|
gtk_text_iter_forward_char (&iter[1]);
|
|
|
|
iter[3] = iter[2];
|
|
|
|
gtk_text_iter_forward_char (&iter[3]);
|
|
|
|
|
|
|
|
if (!buffer->priv->bracket_mark[0])
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
|
|
buffer->priv->bracket_mark[i] =
|
|
|
|
gtk_text_buffer_create_mark (text_buffer, NULL, &iter[i], FALSE);
|
|
|
|
else
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
|
|
gtk_text_buffer_move_mark (text_buffer, buffer->priv->bracket_mark[i], &iter[i]);
|
|
|
|
|
|
|
|
gtk_text_buffer_apply_tag (text_buffer, tag, &iter[0], &iter[1]);
|
|
|
|
gtk_text_buffer_apply_tag (text_buffer, tag, &iter[2], &iter[3]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
moo_text_buffer_mark_set (GtkTextBuffer *text_buffer,
|
|
|
|
const GtkTextIter *iter,
|
|
|
|
GtkTextMark *mark)
|
|
|
|
{
|
|
|
|
GtkTextMark *insert = gtk_text_buffer_get_insert (text_buffer);
|
|
|
|
GtkTextMark *sel_bound = gtk_text_buffer_get_selection_bound (text_buffer);
|
|
|
|
MooTextBuffer *buffer = MOO_TEXT_BUFFER (text_buffer);
|
|
|
|
gboolean has_selection = buffer->priv->has_selection;
|
|
|
|
|
|
|
|
if (GTK_TEXT_BUFFER_CLASS(moo_text_buffer_parent_class)->mark_set)
|
|
|
|
GTK_TEXT_BUFFER_CLASS(moo_text_buffer_parent_class)->mark_set (text_buffer, iter, mark);
|
|
|
|
|
|
|
|
if (mark == insert)
|
|
|
|
{
|
|
|
|
GtkTextIter iter2;
|
|
|
|
gtk_text_buffer_get_iter_at_mark (text_buffer, &iter2, sel_bound);
|
|
|
|
has_selection = gtk_text_iter_compare (iter, &iter2) ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
else if (mark == sel_bound)
|
|
|
|
{
|
|
|
|
GtkTextIter iter2;
|
|
|
|
gtk_text_buffer_get_iter_at_mark (text_buffer, &iter2, insert);
|
|
|
|
has_selection = gtk_text_iter_compare (iter, &iter2) ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (has_selection != buffer->priv->has_selection)
|
|
|
|
{
|
|
|
|
buffer->priv->has_selection = has_selection;
|
|
|
|
g_object_notify (G_OBJECT (buffer), "has-selection");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mark == insert)
|
|
|
|
g_signal_emit (buffer, signals[CURSOR_MOVED], 0, iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
static void
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_insert_text (GtkTextBuffer *text_buffer,
|
|
|
|
GtkTextIter *pos,
|
|
|
|
const gchar *text,
|
|
|
|
gint length)
|
|
|
|
{
|
|
|
|
MooTextBuffer *buffer = MOO_TEXT_BUFFER (text_buffer);
|
|
|
|
|
|
|
|
if (GTK_TEXT_BUFFER_CLASS(moo_text_buffer_parent_class)->insert_text)
|
|
|
|
GTK_TEXT_BUFFER_CLASS(moo_text_buffer_parent_class)->insert_text (text_buffer, pos, text, length);
|
|
|
|
|
|
|
|
g_signal_emit (buffer, signals[CURSOR_MOVED], 0, pos);
|
|
|
|
|
|
|
|
if (!buffer->priv->has_text)
|
|
|
|
{
|
|
|
|
buffer->priv->has_text = TRUE;
|
|
|
|
g_object_notify (G_OBJECT (buffer), "has-text");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
static void
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_delete_range (GtkTextBuffer *text_buffer,
|
|
|
|
GtkTextIter *start,
|
|
|
|
GtkTextIter *end)
|
|
|
|
{
|
|
|
|
MooTextBuffer *buffer = MOO_TEXT_BUFFER (text_buffer);
|
|
|
|
|
|
|
|
if (GTK_TEXT_BUFFER_CLASS(moo_text_buffer_parent_class)->delete_range)
|
|
|
|
GTK_TEXT_BUFFER_CLASS(moo_text_buffer_parent_class)->delete_range (text_buffer, start, end);
|
|
|
|
|
|
|
|
g_signal_emit (buffer, signals[CURSOR_MOVED], 0, start);
|
|
|
|
|
|
|
|
if (buffer->priv->has_text)
|
|
|
|
{
|
|
|
|
buffer->priv->has_text = moo_text_buffer_has_text (buffer);
|
|
|
|
if (!buffer->priv->has_text)
|
|
|
|
g_object_notify (G_OBJECT (buffer), "has-text");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
static void
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MooTextBuffer *buffer = MOO_TEXT_BUFFER (object);
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_BRACKET_MATCH_STYLE:
|
|
|
|
moo_text_buffer_set_bracket_match_style (buffer,
|
|
|
|
g_value_get_boxed (value));
|
|
|
|
break;
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
case PROP_CHECK_BRACKETS:
|
2005-09-09 02:54:58 -07:00
|
|
|
moo_text_buffer_set_check_brackets (buffer,
|
2005-09-09 02:40:10 -07:00
|
|
|
g_value_get_boolean (value));
|
|
|
|
break;
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
static void
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MooTextBuffer *buffer = MOO_TEXT_BUFFER (object);
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_CHECK_BRACKETS:
|
|
|
|
g_value_set_boolean (value, buffer->priv->check_brackets);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_HAS_TEXT:
|
|
|
|
g_value_set_boolean (value, moo_text_buffer_has_text (buffer));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_HAS_SELECTION:
|
|
|
|
g_value_set_boolean (value, moo_text_buffer_has_selection (buffer));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
moo_text_buffer_set_bracket_match_style (MooTextBuffer *buffer,
|
|
|
|
const GtkSourceTagStyle *style)
|
|
|
|
{
|
|
|
|
GtkSourceTagStyle *freeme = NULL;
|
|
|
|
const GdkColor *bg = NULL, *fg = NULL;
|
|
|
|
int weight = PANGO_WEIGHT_NORMAL;
|
|
|
|
PangoUnderline underline = PANGO_UNDERLINE_NONE;
|
|
|
|
PangoStyle italic = PANGO_STYLE_NORMAL;
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
g_return_if_fail (MOO_IS_TEXT_BUFFER (buffer));
|
|
|
|
|
|
|
|
if (!style)
|
|
|
|
{
|
|
|
|
freeme = gtk_source_tag_style_new ();
|
|
|
|
freeme->is_default = FALSE;
|
|
|
|
freeme->mask = GTK_SOURCE_TAG_STYLE_USE_BACKGROUND;
|
|
|
|
gdk_color_parse ("yellow", &freeme->background);
|
|
|
|
freeme->italic = FALSE;
|
|
|
|
freeme->bold = FALSE;
|
|
|
|
freeme->underline = FALSE;
|
|
|
|
freeme->strikethrough = FALSE;
|
|
|
|
|
|
|
|
style = freeme;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!buffer->priv->correct_match_tag)
|
2005-09-09 02:54:58 -07:00
|
|
|
buffer->priv->correct_match_tag =
|
2005-09-09 02:40:10 -07:00
|
|
|
gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (buffer), NULL, NULL);
|
|
|
|
|
|
|
|
if (style->mask & GTK_SOURCE_TAG_STYLE_USE_BACKGROUND)
|
|
|
|
bg = &style->background;
|
|
|
|
if (style->mask & GTK_SOURCE_TAG_STYLE_USE_FOREGROUND)
|
|
|
|
bg = &style->foreground;
|
|
|
|
if (style->italic)
|
|
|
|
italic = PANGO_STYLE_ITALIC;
|
|
|
|
if (style->bold)
|
|
|
|
weight = PANGO_WEIGHT_BOLD;
|
|
|
|
if (style->underline)
|
|
|
|
underline = PANGO_UNDERLINE_SINGLE;
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
g_object_set (buffer->priv->correct_match_tag,
|
2005-09-09 02:40:10 -07:00
|
|
|
"foreground-gdk", fg,
|
|
|
|
"background-gdk", bg,
|
|
|
|
"style", italic,
|
|
|
|
"weight", weight,
|
|
|
|
"underline", underline,
|
|
|
|
"strikethrough", style->strikethrough,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (buffer), "bracket-match-style");
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
if (freeme)
|
|
|
|
gtk_source_tag_style_free (freeme);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
parse_brackets (const char *string,
|
|
|
|
gunichar **left_brackets,
|
|
|
|
gunichar **right_brackets,
|
|
|
|
guint *num)
|
|
|
|
{
|
|
|
|
long len, i;
|
|
|
|
const char *p;
|
|
|
|
gunichar *left, *right;
|
|
|
|
|
|
|
|
g_return_val_if_fail (g_utf8_validate (string, -1, NULL), FALSE);
|
|
|
|
len = g_utf8_strlen (string, -1);
|
|
|
|
g_return_val_if_fail (len > 0 && (len / 2) * 2 == len, FALSE);
|
|
|
|
|
|
|
|
len /= 2;
|
|
|
|
p = string;
|
|
|
|
left = g_new (gunichar, len);
|
|
|
|
right = g_new (gunichar, len);
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
for (i = 0; i < len; ++i)
|
2005-09-09 02:40:10 -07:00
|
|
|
{
|
|
|
|
left[i] = g_utf8_get_char (p);
|
|
|
|
p = g_utf8_next_char (p);
|
|
|
|
right[i] = g_utf8_get_char (p);
|
|
|
|
p = g_utf8_next_char (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
*left_brackets = left;
|
|
|
|
*right_brackets = right;
|
|
|
|
*num = len;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
moo_text_buffer_set_brackets (MooTextBuffer *buffer,
|
|
|
|
const gchar *string)
|
|
|
|
{
|
|
|
|
g_return_if_fail (MOO_IS_TEXT_BUFFER (buffer));
|
|
|
|
|
|
|
|
buffer->priv->num_brackets = 0;
|
|
|
|
g_free (buffer->priv->left_brackets);
|
|
|
|
buffer->priv->left_brackets = NULL;
|
|
|
|
g_free (buffer->priv->right_brackets);
|
|
|
|
buffer->priv->right_brackets = NULL;
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
if (!string)
|
2005-09-09 02:40:10 -07:00
|
|
|
{
|
|
|
|
buffer->priv->num_brackets = 3;
|
|
|
|
buffer->priv->left_brackets = g_new (gunichar, 3);
|
|
|
|
buffer->priv->right_brackets = g_new (gunichar, 3);
|
|
|
|
buffer->priv->left_brackets[0] = '(';
|
|
|
|
buffer->priv->left_brackets[1] = '{';
|
|
|
|
buffer->priv->left_brackets[2] = '[';
|
|
|
|
buffer->priv->right_brackets[0] = ')';
|
|
|
|
buffer->priv->right_brackets[1] = '}';
|
|
|
|
buffer->priv->right_brackets[2] = ']';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (!string[0])
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_brackets (string,
|
|
|
|
&(buffer->priv->left_brackets),
|
|
|
|
&(buffer->priv->right_brackets),
|
|
|
|
&(buffer->priv->num_brackets));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
void
|
|
|
|
moo_text_buffer_set_check_brackets (MooTextBuffer *buffer,
|
2005-09-09 02:40:10 -07:00
|
|
|
gboolean check)
|
|
|
|
{
|
|
|
|
g_return_if_fail (MOO_IS_TEXT_BUFFER (buffer));
|
|
|
|
buffer->priv->check_brackets = check ? TRUE : FALSE;
|
|
|
|
g_object_notify (G_OBJECT (buffer), "check-brackets");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
gboolean
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_has_text (MooTextBuffer *buffer)
|
|
|
|
{
|
|
|
|
GtkTextIter start, end;
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
g_return_val_if_fail (MOO_IS_TEXT_BUFFER (buffer), TRUE);
|
2005-09-09 02:54:58 -07:00
|
|
|
|
2005-09-09 02:40:10 -07:00
|
|
|
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (buffer), &start, &end);
|
|
|
|
return gtk_text_iter_compare (&start, &end) ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-09 02:54:58 -07:00
|
|
|
gboolean
|
2005-09-09 02:40:10 -07:00
|
|
|
moo_text_buffer_has_selection (MooTextBuffer *buffer)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (MOO_IS_TEXT_BUFFER (buffer), FALSE);
|
|
|
|
return gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (buffer), NULL, NULL);
|
|
|
|
}
|