2005-09-06 09:21:05 -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-11-30 07:02:07 -08:00
|
|
|
* mooindenter.c
|
2005-09-06 09:21:05 -07:00
|
|
|
*
|
|
|
|
* 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/mooindenter.h"
|
2005-11-03 17:35:22 -08:00
|
|
|
#include "mooedit/mooedit.h"
|
2005-11-24 06:14:48 -08:00
|
|
|
#include "mooutils/moomarshals.h"
|
2005-09-06 09:21:05 -07:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
|
/* XXX this doesn't take unicode control chars into account */
|
|
|
|
|
2005-11-03 17:35:22 -08:00
|
|
|
static GObject *moo_indenter_constructor (GType type,
|
|
|
|
guint n_construct_properties,
|
|
|
|
GObjectConstructParam *construct_param);
|
|
|
|
static void moo_indenter_finalize (GObject *object);
|
2005-09-06 09:21:05 -07:00
|
|
|
static void moo_indenter_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void moo_indenter_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
|
|
|
static void character_default (MooIndenter *indenter,
|
|
|
|
gunichar inserted_char,
|
|
|
|
GtkTextIter *where);
|
2005-11-24 06:14:48 -08:00
|
|
|
static void update_variable_default (MooIndenter *indenter,
|
|
|
|
const char *var);
|
|
|
|
|
2005-11-03 17:35:22 -08:00
|
|
|
static void variable_changed (MooIndenter *indenter,
|
2005-11-24 06:14:48 -08:00
|
|
|
const char *var);
|
2005-09-06 09:21:05 -07:00
|
|
|
|
|
|
|
|
|
|
|
enum {
|
2005-11-24 06:14:48 -08:00
|
|
|
UPDATE_VARIABLE,
|
|
|
|
CHARACTER,
|
2005-09-06 09:21:05 -07:00
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
2005-11-24 06:14:48 -08:00
|
|
|
static guint signals[LAST_SIGNAL];
|
2005-09-06 09:21:05 -07:00
|
|
|
|
|
|
|
enum {
|
|
|
|
PROP_0,
|
|
|
|
PROP_TAB_WIDTH,
|
|
|
|
PROP_USE_TABS,
|
2005-11-03 17:35:22 -08:00
|
|
|
PROP_INDENT,
|
|
|
|
PROP_DOC
|
2005-09-06 09:21:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* MOO_TYPE_INDENTER */
|
|
|
|
G_DEFINE_TYPE (MooIndenter, moo_indenter, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
moo_indenter_class_init (MooIndenterClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
2005-11-03 17:35:22 -08:00
|
|
|
gobject_class->constructor = moo_indenter_constructor;
|
|
|
|
gobject_class->finalize = moo_indenter_finalize;
|
2005-09-06 09:21:05 -07:00
|
|
|
gobject_class->set_property = moo_indenter_set_property;
|
|
|
|
gobject_class->get_property = moo_indenter_get_property;
|
|
|
|
|
|
|
|
klass->character = character_default;
|
2005-11-24 06:14:48 -08:00
|
|
|
klass->update_variable = update_variable_default;
|
|
|
|
|
|
|
|
moo_edit_register_var (g_param_spec_uint ("indent-tab-width", "indent-tab-width",
|
|
|
|
"indent-tab-width", 1, G_MAXUINT, 8, 0));
|
|
|
|
moo_edit_register_var (g_param_spec_boolean ("indent-use-tabs",
|
|
|
|
"indent-use-tabs", "indent-use-tabs", TRUE, 0));
|
|
|
|
moo_edit_register_var_alias ("indent-use-tabs", "use-tabs");
|
|
|
|
moo_edit_register_var (g_param_spec_uint ("indent-width", "indent-width",
|
|
|
|
"indent-width", 1, G_MAXUINT, 8, 0));
|
2005-09-06 09:21:05 -07:00
|
|
|
|
2005-11-03 17:35:22 -08:00
|
|
|
g_object_class_install_property (gobject_class,
|
|
|
|
PROP_DOC,
|
|
|
|
g_param_spec_object ("doc",
|
|
|
|
"doc",
|
|
|
|
"doc",
|
|
|
|
MOO_TYPE_EDIT,
|
|
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
g_object_class_install_property (gobject_class,
|
|
|
|
PROP_TAB_WIDTH,
|
|
|
|
g_param_spec_uint ("tab-width",
|
|
|
|
"tab-width",
|
|
|
|
"tab-width",
|
|
|
|
1,
|
|
|
|
G_MAXUINT,
|
|
|
|
8,
|
|
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
|
|
|
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
|
|
PROP_USE_TABS,
|
|
|
|
g_param_spec_boolean ("use-tabs",
|
|
|
|
"use-tabs",
|
|
|
|
"use-tabs",
|
|
|
|
TRUE,
|
|
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
|
|
|
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
|
|
PROP_INDENT,
|
|
|
|
g_param_spec_uint ("indent",
|
|
|
|
"indent",
|
|
|
|
"indent",
|
|
|
|
1,
|
|
|
|
G_MAXUINT,
|
|
|
|
8,
|
|
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
2005-11-24 06:14:48 -08:00
|
|
|
|
|
|
|
signals[UPDATE_VARIABLE] =
|
|
|
|
g_signal_new ("update-variable",
|
|
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
|
|
|
G_STRUCT_OFFSET (MooIndenterClass, update_variable),
|
|
|
|
NULL, NULL,
|
|
|
|
_moo_marshal_VOID__STRING,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
|
|
|
|
|
|
signals[CHARACTER] =
|
|
|
|
g_signal_new ("character",
|
|
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
|
|
|
|
G_STRUCT_OFFSET (MooIndenterClass, character),
|
|
|
|
NULL, NULL,
|
|
|
|
_moo_marshal_VOID__UINT_BOXED,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
G_TYPE_UINT,
|
|
|
|
GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE);
|
2005-09-06 09:21:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
moo_indenter_init (G_GNUC_UNUSED MooIndenter *indent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-03 17:35:22 -08:00
|
|
|
static GObject*
|
|
|
|
moo_indenter_constructor (GType type,
|
|
|
|
guint n_props,
|
|
|
|
GObjectConstructParam *props)
|
|
|
|
{
|
|
|
|
GObject *object;
|
|
|
|
MooIndenter *indent;
|
|
|
|
|
|
|
|
object = G_OBJECT_CLASS(moo_indenter_parent_class)->constructor (type, n_props, props);
|
|
|
|
indent = MOO_INDENTER (object);
|
|
|
|
|
|
|
|
if (indent->doc)
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
|
2005-11-24 06:14:48 -08:00
|
|
|
static const char *vars[] = {
|
|
|
|
"indent-tab-width",
|
|
|
|
"indent-width",
|
|
|
|
"indent-use-tabs"
|
|
|
|
};
|
2005-11-08 10:59:52 -08:00
|
|
|
|
2005-11-24 06:14:48 -08:00
|
|
|
for (i = 0; i < G_N_ELEMENTS (vars); ++i)
|
2005-11-08 10:59:52 -08:00
|
|
|
{
|
2005-11-24 06:14:48 -08:00
|
|
|
if (moo_edit_get_var (indent->doc, vars[i], NULL))
|
|
|
|
variable_changed (indent, vars[i]);
|
2005-11-08 10:59:52 -08:00
|
|
|
}
|
2005-11-03 17:35:22 -08:00
|
|
|
|
|
|
|
g_signal_connect_swapped (indent->doc, "variable-changed",
|
2005-11-24 06:14:48 -08:00
|
|
|
G_CALLBACK (variable_changed),
|
|
|
|
indent);
|
2005-11-03 17:35:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
moo_indenter_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MooIndenter *indent = MOO_INDENTER (object);
|
|
|
|
|
|
|
|
if (indent->doc)
|
|
|
|
g_signal_handlers_disconnect_by_func (indent->doc,
|
|
|
|
(gpointer) variable_changed,
|
|
|
|
indent);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS(moo_indenter_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
static void moo_indenter_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MooIndenter *indenter = MOO_INDENTER (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2005-11-03 17:35:22 -08:00
|
|
|
case PROP_DOC:
|
|
|
|
indenter->doc = g_value_get_object (value);
|
|
|
|
g_object_notify (object, "doc");
|
|
|
|
break;
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
case PROP_TAB_WIDTH:
|
|
|
|
indenter->tab_width = g_value_get_uint (value);
|
|
|
|
g_object_notify (object, "tab-width");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_USE_TABS:
|
|
|
|
indenter->use_tabs = g_value_get_boolean (value);
|
|
|
|
g_object_notify (object, "use-tabs");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_INDENT:
|
|
|
|
indenter->indent = g_value_get_uint (value);
|
|
|
|
g_object_notify (object, "indent");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void moo_indenter_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MooIndenter *indenter = MOO_INDENTER (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2005-11-03 17:35:22 -08:00
|
|
|
case PROP_DOC:
|
|
|
|
g_value_set_object (value, indenter->doc);
|
|
|
|
break;
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
case PROP_TAB_WIDTH:
|
|
|
|
g_value_set_uint (value, indenter->tab_width);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_USE_TABS:
|
|
|
|
g_value_set_boolean (value, indenter->use_tabs);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_INDENT:
|
|
|
|
g_value_set_uint (value, indenter->indent);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-03 17:35:22 -08:00
|
|
|
static void
|
|
|
|
variable_changed (MooIndenter *indenter,
|
2005-11-24 06:14:48 -08:00
|
|
|
const char *var)
|
2005-11-03 17:35:22 -08:00
|
|
|
{
|
2005-11-24 06:14:48 -08:00
|
|
|
g_signal_emit (indenter, signals[UPDATE_VARIABLE], 0, var);
|
2005-11-03 17:35:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
void
|
|
|
|
moo_indenter_character (MooIndenter *indenter,
|
|
|
|
gunichar inserted_char,
|
|
|
|
GtkTextIter *where)
|
|
|
|
{
|
|
|
|
g_return_if_fail (MOO_IS_INDENTER (indenter));
|
2005-11-24 06:14:48 -08:00
|
|
|
MOO_INDENTER_GET_CLASS(indenter)->character (indenter, inserted_char, where);
|
2005-09-06 09:21:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MooIndenter*
|
2005-11-03 17:35:22 -08:00
|
|
|
moo_indenter_new (gpointer doc,
|
|
|
|
G_GNUC_UNUSED const char *name)
|
2005-09-06 09:21:05 -07:00
|
|
|
{
|
2005-11-03 17:35:22 -08:00
|
|
|
g_return_val_if_fail (MOO_IS_EDIT (doc), NULL);
|
|
|
|
return g_object_new (MOO_TYPE_INDENTER, "doc", doc, NULL);
|
2005-09-06 09:21:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* Default implementation
|
|
|
|
*/
|
|
|
|
|
|
|
|
char*
|
|
|
|
moo_indenter_make_space (MooIndenter *indenter,
|
|
|
|
guint len,
|
|
|
|
guint start)
|
|
|
|
{
|
|
|
|
guint tabs, spaces, delta;
|
|
|
|
guint tab_width = indenter->tab_width;
|
|
|
|
char *string;
|
|
|
|
|
|
|
|
g_return_val_if_fail (MOO_IS_INDENTER (indenter), NULL);
|
|
|
|
|
|
|
|
if (!len)
|
|
|
|
return NULL;
|
|
|
|
|
2005-09-17 05:58:42 -07:00
|
|
|
if (!indenter->use_tabs)
|
2005-09-06 09:21:05 -07:00
|
|
|
return g_strnfill (len, ' ');
|
|
|
|
|
|
|
|
delta = start % tab_width;
|
2005-09-17 05:58:42 -07:00
|
|
|
|
|
|
|
if (!delta)
|
|
|
|
{
|
|
|
|
tabs = len / tab_width;
|
|
|
|
spaces = len % tab_width;
|
|
|
|
}
|
|
|
|
else if (len < tab_width - delta)
|
|
|
|
{
|
|
|
|
tabs = 0;
|
|
|
|
spaces = len;
|
|
|
|
}
|
|
|
|
else if (len == tab_width - delta)
|
|
|
|
{
|
|
|
|
tabs = 1;
|
|
|
|
spaces = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
len -= tab_width - delta;
|
|
|
|
tabs = len / tab_width + 1;
|
|
|
|
spaces = len % tab_width;
|
|
|
|
}
|
2005-09-06 09:21:05 -07:00
|
|
|
|
|
|
|
string = g_new (char, tabs + spaces + 1);
|
|
|
|
string[tabs + spaces] = 0;
|
|
|
|
|
|
|
|
if (tabs)
|
|
|
|
memset (string, '\t', tabs);
|
|
|
|
if (spaces)
|
|
|
|
memset (string + tabs, ' ', spaces);
|
|
|
|
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* computes amount of leading white space on the given line;
|
|
|
|
returns TRUE if line contains some non-whitespace chars;
|
|
|
|
if returns TRUE, then iter points to the first non-white-space char */
|
|
|
|
static gboolean
|
|
|
|
compute_line_offset (GtkTextIter *iter,
|
|
|
|
guint tab_width,
|
|
|
|
guint *offsetp)
|
|
|
|
{
|
|
|
|
guint offset = 0;
|
|
|
|
|
|
|
|
while (!gtk_text_iter_ends_line (iter))
|
|
|
|
{
|
|
|
|
gunichar c = gtk_text_iter_get_char (iter);
|
|
|
|
|
|
|
|
if (c == ' ')
|
|
|
|
{
|
|
|
|
offset += 1;
|
|
|
|
}
|
|
|
|
else if (c == '\t')
|
|
|
|
{
|
|
|
|
guint add = tab_width - offset % tab_width;
|
|
|
|
offset += add;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*offsetp = offset;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_text_iter_forward_char (iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
character_default (MooIndenter *indenter,
|
|
|
|
gunichar inserted_char,
|
|
|
|
GtkTextIter *where)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *indent_string = NULL;
|
2005-11-24 06:14:48 -08:00
|
|
|
GtkTextBuffer *buffer = gtk_text_iter_get_buffer (where);
|
2005-09-06 09:21:05 -07:00
|
|
|
|
|
|
|
if (inserted_char != '\n')
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = gtk_text_iter_get_line (where) - 1; i >= 0; --i)
|
|
|
|
{
|
|
|
|
guint offset;
|
|
|
|
GtkTextIter iter;
|
|
|
|
|
|
|
|
gtk_text_buffer_get_iter_at_line (buffer, &iter, i);
|
|
|
|
|
|
|
|
if (compute_line_offset (&iter, indenter->tab_width, &offset))
|
|
|
|
{
|
|
|
|
indent_string = moo_indenter_make_space (indenter, offset, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (indent_string)
|
|
|
|
{
|
|
|
|
gtk_text_buffer_insert (buffer, where, indent_string, -1);
|
|
|
|
g_free (indent_string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* computes offset of start and returns offset or -1 if there are
|
|
|
|
non-whitespace characters before start */
|
2005-09-17 05:58:42 -07:00
|
|
|
int
|
|
|
|
moo_iter_get_blank_offset (const GtkTextIter *start,
|
|
|
|
guint tab_width)
|
2005-09-06 09:21:05 -07:00
|
|
|
{
|
|
|
|
GtkTextIter iter;
|
|
|
|
guint offset;
|
|
|
|
|
|
|
|
if (gtk_text_iter_starts_line (start))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
iter = *start;
|
|
|
|
gtk_text_iter_set_line_offset (&iter, 0);
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
while (gtk_text_iter_compare (&iter, start))
|
|
|
|
{
|
|
|
|
gunichar c = gtk_text_iter_get_char (&iter);
|
|
|
|
|
|
|
|
if (c == ' ')
|
|
|
|
{
|
|
|
|
offset += 1;
|
|
|
|
}
|
|
|
|
else if (c == '\t')
|
|
|
|
{
|
|
|
|
guint add = tab_width - offset % tab_width;
|
|
|
|
offset += add;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_text_iter_forward_char (&iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* computes where cursor should jump when backspace is pressed
|
|
|
|
|
|
|
|
<-- result -->
|
|
|
|
blah blah blah
|
|
|
|
blah
|
|
|
|
| offset
|
|
|
|
*/
|
2005-09-17 05:58:42 -07:00
|
|
|
guint
|
|
|
|
moo_text_iter_get_prev_stop (const GtkTextIter *start,
|
|
|
|
guint tab_width,
|
|
|
|
guint offset,
|
|
|
|
gboolean same_line)
|
2005-09-06 09:21:05 -07:00
|
|
|
{
|
|
|
|
GtkTextIter iter;
|
|
|
|
guint indent;
|
|
|
|
|
|
|
|
iter = *start;
|
|
|
|
|
|
|
|
gtk_text_iter_set_line_offset (&iter, 0);
|
|
|
|
if (!same_line)
|
|
|
|
{
|
|
|
|
if (gtk_text_iter_is_start (&iter))
|
|
|
|
return 0;
|
|
|
|
gtk_text_iter_backward_line (&iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
if (compute_line_offset (&iter, tab_width, &indent) &&
|
|
|
|
indent && indent <= offset)
|
|
|
|
return indent;
|
|
|
|
if (!gtk_text_iter_backward_line (&iter))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* computes visual offset at iter, amount of white space before the iter,
|
|
|
|
and makes iter to point to the beginning of the white space, e.g. for
|
|
|
|
blah wefwefw
|
|
|
|
|
|
|
|
|
it would set offset == 7, white_space == 3, and set iter to the first
|
|
|
|
space after 'blah'
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
iter_get_visual_offset (GtkTextIter *iter,
|
|
|
|
guint tab_width,
|
|
|
|
int *offsetp,
|
|
|
|
int *white_spacep)
|
|
|
|
{
|
|
|
|
GtkTextIter start, white_space_start;
|
|
|
|
guint offset, white_space;
|
|
|
|
|
|
|
|
start = *iter;
|
|
|
|
gtk_text_iter_set_line_offset (&start, 0);
|
|
|
|
offset = 0;
|
|
|
|
white_space = 0;
|
|
|
|
|
|
|
|
while (gtk_text_iter_compare (&start, iter))
|
|
|
|
{
|
|
|
|
gunichar c = gtk_text_iter_get_char (&start);
|
|
|
|
|
|
|
|
if (c == ' ' || c == '\t')
|
|
|
|
{
|
|
|
|
if (!white_space)
|
|
|
|
white_space_start = start;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
white_space = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '\t')
|
|
|
|
{
|
|
|
|
guint add = tab_width - offset % tab_width;
|
|
|
|
offset += add;
|
|
|
|
white_space += add;
|
|
|
|
}
|
|
|
|
else if (c == ' ')
|
|
|
|
{
|
|
|
|
offset += 1;
|
|
|
|
white_space += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
offset += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_text_iter_forward_char (&start);
|
|
|
|
}
|
|
|
|
|
|
|
|
*offsetp = offset;
|
|
|
|
*white_spacep = white_space;
|
|
|
|
if (white_space)
|
|
|
|
*iter = white_space_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-17 05:58:42 -07:00
|
|
|
void
|
|
|
|
moo_indenter_tab (MooIndenter *indenter,
|
|
|
|
GtkTextBuffer *buffer)
|
2005-09-06 09:21:05 -07:00
|
|
|
{
|
|
|
|
GtkTextIter insert, start;
|
|
|
|
int offset, new_offset, white_space;
|
|
|
|
guint tab_width = indenter->tab_width;
|
|
|
|
guint indent = indenter->indent;
|
|
|
|
char *text = NULL;
|
|
|
|
|
|
|
|
gtk_text_buffer_get_iter_at_mark (buffer, &insert, gtk_text_buffer_get_insert (buffer));
|
|
|
|
|
|
|
|
start = insert;
|
|
|
|
iter_get_visual_offset (&start, tab_width, &offset, &white_space);
|
|
|
|
|
|
|
|
new_offset = offset + (indent - offset % indent);
|
|
|
|
text = moo_indenter_make_space (indenter,
|
|
|
|
new_offset - offset + white_space,
|
|
|
|
offset - white_space);
|
|
|
|
|
|
|
|
gtk_text_buffer_delete (buffer, &start, &insert);
|
|
|
|
gtk_text_buffer_insert (buffer, &start, text, -1);
|
|
|
|
|
|
|
|
g_free (text);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
shift_line_forward (MooIndenter *indenter,
|
|
|
|
GtkTextBuffer *buffer,
|
|
|
|
GtkTextIter *iter)
|
|
|
|
{
|
|
|
|
char *text;
|
|
|
|
guint offset;
|
|
|
|
GtkTextIter start;
|
|
|
|
|
|
|
|
if (!compute_line_offset (iter, indenter->tab_width, &offset))
|
2005-10-13 07:08:18 -07:00
|
|
|
return;
|
2005-09-06 09:21:05 -07:00
|
|
|
|
|
|
|
if (offset)
|
|
|
|
{
|
|
|
|
start = *iter;
|
|
|
|
gtk_text_iter_set_line_offset (&start, 0);
|
|
|
|
gtk_text_buffer_delete (buffer, &start, iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
text = moo_indenter_make_space (indenter, offset + indenter->indent, 0);
|
|
|
|
|
|
|
|
if (text)
|
|
|
|
gtk_text_buffer_insert (buffer, iter, text, -1);
|
|
|
|
|
|
|
|
g_free (text);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
shift_line_backward (MooIndenter *indenter,
|
|
|
|
GtkTextBuffer *buffer,
|
|
|
|
GtkTextIter *iter)
|
|
|
|
{
|
|
|
|
GtkTextIter end;
|
|
|
|
int deleted;
|
|
|
|
gunichar c;
|
|
|
|
|
|
|
|
gtk_text_iter_set_line_offset (iter, 0);
|
|
|
|
end = *iter;
|
|
|
|
deleted = 0;
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
if (gtk_text_iter_ends_line (&end))
|
|
|
|
break;
|
|
|
|
|
|
|
|
c = gtk_text_iter_get_char (&end);
|
|
|
|
|
|
|
|
if (c == ' ')
|
|
|
|
{
|
|
|
|
gtk_text_iter_forward_char (&end);
|
|
|
|
deleted += 1;
|
|
|
|
}
|
|
|
|
else if (c == '\t')
|
|
|
|
{
|
|
|
|
gtk_text_iter_forward_char (&end);
|
|
|
|
deleted += indenter->tab_width;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (deleted >= (int) indenter->indent)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_text_buffer_delete (buffer, iter, &end);
|
|
|
|
|
|
|
|
deleted -= indenter->indent;
|
|
|
|
|
|
|
|
if (deleted > 0)
|
|
|
|
{
|
|
|
|
char *text = moo_indenter_make_space (indenter, deleted, 0);
|
|
|
|
gtk_text_buffer_insert (buffer, iter, text, -1);
|
|
|
|
g_free (text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-17 05:58:42 -07:00
|
|
|
void
|
|
|
|
moo_indenter_shift_lines (MooIndenter *indenter,
|
|
|
|
GtkTextBuffer *buffer,
|
|
|
|
guint first_line,
|
|
|
|
guint last_line,
|
|
|
|
int direction)
|
2005-09-06 09:21:05 -07:00
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
GtkTextIter iter;
|
|
|
|
|
|
|
|
for (i = first_line; i <= last_line; ++i)
|
|
|
|
{
|
|
|
|
gtk_text_buffer_get_iter_at_line (buffer, &iter, i);
|
|
|
|
if (direction > 0)
|
|
|
|
shift_line_forward (indenter, buffer, &iter);
|
|
|
|
else
|
|
|
|
shift_line_backward (indenter, buffer, &iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2005-11-24 06:14:48 -08:00
|
|
|
update_variable_default (MooIndenter *indenter,
|
|
|
|
const char *var)
|
2005-09-06 09:21:05 -07:00
|
|
|
{
|
2005-11-24 06:14:48 -08:00
|
|
|
if (!strcmp (var, "indent-tab-width"))
|
2005-09-06 09:21:05 -07:00
|
|
|
{
|
2005-11-24 06:14:48 -08:00
|
|
|
guint tab_width = moo_edit_get_uint (indenter->doc, var, 8);
|
|
|
|
g_object_set (indenter, "tab-width", tab_width, NULL);
|
2005-09-06 09:21:05 -07:00
|
|
|
}
|
2005-11-24 06:14:48 -08:00
|
|
|
else if (!strcmp (var, "indent-use-tabs"))
|
2005-09-06 09:21:05 -07:00
|
|
|
{
|
2005-11-24 06:14:48 -08:00
|
|
|
gboolean use_tabs = moo_edit_get_bool (indenter->doc, var, TRUE);
|
|
|
|
g_object_set (indenter, "use-tabs", use_tabs, NULL);
|
2005-11-02 22:47:53 -08:00
|
|
|
}
|
2005-11-24 06:14:48 -08:00
|
|
|
else if (!strcmp (var, "indent-width"))
|
2005-11-02 22:47:53 -08:00
|
|
|
{
|
2005-11-24 06:14:48 -08:00
|
|
|
guint width = moo_edit_get_uint (indenter->doc, var, 8);
|
2005-11-24 09:36:57 -08:00
|
|
|
g_object_set (indenter, "indent", width, NULL);
|
2005-09-06 09:21:05 -07:00
|
|
|
}
|
|
|
|
}
|