Started regex-based indenter

master
Yevgen Muntyan 2007-07-31 11:52:04 -05:00
parent c2ca12a203
commit e2279c8e5b
11 changed files with 635 additions and 60 deletions

View File

@ -1,8 +1,8 @@
# XXX it needs plugins to be built first but plugins want mooedit-enums.h # XXX it needs plugins to be built first but plugins want mooedit-enums.h
SUBDIRS = gtksourceview plugins language-specs SUBDIRS = gtksourceview plugins language-specs
mooedit_toolsdir = $(MOO_DATA_DIR) mooedit_datadir = $(MOO_DATA_DIR)
mooedit_tools_DATA = context.cfg menu.cfg filters.xml mooedit_data_DATA = context.cfg menu.cfg filters.xml indent.xml
moocommand-exe.lo: moocommand-exe-unix.lo moocommand-exe.lo: moocommand-exe-unix.lo
moocommand-exe-private.lo: moocommand-exe-unix.lo moocommand-exe-private.lo: moocommand-exe-unix.lo
@ -13,7 +13,9 @@ objc_sources = \
mooedit-script.h \ mooedit-script.h \
mooedit-script.m \ mooedit-script.m \
moocommand-script.h \ moocommand-script.h \
moocommand-script.m moocommand-script.m \
mooindenter-regex.h \
mooindenter-regex.m
unix_sources = \ unix_sources = \
moocommand-exe-unix.c moocommand-exe-unix.c
@ -209,7 +211,7 @@ CLEANFILES += mooedit-ui.h medit-ui.h
EXTRA_DIST += \ EXTRA_DIST += \
$(completion_sources) \ $(completion_sources) \
$(mooedit_tools_DATA) \ $(mooedit_data_DATA) \
medit-ui.xml \ medit-ui.xml \
mooedit-ui.xml mooedit-ui.xml

6
moo/mooedit/indent.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<indent-settings version="1">
<lang id="python">
<shift pattern=":\s*$"/>
</lang>
</indent-settings>

View File

@ -249,7 +249,7 @@ moo_edit_init (MooEdit *edit)
edit->priv->actions = moo_action_collection_new ("MooEdit", "MooEdit"); edit->priv->actions = moo_action_collection_new ("MooEdit", "MooEdit");
indent = moo_indenter_new (edit, NULL); indent = moo_indenter_new (edit);
moo_text_view_set_indenter (MOO_TEXT_VIEW (edit), indent); moo_text_view_set_indenter (MOO_TEXT_VIEW (edit), indent);
g_object_unref (indent); g_object_unref (indent);
} }
@ -946,6 +946,13 @@ moo_edit_set_lang (MooEdit *edit,
_moo_lang_mgr_update_config (moo_editor_get_lang_mgr (edit->priv->editor), _moo_lang_mgr_update_config (moo_editor_get_lang_mgr (edit->priv->editor),
edit->config, _moo_lang_id (lang)); edit->config, _moo_lang_id (lang));
_moo_edit_update_config_from_global (edit); _moo_edit_update_config_from_global (edit);
{
MooIndenter *indenter = moo_text_view_get_indenter (MOO_TEXT_VIEW (edit));
if (indenter)
g_object_set (indenter, "id", lang ? _moo_lang_id (lang) : NULL, NULL);
}
g_object_notify (G_OBJECT (edit), "has-comments"); g_object_notify (G_OBJECT (edit), "has-comments");
} }
} }

View File

@ -1420,7 +1420,7 @@ handle_backspace (MooTextView *view,
if (gtk_text_iter_starts_line (&end)) if (gtk_text_iter_starts_line (&end))
return FALSE; return FALSE;
tab_width = view->priv->indenter->tab_width; tab_width = moo_indenter_get_tab_width (view->priv->indenter);
offset = moo_iter_get_blank_offset (&end, tab_width); offset = moo_iter_get_blank_offset (&end, tab_width);
if (offset < 0) if (offset < 0)

View File

@ -0,0 +1,42 @@
/*
* mooindenter-settings.h
*
* Copyright (C) 2004-2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#ifndef MOOEDIT_COMPILATION
#error "This file may not be included"
#endif
#ifndef MOO_INDENTER_SETTINGS_H
#define MOO_INDENTER_SETTINGS_H
#include "mooindenter.h"
G_BEGIN_DECLS
#ifdef __OBJC__
@class MooIndenterRegex;
#else
typedef struct MooIndenterRegex MooIndenterRegex;
#endif
MooIndenterRegex *_moo_indenter_get_regex (const char *id_);
MooIndenterRegex *_moo_indenter_regex_ref (MooIndenterRegex *regex);
void _moo_indenter_regex_unref (MooIndenterRegex *regex);
gboolean _moo_indenter_regex_newline (MooIndenterRegex *regex,
MooIndenter *indenter,
GtkTextIter *where);
G_END_DECLS
#endif /* MOO_INDENTER_SETTINGS_H */

View File

@ -0,0 +1,371 @@
/* -*- objc -*-
* mooindenter-settings.m
*
* Copyright (C) 2004-2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#define MOOEDIT_COMPILATION
#include "mooedit/mooindenter-regex.h"
#include "mooutils/moocobject.h"
#include "mooutils/moomarkup.h"
#include "mooutils/mooutils-misc.h"
#include <glib/gregex.h>
static GHashTable *regex_hash;
@protocol MooIndenterElm
- (BOOL) newline: (MooIndenter*)indenter
text: (const char*)text
cursor: (GtkTextIter*)cursor
start: (GtkTextIter*)start
end: (GtkTextIter*)end;
@end
typedef MooCObject<MooIndenterElm> MooIndenterElm;
@interface MooIndenterShift : MooCObject <MooIndenterElm>
{
GRegex *re;
}
- init: (const char*)pattern;
@end;
@interface MooIndenterRegex : MooCObject
{
char *id_;
GRegex *re_all;
guint n_elms;
MooIndenterElm **elms;
}
- initWithMarkup: (MooMarkupNode*)node
lang_id: (const char*)lang_id
filename: (const char*)filename;
- (BOOL) newline: (MooIndenter*)indenter
where: (GtkTextIter*)where;
+ (void) loadSettings;
@end
@implementation MooIndenterRegex
+ (void) loadSettings
{
char *filename = NULL;
MooMarkupDoc *doc;
MooMarkupNode *root, *node;
const char *version;
GError *error = NULL;
MooIndenterRegex *re;
if (regex_hash)
return;
regex_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) _moo_indenter_regex_unref);
filename = moo_get_data_file ("indent.xml");
if (!filename)
return;
doc = moo_markup_parse_file (filename, &error);
if (!doc)
{
g_warning ("%s: %s", G_STRLOC, error->message);
g_free (error);
goto out;
}
if (!(root = moo_markup_get_root_element (doc, "indent-settings")))
{
g_warning ("%s: 'indent-settings' element missing", G_STRLOC);
goto out;
}
version = moo_markup_get_prop (root, "version");
if (!version || strcmp (version, "1") != 0)
{
g_warning ("%s: invalid version '%s'", G_STRLOC,
version ? version : "(null)");
goto out;
}
for (node = root->children; node != NULL; node = node->next)
{
const char *lang_id;
if (!MOO_MARKUP_IS_ELEMENT (node))
continue;
if (strcmp (node->name, "lang") != 0)
{
g_warning ("%s: invalid element '%s'", G_STRLOC, node->name);
goto out;
}
lang_id = moo_markup_get_prop (node, "id");
if (!lang_id)
{
g_warning ("%s: 'id' attribute missing in file '%s'", G_STRLOC, filename);
goto out;
}
re = [[self alloc] initWithMarkup:node lang_id:lang_id filename:filename];
if (!re)
goto out;
g_hash_table_insert (regex_hash, g_strdup (re->id_), re);
}
out:
g_free (filename);
if (doc)
moo_markup_doc_unref (doc);
}
- initWithMarkup: (MooMarkupNode*)elm
lang_id: (const char*)lang_id
filename: (const char*)filename
{
MooMarkupNode *node;
GSList *elements = NULL;
GString *pattern_all;
GError *error = NULL;
guint i;
[super init];
id_ = g_strdup (lang_id);
pattern_all = NULL;
for (node = elm->children; node != NULL; node = node->next)
{
if (!MOO_MARKUP_IS_ELEMENT (node))
continue;
if (!strcmp (node->name, "shift"))
{
const char *pattern = moo_markup_get_prop (node, "pattern");
MooIndenterElm *elm = [[MooIndenterShift alloc] init:pattern];
if (!elm)
goto error;
elements = g_slist_prepend (elements, elm);
if (!pattern_all)
{
pattern_all = g_string_new ("(");
g_string_append (pattern_all, pattern);
}
else
{
g_string_append_printf (pattern_all, "|%s", pattern);
}
}
else
{
g_warning ("in file %s: invalid element '%s' in lang '%s'",
filename, node->name, lang_id);
goto error;
}
}
if (!elements)
{
g_warning ("in file %s: empty lang '%s' node",
filename, lang_id);
goto error;
}
g_string_append (pattern_all, ")");
re_all = g_regex_new (pattern_all->str, G_REGEX_DUPNAMES | G_REGEX_OPTIMIZE,
0, &error);
if (!re_all)
{
g_warning ("in file %s: could not compile resulting regex '%s': %s",
filename, pattern_all->str, error->message);
g_error_free (error);
goto error;
}
elements = g_slist_reverse (elements);
n_elms = g_slist_length (elements);
elms = g_new (MooIndenterElm*, n_elms);
for (i = 0; i < n_elms; ++i)
{
elms[i] = elements->data;
elements = g_slist_delete_link (elements, elements);
}
g_string_free (pattern_all, TRUE);
return self;
error:
while (elements)
{
[(id) elements->data release];
elements = g_slist_delete_link (elements, elements);
}
g_string_free (pattern_all, TRUE);
[self release];
return nil;
}
- (void) dealloc
{
guint i;
g_free (id_);
if (re_all)
g_regex_unref (re_all);
for (i = 0; i < n_elms; ++i)
[elms[i] release];
g_free (elms);
[super dealloc];
}
- (BOOL) newline: (MooIndenter*)indenter
where: (GtkTextIter*)where
{
guint i;
GtkTextIter start, end;
char *text;
BOOL handled;
start = *where;
gtk_text_iter_backward_line (&start);
if (gtk_text_iter_ends_line (&start))
return NO;
end = start;
gtk_text_iter_forward_to_line_end (&end);
text = gtk_text_iter_get_slice (&start, &end);
if (!g_regex_match (re_all, text, 0, NULL))
{
g_free (text);
return NO;
}
for (i = 0, handled = NO; !handled && i < n_elms; ++i)
handled = [elms[i] newline:indenter text:text
cursor:where start:&start end:&end];
g_free (text);
return handled;
}
@end
MooIndenterRegex *
_moo_indenter_regex_ref (MooIndenterRegex *regex)
{
g_return_val_if_fail (regex != nil, NULL);
return [regex retain];
}
void
_moo_indenter_regex_unref (MooIndenterRegex *regex)
{
g_return_if_fail (regex != nil);
[regex release];
}
MooIndenterRegex *
_moo_indenter_get_regex (const char *id_)
{
g_return_val_if_fail (id_ != NULL, nil);
[MooIndenterRegex loadSettings];
return g_hash_table_lookup (regex_hash, id_);
}
gboolean
_moo_indenter_regex_newline (MooIndenterRegex *regex,
MooIndenter *indenter,
GtkTextIter *where)
{
g_return_val_if_fail (regex != NULL, FALSE);
return [regex newline:indenter where:where];
}
@implementation MooIndenterShift
- init: (const char*)pattern
{
GError *error = NULL;
[super init];
re = g_regex_new (pattern, G_REGEX_DUPNAMES | G_REGEX_OPTIMIZE, 0, &error);
if (!re)
{
g_warning ("%s: %s", G_STRFUNC, error->message);
g_error_free (error);
[self release];
return nil;
}
return self;
}
- (void) dealloc
{
if (re)
g_regex_unref (re);
[super dealloc];
}
- (BOOL) newline: (MooIndenter*)indenter
text: (const char*)text
cursor: (GtkTextIter*)cursor
start: (GtkTextIter*)start
end: (GtkTextIter*)end
{
GtkTextIter iter;
guint offset;
char *insert;
MOO_UNUSED_VAR (end);
if (!g_regex_match (re, text, 0, NULL))
return NO;
iter = *start;
if (!_moo_indenter_compute_line_offset (indenter, &iter, &offset))
{
g_critical ("%s: oops", G_STRFUNC);
return NO;
}
offset = _moo_indenter_compute_next_offset (indenter, offset);
insert = moo_indenter_make_space (indenter, offset, 0);
gtk_text_buffer_insert (gtk_text_iter_get_buffer (start), cursor, insert, -1);
g_free (insert);
return YES;
}
@end;

View File

@ -11,12 +11,26 @@
* See COPYING file that comes with this distribution. * See COPYING file that comes with this distribution.
*/ */
#define MOOEDIT_COMPILATION
#include <config.h>
#include "mooedit/mooindenter.h" #include "mooedit/mooindenter.h"
#include "mooedit/mooindenter-regex.h"
#include "mooedit/mooedit.h" #include "mooedit/mooedit.h"
#include "mooutils/moomarshals.h" #include "mooutils/moomarshals.h"
#include <string.h> #include <string.h>
struct _MooIndenterPrivate {
char *id;
MooIndenterRegex *re;
gpointer doc; /* MooEdit* */
gboolean use_tabs;
gboolean strip;
guint tab_width;
guint indent;
};
/* XXX this doesn't take unicode control chars into account */ /* XXX this doesn't take unicode control chars into account */
static GObject *moo_indenter_constructor (GType type, static GObject *moo_indenter_constructor (GType type,
@ -32,6 +46,9 @@ static void moo_indenter_get_property (GObject *object,
GValue *value, GValue *value,
GParamSpec *pspec); GParamSpec *pspec);
static void moo_indenter_set_id (MooIndenter *indenter,
const char *id);
static void character_default (MooIndenter *indenter, static void character_default (MooIndenter *indenter,
gunichar inserted_char, gunichar inserted_char,
GtkTextIter *where); GtkTextIter *where);
@ -58,6 +75,7 @@ enum {
PROP_USE_TABS, PROP_USE_TABS,
PROP_STRIP, PROP_STRIP,
PROP_INDENT, PROP_INDENT,
PROP_ID,
PROP_DOC PROP_DOC
}; };
@ -126,6 +144,11 @@ moo_indenter_class_init (MooIndenterClass *klass)
1, G_MAXUINT, 8, 1, G_MAXUINT, 8,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class, PROP_ID,
g_param_spec_string ("id", "id", "id",
NULL,
G_PARAM_READWRITE));
signals[CONFIG_CHANGED] = signals[CONFIG_CHANGED] =
g_signal_new ("config-changed", g_signal_new ("config-changed",
G_OBJECT_CLASS_TYPE (klass), G_OBJECT_CLASS_TYPE (klass),
@ -146,12 +169,17 @@ moo_indenter_class_init (MooIndenterClass *klass)
G_TYPE_NONE, 1, G_TYPE_NONE, 1,
G_TYPE_UINT, G_TYPE_UINT,
GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE); GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE);
g_type_class_add_private (gobject_class, sizeof (MooIndenterPrivate));
} }
static void static void
moo_indenter_init (G_GNUC_UNUSED MooIndenter *indent) moo_indenter_init (MooIndenter *indent)
{ {
indent->priv = G_TYPE_INSTANCE_GET_PRIVATE (indent,
MOO_TYPE_INDENTER,
MooIndenterPrivate);
} }
@ -166,7 +194,7 @@ moo_indenter_constructor (GType type,
object = G_OBJECT_CLASS(moo_indenter_parent_class)->constructor (type, n_props, props); object = G_OBJECT_CLASS(moo_indenter_parent_class)->constructor (type, n_props, props);
indent = MOO_INDENTER (object); indent = MOO_INDENTER (object);
if (indent->doc) if (indent->priv->doc)
{ {
guint i; guint i;
GParamSpec *pspec; GParamSpec *pspec;
@ -179,7 +207,7 @@ moo_indenter_constructor (GType type,
g_return_val_if_fail (pspec != NULL, object); g_return_val_if_fail (pspec != NULL, object);
config_notify (indent, id, pspec); config_notify (indent, id, pspec);
g_signal_connect_swapped (indent->doc, "config-notify", g_signal_connect_swapped (indent->priv->doc, "config-notify",
G_CALLBACK (config_notify), G_CALLBACK (config_notify),
indent); indent);
} }
@ -193,11 +221,14 @@ moo_indenter_finalize (GObject *object)
{ {
MooIndenter *indent = MOO_INDENTER (object); MooIndenter *indent = MOO_INDENTER (object);
if (indent->doc) if (indent->priv->doc)
g_signal_handlers_disconnect_by_func (indent->doc, g_signal_handlers_disconnect_by_func (indent->priv->doc,
(gpointer) config_notify, (gpointer) config_notify,
indent); indent);
if (indent->priv->re)
_moo_indenter_regex_unref (indent->priv->re);
G_OBJECT_CLASS(moo_indenter_parent_class)->finalize (object); G_OBJECT_CLASS(moo_indenter_parent_class)->finalize (object);
} }
@ -212,30 +243,34 @@ static void moo_indenter_set_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_DOC: case PROP_DOC:
indenter->doc = g_value_get_object (value); indenter->priv->doc = g_value_get_object (value);
g_object_notify (object, "doc"); g_object_notify (object, "doc");
break; break;
case PROP_TAB_WIDTH: case PROP_TAB_WIDTH:
indenter->tab_width = g_value_get_uint (value); indenter->priv->tab_width = g_value_get_uint (value);
g_object_notify (object, "tab-width"); g_object_notify (object, "tab-width");
break; break;
case PROP_USE_TABS: case PROP_USE_TABS:
indenter->use_tabs = g_value_get_boolean (value); indenter->priv->use_tabs = g_value_get_boolean (value);
g_object_notify (object, "use-tabs"); g_object_notify (object, "use-tabs");
break; break;
case PROP_STRIP: case PROP_STRIP:
indenter->strip = g_value_get_boolean (value); indenter->priv->strip = g_value_get_boolean (value);
g_object_notify (object, "strip"); g_object_notify (object, "strip");
break; break;
case PROP_INDENT: case PROP_INDENT:
indenter->indent = g_value_get_uint (value); indenter->priv->indent = g_value_get_uint (value);
g_object_notify (object, "indent"); g_object_notify (object, "indent");
break; break;
case PROP_ID:
moo_indenter_set_id (indenter, g_value_get_string (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -253,23 +288,27 @@ static void moo_indenter_get_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_DOC: case PROP_DOC:
g_value_set_object (value, indenter->doc); g_value_set_object (value, indenter->priv->doc);
break; break;
case PROP_TAB_WIDTH: case PROP_TAB_WIDTH:
g_value_set_uint (value, indenter->tab_width); g_value_set_uint (value, indenter->priv->tab_width);
break; break;
case PROP_USE_TABS: case PROP_USE_TABS:
g_value_set_boolean (value, indenter->use_tabs); g_value_set_boolean (value, indenter->priv->use_tabs);
break; break;
case PROP_STRIP: case PROP_STRIP:
g_value_set_boolean (value, indenter->strip); g_value_set_boolean (value, indenter->priv->strip);
break; break;
case PROP_INDENT: case PROP_INDENT:
g_value_set_uint (value, indenter->indent); g_value_set_uint (value, indenter->priv->indent);
break;
case PROP_ID:
g_value_set_string (value, indenter->priv->id);
break; break;
default: default:
@ -302,14 +341,68 @@ moo_indenter_character (MooIndenter *indenter,
MooIndenter* MooIndenter*
moo_indenter_new (gpointer doc, moo_indenter_new (gpointer doc)
G_GNUC_UNUSED const char *name)
{ {
g_return_val_if_fail (!doc || MOO_IS_EDIT (doc), NULL); g_return_val_if_fail (!doc || MOO_IS_EDIT (doc), NULL);
return g_object_new (MOO_TYPE_INDENTER, "doc", doc, NULL); return g_object_new (MOO_TYPE_INDENTER, "doc", doc, NULL);
} }
guint
moo_indenter_get_tab_width (MooIndenter *indenter)
{
g_return_val_if_fail (MOO_IS_INDENTER (indenter), 8);
return indenter->priv->tab_width;
}
#ifndef MOO_USE_OBJC
MooIndenterRegex *
_moo_indenter_get_regex (G_GNUC_UNUSED const char *id)
{
return NULL;
}
MooIndenterRegex *
_moo_indenter_regex_ref (G_GNUC_UNUSED MooIndenterRegex *regex)
{
g_return_val_if_reached (NULL);
}
void
_moo_indenter_regex_unref (G_GNUC_UNUSED MooIndenterRegex *regex)
{
g_return_if_reached ();
}
gboolean
_moo_indenter_regex_newline (G_GNUC_UNUSED MooIndenterRegex *regex,
G_GNUC_UNUSED GtkTextBuffer *buffer,
G_GNUC_UNUSED GtkTextIter *where)
{
g_return_val_if_reached (FALSE);
}
#endif
static void
moo_indenter_set_id (MooIndenter *indenter,
const char *id)
{
if (!strcmp (indenter->priv->id ? indenter->priv->id : "", id ? id : ""))
return;
g_free (indenter->priv->id);
indenter->priv->id = g_strdup (id);
if (indenter->priv->re)
_moo_indenter_regex_unref (indenter->priv->re);
indenter->priv->re = _moo_indenter_get_regex (id);
if (indenter->priv->re)
_moo_indenter_regex_ref (indenter->priv->re);
}
/*****************************************************************************/ /*****************************************************************************/
/* Default implementation /* Default implementation
*/ */
@ -320,7 +413,7 @@ moo_indenter_make_space (MooIndenter *indenter,
guint start) guint start)
{ {
guint tabs, spaces, delta; guint tabs, spaces, delta;
guint tab_width = indenter->tab_width; guint tab_width = indenter->priv->tab_width;
char *string; char *string;
g_return_val_if_fail (MOO_IS_INDENTER (indenter), NULL); g_return_val_if_fail (MOO_IS_INDENTER (indenter), NULL);
@ -328,7 +421,7 @@ moo_indenter_make_space (MooIndenter *indenter,
if (!len) if (!len)
return NULL; return NULL;
if (!indenter->use_tabs) if (!indenter->priv->use_tabs)
return g_strnfill (len, ' '); return g_strnfill (len, ' ');
delta = start % tab_width; delta = start % tab_width;
@ -407,6 +500,17 @@ compute_line_offset (GtkTextIter *dest,
return retval; return retval;
} }
gboolean
_moo_indenter_compute_line_offset (MooIndenter *indenter,
GtkTextIter *dest,
guint *offsetp)
{
g_return_val_if_fail (MOO_IS_INDENTER (indenter), FALSE);
g_return_val_if_fail (dest != NULL, FALSE);
g_return_val_if_fail (offsetp != NULL, FALSE);
return compute_line_offset (dest, indenter->priv->tab_width, offsetp);
}
static void static void
character_default (MooIndenter *indenter, character_default (MooIndenter *indenter,
@ -422,9 +526,14 @@ character_default (MooIndenter *indenter,
if (inserted_char != '\n') if (inserted_char != '\n')
return; return;
if (indenter->priv->re &&
_moo_indenter_regex_newline (indenter->priv->re,
indenter, where))
return;
iter = *where; iter = *where;
gtk_text_iter_backward_line (&iter); gtk_text_iter_backward_line (&iter);
ws_line = !compute_line_offset (&iter, indenter->tab_width, &offset); ws_line = !compute_line_offset (&iter, indenter->priv->tab_width, &offset);
if (!offset) if (!offset)
return; return;
@ -436,22 +545,22 @@ character_default (MooIndenter *indenter,
g_free (indent_string); g_free (indent_string);
} }
if (ws_line && indenter->strip) // if (ws_line && indenter->priv->strip)
{ // {
GtkTextMark *saved_location; // GtkTextMark *saved_location;
GtkTextIter iter2; // GtkTextIter iter2;
//
saved_location = gtk_text_buffer_create_mark (buffer, NULL, where, FALSE); // saved_location = gtk_text_buffer_create_mark (buffer, NULL, where, FALSE);
//
iter = *where; // iter = *where;
gtk_text_iter_backward_line (&iter); // gtk_text_iter_backward_line (&iter);
iter2 = iter; // iter2 = iter;
gtk_text_iter_forward_to_line_end (&iter2); // gtk_text_iter_forward_to_line_end (&iter2);
gtk_text_buffer_delete (buffer, &iter, &iter2); // gtk_text_buffer_delete (buffer, &iter, &iter2);
//
gtk_text_buffer_get_iter_at_mark (buffer, where, saved_location); // gtk_text_buffer_get_iter_at_mark (buffer, where, saved_location);
gtk_text_buffer_delete_mark (buffer, saved_location); // gtk_text_buffer_delete_mark (buffer, saved_location);
} // }
} }
@ -592,14 +701,21 @@ iter_get_visual_offset (GtkTextIter *iter,
} }
static guint
get_next_offset (guint offset,
guint indent)
{
return offset + (indent - offset % indent);
}
void void
moo_indenter_tab (MooIndenter *indenter, moo_indenter_tab (MooIndenter *indenter,
GtkTextBuffer *buffer) GtkTextBuffer *buffer)
{ {
GtkTextIter insert, start; GtkTextIter insert, start;
int offset, new_offset, white_space; int offset, new_offset, white_space;
guint tab_width = indenter->tab_width; guint tab_width = indenter->priv->tab_width;
guint indent = indenter->indent; guint indent = indenter->priv->indent;
char *text = NULL; char *text = NULL;
gtk_text_buffer_get_iter_at_mark (buffer, &insert, gtk_text_buffer_get_insert (buffer)); gtk_text_buffer_get_iter_at_mark (buffer, &insert, gtk_text_buffer_get_insert (buffer));
@ -607,7 +723,7 @@ moo_indenter_tab (MooIndenter *indenter,
start = insert; start = insert;
iter_get_visual_offset (&start, tab_width, &offset, &white_space); iter_get_visual_offset (&start, tab_width, &offset, &white_space);
new_offset = offset + (indent - offset % indent); new_offset = get_next_offset (offset, indent);
text = moo_indenter_make_space (indenter, text = moo_indenter_make_space (indenter,
new_offset - offset + white_space, new_offset - offset + white_space,
offset - white_space); offset - white_space);
@ -618,6 +734,14 @@ moo_indenter_tab (MooIndenter *indenter,
g_free (text); g_free (text);
} }
guint
_moo_indenter_compute_next_offset (MooIndenter *indenter,
guint offset)
{
g_return_val_if_fail (MOO_IS_INDENTER (indenter), offset);
return get_next_offset (offset, indenter->priv->indent);
}
static void static void
shift_line_forward (MooIndenter *indenter, shift_line_forward (MooIndenter *indenter,
@ -628,7 +752,7 @@ shift_line_forward (MooIndenter *indenter,
guint offset; guint offset;
GtkTextIter start; GtkTextIter start;
if (!compute_line_offset (iter, indenter->tab_width, &offset)) if (!compute_line_offset (iter, indenter->priv->tab_width, &offset))
return; return;
if (offset) if (offset)
@ -638,7 +762,7 @@ shift_line_forward (MooIndenter *indenter,
gtk_text_buffer_delete (buffer, &start, iter); gtk_text_buffer_delete (buffer, &start, iter);
} }
text = moo_indenter_make_space (indenter, offset + indenter->indent, 0); text = moo_indenter_make_space (indenter, offset + indenter->priv->indent, 0);
if (text) if (text)
gtk_text_buffer_insert (buffer, iter, text, -1); gtk_text_buffer_insert (buffer, iter, text, -1);
@ -675,20 +799,20 @@ shift_line_backward (MooIndenter *indenter,
else if (c == '\t') else if (c == '\t')
{ {
gtk_text_iter_forward_char (&end); gtk_text_iter_forward_char (&end);
deleted += indenter->tab_width; deleted += indenter->priv->tab_width;
} }
else else
{ {
break; break;
} }
if (deleted >= (int) indenter->indent) if (deleted >= (int) indenter->priv->indent)
break; break;
} }
gtk_text_buffer_delete (buffer, iter, &end); gtk_text_buffer_delete (buffer, iter, &end);
deleted -= indenter->indent; deleted -= indenter->priv->indent;
if (deleted > 0) if (deleted > 0)
{ {
@ -725,7 +849,7 @@ config_changed_default (MooIndenter *indenter,
guint var_id, guint var_id,
GParamSpec *pspec) GParamSpec *pspec)
{ {
MooEdit *doc = indenter->doc; MooEdit *doc = indenter->priv->doc;
g_return_if_fail (MOO_IS_EDIT (doc)); g_return_if_fail (MOO_IS_EDIT (doc));

View File

@ -28,17 +28,13 @@ G_BEGIN_DECLS
typedef struct _MooIndenter MooIndenter; typedef struct _MooIndenter MooIndenter;
typedef struct _MooIndenterPrivate MooIndenterPrivate;
typedef struct _MooIndenterClass MooIndenterClass; typedef struct _MooIndenterClass MooIndenterClass;
struct _MooIndenter struct _MooIndenter
{ {
GObject parent; GObject parent;
MooIndenterPrivate *priv;
gpointer doc; /* MooEdit* */
gboolean use_tabs;
gboolean strip;
guint tab_width;
guint indent;
}; };
struct _MooIndenterClass struct _MooIndenterClass
@ -56,8 +52,9 @@ struct _MooIndenterClass
GType moo_indenter_get_type (void) G_GNUC_CONST; GType moo_indenter_get_type (void) G_GNUC_CONST;
MooIndenter *moo_indenter_new (gpointer doc, MooIndenter *moo_indenter_new (gpointer doc);
const char *name);
guint moo_indenter_get_tab_width (MooIndenter *indenter);
char *moo_indenter_make_space (MooIndenter *indenter, char *moo_indenter_make_space (MooIndenter *indenter,
guint len, guint len,
@ -91,6 +88,12 @@ guint moo_text_iter_get_prev_stop (const GtkTextIter *start,
guint offset, guint offset,
gboolean same_line); gboolean same_line);
gboolean _moo_indenter_compute_line_offset (MooIndenter *indenter,
GtkTextIter *dest,
guint *offsetp);
guint _moo_indenter_compute_next_offset (MooIndenter *indenter,
guint offset);
G_END_DECLS G_END_DECLS

View File

@ -574,7 +574,6 @@
(return-type "MooIndenter*") (return-type "MooIndenter*")
(parameters (parameters
'("MooEdit*" "doc") '("MooEdit*" "doc")
'("const-char*" "name")
) )
) )

View File

@ -1405,6 +1405,25 @@ moo_get_data_subdirs (const char *subdir,
return dirs; return dirs;
} }
char *
moo_get_data_file (const char *name)
{
guint n_files, i;
char **files;
char *filename = NULL;
g_return_val_if_fail (name != NULL, NULL);
files = moo_get_data_files (name, MOO_DATA_SHARE, &n_files);
for (i = 0; !filename && i < n_files; ++i)
if (g_file_test (files[i], G_FILE_TEST_EXISTS))
filename = g_strdup (files[i]);
g_strfreev (files);
return filename;
}
static char * static char *
get_user_data_file (const char *basename, get_user_data_file (const char *basename,

View File

@ -82,6 +82,8 @@ char **moo_get_data_subdirs (const char *subdir,
guint *n_dirs); guint *n_dirs);
#define moo_get_data_files moo_get_data_subdirs #define moo_get_data_files moo_get_data_subdirs
char *moo_get_data_file (const char *name);
const char *moo_get_locale_dir (void); const char *moo_get_locale_dir (void);
const char *const *_moo_get_shared_data_dirs (void); const char *const *_moo_get_shared_data_dirs (void);