[gtksourceview/wip/chergert/vim: 292/293] more work on text objects, with tests this time
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/chergert/vim: 292/293] more work on text objects, with tests this time
- Date: Fri, 5 Nov 2021 04:23:08 +0000 (UTC)
commit ae84eb7cf6a6bc9c34d1961ed2683b6dc8a0d661
Author: Christian Hergert <chergert redhat com>
Date: Thu Nov 4 17:51:52 2021 -0700
more work on text objects, with tests this time
gtksourceview/meson.build | 17 +-
gtksourceview/vim/gtk-source-vim-motion.c | 45 +++++-
gtksourceview/vim/gtk-source-vim-normal.c | 71 +++++++--
gtksourceview/vim/gtk-source-vim-state.h | 2 +-
gtksourceview/vim/gtk-source-vim-text-object.c | 212 +++++++++++++++++--------
gtksourceview/vim/meson.build | 16 --
testsuite/meson.build | 1 +
testsuite/test-vim-text-object.c | 145 +++++++++++++++++
8 files changed, 401 insertions(+), 108 deletions(-)
---
diff --git a/gtksourceview/meson.build b/gtksourceview/meson.build
index ee9efebe..664af125 100644
--- a/gtksourceview/meson.build
+++ b/gtksourceview/meson.build
@@ -5,8 +5,6 @@ core_marshallers = gnome.genmarshal('gtksource-marshal',
valist_marshallers: true,
)
-subdir('vim')
-
core_public_h = files([
'gtksource.h',
'gtksourcebuffer.h',
@@ -138,6 +136,20 @@ core_private_c = files([
'gtksourcesnippetbundle-parser.c',
'gtksourceview-snippets.c',
'implregex.c',
+ 'vim/gtk-source-vim.c',
+ 'vim/gtk-source-vim-char-pending.c',
+ 'vim/gtk-source-vim-command-bar.c',
+ 'vim/gtk-source-vim-command.c',
+ 'vim/gtk-source-vim-insert.c',
+ 'vim/gtk-source-vim-insert-literal.c',
+ 'vim/gtk-source-vim-motion.c',
+ 'vim/gtk-source-vim-normal.c',
+ 'vim/gtk-source-vim-registers.c',
+ 'vim/gtk-source-vim-replace.c',
+ 'vim/gtk-source-vim-state.c',
+ 'vim/gtk-source-vim-text-history.c',
+ 'vim/gtk-source-vim-text-object.c',
+ 'vim/gtk-source-vim-visual.c',
])
core_c_args = [
@@ -225,7 +237,6 @@ core_sources = [
gtksourceversion_h,
core_marshallers,
gtksource_res,
- vim_sources,
]
install_headers(
diff --git a/gtksourceview/vim/gtk-source-vim-motion.c b/gtksourceview/vim/gtk-source-vim-motion.c
index c985ad8c..19d8f571 100644
--- a/gtksourceview/vim/gtk-source-vim-motion.c
+++ b/gtksourceview/vim/gtk-source-vim-motion.c
@@ -1997,25 +1997,29 @@ gtk_source_vim_motion_set_linewise_keyval (GtkSourceVimMotion *self,
gboolean
gtk_source_vim_iter_forward_word_end (GtkTextIter *iter)
{
- return forward_classified_end (iter, classify_word_newline_stop);
+ forward_classified_end (iter, classify_word_newline_stop);
+ return TRUE;
}
gboolean
gtk_source_vim_iter_forward_WORD_end (GtkTextIter *iter)
{
- return forward_classified_end (iter, classify_WORD_newline_stop);
+ forward_classified_end (iter, classify_WORD_newline_stop);
+ return TRUE;
}
gboolean
gtk_source_vim_iter_backward_word_start (GtkTextIter *iter)
{
- return backward_classified_start (iter, classify_word_newline_stop);
+ backward_classified_start (iter, classify_word_newline_stop);
+ return TRUE;
}
gboolean
gtk_source_vim_iter_backward_WORD_start (GtkTextIter *iter)
{
- return backward_classified_start (iter, classify_WORD_newline_stop);
+ backward_classified_start (iter, classify_WORD_newline_stop);
+ return TRUE;
}
static inline gboolean
@@ -2137,6 +2141,9 @@ static gboolean
gtk_source_vim_iter_backward_block_start (GtkTextIter *iter,
gunichar ch)
{
+ if (gtk_text_iter_get_char (iter) == ch)
+ return TRUE;
+
return gtk_text_iter_backward_find_char (iter, find_predicate, GSIZE_TO_POINTER (ch), NULL);
}
@@ -2144,6 +2151,9 @@ static gboolean
gtk_source_vim_iter_forward_block_end (GtkTextIter *iter,
gunichar ch)
{
+ if (gtk_text_iter_get_char (iter) == ch)
+ return TRUE;
+
return gtk_text_iter_forward_find_char (iter, find_predicate, GSIZE_TO_POINTER (ch), NULL);
}
@@ -2200,7 +2210,7 @@ gtk_source_vim_iter_backward_quote_start (GtkTextIter *iter,
gunichar ch)
{
GtkTextIter limit = *iter;
- gtk_text_iter_set_line_offset (iter, 0);
+ gtk_text_iter_set_line_offset (&limit, 0);
return gtk_text_iter_backward_find_char (iter, find_predicate, GSIZE_TO_POINTER (ch), &limit);
}
@@ -2208,9 +2218,32 @@ static gboolean
gtk_source_vim_iter_forward_quote_end (GtkTextIter *iter,
gunichar ch)
{
- GtkTextIter limit = *iter;
+ GtkTextIter limit;
+
+ /* The way this seems to work in VIM is that we match
+ * to backwards if we have a preference, then forwards.
+ * So if we find @ch before us and we are currently on
+ * @ch, then that is preferred over scanning forward.
+ */
+ if (ch == gtk_text_iter_get_char (iter) &&
+ !gtk_text_iter_is_start (iter))
+ {
+ GtkTextIter alt = *iter;
+
+ gtk_text_iter_backward_char (&alt);
+
+ if (gtk_source_vim_iter_backward_quote_start (&alt, ch))
+ {
+ return TRUE;
+ }
+
+ gtk_text_iter_forward_char (iter);
+ }
+
+ limit = *iter;
if (!gtk_text_iter_ends_line (&limit))
gtk_text_iter_forward_to_line_end (&limit);
+
return gtk_text_iter_forward_find_char (iter, find_predicate, GSIZE_TO_POINTER (ch), &limit);
}
diff --git a/gtksourceview/vim/gtk-source-vim-normal.c b/gtksourceview/vim/gtk-source-vim-normal.c
index b7387c17..c27047fd 100644
--- a/gtksourceview/vim/gtk-source-vim-normal.c
+++ b/gtksourceview/vim/gtk-source-vim-normal.c
@@ -41,6 +41,13 @@ typedef gboolean (*KeyHandler) (GtkSourceVimNormal *self,
GdkModifierType mods,
const char *string);
+typedef enum
+{
+ CHANGE_NONE = 0,
+ CHANGE_INNER = 1,
+ CHANGE_A = 2,
+} ChangeModifier;
+
struct _GtkSourceVimNormal
{
GtkSourceVimState parent_instance;
@@ -49,6 +56,7 @@ struct _GtkSourceVimNormal
GtkSourceVimState *last_visual;
KeyHandler handler;
int count;
+ ChangeModifier change_modifier;
guint has_count : 1;
};
@@ -634,25 +642,51 @@ key_handler_viewport (GtkSourceVimNormal *self,
}
static gboolean
-key_handler_ci (GtkSourceVimNormal *self,
- guint keyval,
- guint keycode,
- GdkModifierType mods,
- const char *string)
+key_handler_c_with_modifier (GtkSourceVimNormal *self,
+ guint keyval,
+ guint keycode,
+ GdkModifierType mods,
+ const char *string)
{
g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
- return gtk_source_vim_normal_bail (self);
-}
+ /* This should be a TextObject and we might need a "motion or
+ * text object" state.
+ */
-static gboolean
-key_handler_ca (GtkSourceVimNormal *self,
- guint keyval,
- guint keycode,
- GdkModifierType mods,
- const char *string)
-{
- g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
+ switch (keyval)
+ {
+ case GDK_KEY_w:
+ case GDK_KEY_W:
+ case GDK_KEY_p:
+ case GDK_KEY_s:
+ break;
+
+ case GDK_KEY_bracketleft:
+ case GDK_KEY_bracketright:
+ break;
+
+ case GDK_KEY_braceleft:
+ case GDK_KEY_braceright:
+ case GDK_KEY_B:
+ break;
+
+ case GDK_KEY_less:
+ case GDK_KEY_greater:
+ break;
+
+ case GDK_KEY_apostrophe:
+ case GDK_KEY_quotedbl:
+ break;
+
+ case GDK_KEY_parenleft:
+ case GDK_KEY_parenright:
+ case GDK_KEY_b:
+ break;
+
+ default:
+ break;
+ }
return gtk_source_vim_normal_bail (self);
}
@@ -677,11 +711,13 @@ key_handler_c (GtkSourceVimNormal *self,
return TRUE;
case GDK_KEY_i:
- self->handler = key_handler_ci;
+ self->change_modifier = CHANGE_INNER;
+ self->handler = key_handler_c_with_modifier;
return TRUE;
case GDK_KEY_a:
- self->handler = key_handler_ca;
+ self->change_modifier = CHANGE_A;
+ self->handler = key_handler_c_with_modifier;
return TRUE;
default:
@@ -1205,6 +1241,7 @@ gtk_source_vim_normal_clear (GtkSourceVimNormal *self)
self->handler = key_handler_initial;
self->count = 0;
self->has_count = FALSE;
+ self->change_modifier = CHANGE_NONE;
g_string_truncate (self->command_text, 0);
diff --git a/gtksourceview/vim/gtk-source-vim-state.h b/gtksourceview/vim/gtk-source-vim-state.h
index 51014eaf..5ab5889c 100644
--- a/gtksourceview/vim/gtk-source-vim-state.h
+++ b/gtksourceview/vim/gtk-source-vim-state.h
@@ -23,7 +23,7 @@
#include <gtk/gtk.h>
-#include "gtksourcetypes.h"
+#include <gtksourceview/gtksourcetypes.h>
G_BEGIN_DECLS
diff --git a/gtksourceview/vim/gtk-source-vim-text-object.c b/gtksourceview/vim/gtk-source-vim-text-object.c
index 4c45c0ad..73d99c5c 100644
--- a/gtksourceview/vim/gtk-source-vim-text-object.c
+++ b/gtksourceview/vim/gtk-source-vim-text-object.c
@@ -24,16 +24,16 @@
#include "gtk-source-vim-motion.h"
#include "gtk-source-vim-text-object.h"
-typedef gboolean (*TextObjectMotion) (GtkTextIter *iter);
+typedef gboolean (*TextObjectMotion) (GtkTextIter *iter);
+typedef void (*TextObjectExtend) (const GtkTextIter *origin,
+ GtkTextIter *inner_begin,
+ GtkTextIter *inner_end,
+ GtkTextIter *a_begin,
+ GtkTextIter *a_end);
enum {
- TEXT_OBJECT_INNER = 0,
- TEXT_OBJECT_A = 1,
-};
-
-enum {
- TEXT_OBJECT_LINE_ENDS = 0,
- TEXT_OBJECT_BUFFER_ENDS = 1,
+ TEXT_OBJECT_INNER,
+ TEXT_OBJECT_A,
};
struct _GtkSourceVimTextObject
@@ -41,62 +41,143 @@ struct _GtkSourceVimTextObject
GtkSourceVimState parent_instance;
TextObjectMotion forward_end;
TextObjectMotion backward_start;
+ TextObjectExtend extend;
guint inner_or_a : 1;
- guint captivity : 1;
};
G_DEFINE_TYPE (GtkSourceVimTextObject, gtk_source_vim_text_object, GTK_SOURCE_TYPE_VIM_STATE)
+static inline gboolean
+iter_isspace (const GtkTextIter *iter)
+{
+ return g_unichar_isspace (gtk_text_iter_get_char (iter));
+}
+
+static void
+backward_to_first_space (GtkTextIter *iter)
+{
+ while (!gtk_text_iter_starts_line (iter))
+ {
+ gtk_text_iter_backward_char (iter);
+
+ if (!iter_isspace (iter))
+ {
+ gtk_text_iter_forward_char (iter);
+ return;
+ }
+ }
+}
+
+static void
+text_object_extend_word (const GtkTextIter *origin,
+ GtkTextIter *inner_begin,
+ GtkTextIter *inner_end,
+ GtkTextIter *a_begin,
+ GtkTextIter *a_end)
+{
+ gtk_text_iter_forward_char (inner_end);
+
+ *a_begin = *inner_begin;
+ *a_end = *inner_end;
+
+ while (!gtk_text_iter_ends_line (a_end) && iter_isspace (a_end))
+ gtk_text_iter_forward_char (a_end);
+
+ backward_to_first_space (a_begin);
+
+ /* If @origin is between a_begin and inner_begin, then we
+ * actually want to just select that space.
+ */
+ if (gtk_text_iter_compare (a_begin, origin) <= 0 &&
+ gtk_text_iter_compare (origin, inner_begin) < 0)
+ {
+ *inner_end = *inner_begin;
+ *inner_begin = *a_begin;
+ *a_end = *inner_end;
+ }
+}
+
+static void
+text_object_extend_one (const GtkTextIter *origin,
+ GtkTextIter *inner_begin,
+ GtkTextIter *inner_end,
+ GtkTextIter *a_begin,
+ GtkTextIter *a_end)
+{
+ *a_begin = *inner_begin;
+ gtk_text_iter_forward_char (inner_begin);
+ *a_end = *inner_end;
+ gtk_text_iter_forward_char (a_end);
+}
+
+static void
+text_object_extend_paragraph (const GtkTextIter *origin,
+ GtkTextIter *inner_begin,
+ GtkTextIter *inner_end,
+ GtkTextIter *a_begin,
+ GtkTextIter *a_end)
+{
+}
+
+static void
+text_object_extend_sentence (const GtkTextIter *origin,
+ GtkTextIter *inner_begin,
+ GtkTextIter *inner_end,
+ GtkTextIter *a_begin,
+ GtkTextIter *a_end)
+{
+}
+
static GtkSourceVimState *
gtk_source_vim_text_object_new (TextObjectMotion forward_end,
TextObjectMotion backward_start,
- guint inner_or_a,
- guint captivity)
+ TextObjectExtend extend,
+ guint inner_or_a)
{
GtkSourceVimTextObject *self;
self = g_object_new (GTK_SOURCE_TYPE_VIM_TEXT_OBJECT, NULL);
self->forward_end = forward_end;
self->backward_start = backward_start;
- self->inner_or_a = !!inner_or_a;
- self->captivity = !!captivity;
+ self->extend = extend;
+ self->inner_or_a = inner_or_a;
return GTK_SOURCE_VIM_STATE (self);
}
-#define TEXT_OBJECT_CTOR(name, forward, backward, inner_or_a, captivity) \
+#define TEXT_OBJECT_CTOR(name, forward, backward, extend, inner_or_a) \
GtkSourceVimState * \
gtk_source_vim_text_object_new_##name (void) \
{ \
return gtk_source_vim_text_object_new (gtk_source_vim_iter_##forward, \
- gtk_source_vim_iter_##backward, \
- TEXT_OBJECT_##inner_or_a, \
- TEXT_OBJECT_##captivity); \
+ gtk_source_vim_iter_##backward, \
+ text_object_extend_##extend, \
+ TEXT_OBJECT_##inner_or_a); \
}
-TEXT_OBJECT_CTOR (inner_word, forward_word_end, backward_word_start, INNER, LINE_ENDS)
-TEXT_OBJECT_CTOR (inner_WORD, forward_WORD_end, backward_WORD_start, INNER, LINE_ENDS)
-TEXT_OBJECT_CTOR (inner_sentence, forward_sentence_end, backward_word_start, INNER, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (inner_paragraph, forward_paragraph_end, backward_paragraph_start, INNER, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (inner_block_paren, forward_block_paren_end, backward_block_paren_start, INNER, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (inner_block_brace, forward_block_brace_end, backward_block_brace_start, INNER, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (inner_block_bracket, forward_block_bracket_end, backward_block_bracket_start, INNER,
BUFFER_ENDS)
-TEXT_OBJECT_CTOR (inner_block_lt_gt, forward_block_lt_gt_end, backward_block_lt_gt_start, INNER, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (inner_quote_double, forward_quote_double, backward_quote_double, INNER, LINE_ENDS)
-TEXT_OBJECT_CTOR (inner_quote_single, forward_quote_single, backward_quote_single, INNER, LINE_ENDS)
-TEXT_OBJECT_CTOR (inner_quote_grave, forward_quote_grave, backward_quote_grave, INNER, LINE_ENDS)
-
-TEXT_OBJECT_CTOR (a_word, forward_word_end, backward_word_start, A, LINE_ENDS)
-TEXT_OBJECT_CTOR (a_WORD, forward_WORD_end, backward_WORD_start, A, LINE_ENDS)
-TEXT_OBJECT_CTOR (a_sentence, forward_sentence_end, backward_word_start, A, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (a_paragraph, forward_paragraph_end, backward_paragraph_start, A, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (a_block_paren, forward_block_paren_end, backward_block_paren_start, A, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (a_block_brace, forward_block_brace_end, backward_block_brace_start, A, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (a_block_bracket, forward_block_bracket_end, backward_block_bracket_start, A, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (a_block_lt_gt, forward_block_lt_gt_end, backward_block_lt_gt_start, A, BUFFER_ENDS)
-TEXT_OBJECT_CTOR (a_quote_double, forward_quote_double, backward_quote_double, A, LINE_ENDS)
-TEXT_OBJECT_CTOR (a_quote_single, forward_quote_single, backward_quote_single, A, LINE_ENDS)
-TEXT_OBJECT_CTOR (a_quote_grave, forward_quote_grave, backward_quote_grave, A, LINE_ENDS)
+TEXT_OBJECT_CTOR (inner_word, forward_word_end, backward_word_start, word, INNER);
+TEXT_OBJECT_CTOR (inner_WORD, forward_WORD_end, backward_WORD_start, word, INNER);
+TEXT_OBJECT_CTOR (inner_sentence, forward_sentence_end, backward_sentence_start, sentence, INNER);
+TEXT_OBJECT_CTOR (inner_paragraph, forward_paragraph_end, backward_paragraph_start, paragraph, INNER);
+TEXT_OBJECT_CTOR (inner_block_paren, forward_block_paren_end, backward_block_paren_start, one, INNER);
+TEXT_OBJECT_CTOR (inner_block_brace, forward_block_brace_end, backward_block_brace_start, one, INNER);
+TEXT_OBJECT_CTOR (inner_block_bracket, forward_block_bracket_end, backward_block_bracket_start, one, INNER);
+TEXT_OBJECT_CTOR (inner_block_lt_gt, forward_block_lt_gt_end, backward_block_lt_gt_start, one, INNER);
+TEXT_OBJECT_CTOR (inner_quote_double, forward_quote_double, backward_quote_double, one, INNER);
+TEXT_OBJECT_CTOR (inner_quote_single, forward_quote_single, backward_quote_single, one, INNER);
+TEXT_OBJECT_CTOR (inner_quote_grave, forward_quote_grave, backward_quote_grave, one, INNER);
+
+TEXT_OBJECT_CTOR (a_word, forward_word_end, backward_word_start, word, A);
+TEXT_OBJECT_CTOR (a_WORD, forward_WORD_end, backward_WORD_start, word, A);
+TEXT_OBJECT_CTOR (a_sentence, forward_sentence_end, backward_sentence_start, sentence, A);
+TEXT_OBJECT_CTOR (a_paragraph, forward_paragraph_end, backward_paragraph_start, paragraph, A);
+TEXT_OBJECT_CTOR (a_block_paren, forward_block_paren_end, backward_block_paren_start, one, A);
+TEXT_OBJECT_CTOR (a_block_brace, forward_block_brace_end, backward_block_brace_start, one, A);
+TEXT_OBJECT_CTOR (a_block_bracket, forward_block_bracket_end, backward_block_bracket_start, one, A);
+TEXT_OBJECT_CTOR (a_block_lt_gt, forward_block_lt_gt_end, backward_block_lt_gt_start, one, A);
+TEXT_OBJECT_CTOR (a_quote_double, forward_quote_double, backward_quote_double, one, A);
+TEXT_OBJECT_CTOR (a_quote_single, forward_quote_single, backward_quote_single, one, A);
+TEXT_OBJECT_CTOR (a_quote_grave, forward_quote_grave, backward_quote_grave, one, A);
#undef TEXT_OBJECT_CTOR
@@ -124,47 +205,48 @@ gtk_source_vim_text_object_select (GtkSourceVimTextObject *self,
GtkTextIter *begin,
GtkTextIter *end)
{
- GtkTextIter b, e;
+ GtkTextIter inner_begin;
+ GtkTextIter inner_end;
+ GtkTextIter a_begin;
+ GtkTextIter a_end;
g_return_val_if_fail (GTK_SOURCE_IS_VIM_TEXT_OBJECT (self), FALSE);
g_return_val_if_fail (begin != NULL, FALSE);
g_return_val_if_fail (end != NULL, FALSE);
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (gtk_text_iter_get_buffer (begin)), FALSE);
+ g_return_val_if_fail (self->forward_end != NULL, FALSE);
+ g_return_val_if_fail (self->backward_start != NULL, FALSE);
+ g_return_val_if_fail (self->extend != NULL, FALSE);
- if (self->forward_end == NULL || self->backward_start == NULL)
+ inner_end = *begin;
+ if (!self->forward_end (&inner_end))
+ {
+ g_print ("forward end failed\n");
return FALSE;
+ }
- b = e = *begin;
-
- if (!self->forward_end (&e))
+ inner_begin = inner_end;
+ if (!self->backward_start (&inner_begin))
+ {
+ g_print ("backward start failed\n");
return FALSE;
+ }
- b = e;
+ a_begin = inner_begin;
+ a_end = inner_end;
- if (!self->backward_start (&b))
- return FALSE;
+ self->extend (begin, &inner_begin, &inner_end, &a_begin, &a_end);
- if (self->captivity == TEXT_OBJECT_LINE_ENDS)
+ if (self->inner_or_a == TEXT_OBJECT_INNER)
{
- if (gtk_text_iter_get_line (&b) != gtk_text_iter_get_line (&e) ||
- gtk_text_iter_get_line (&b) != gtk_text_iter_get_line (begin) ||
- gtk_text_iter_get_line (&e) != gtk_text_iter_get_line (begin))
- {
- return FALSE;
- }
+ *begin = inner_begin;
+ *end = inner_end;
}
-
- /* If we're INNER and find the new begin position being after
- * where we started, then we want to select the space between
- * the new beginning and the previous ending.
- */
- if (self->inner_or_a == TEXT_OBJECT_INNER &&
- gtk_text_iter_compare (begin, &b) < 0)
+ else
{
+ *begin = a_begin;
+ *end = a_end;
}
- *begin = b;
- *end = e;
-
return TRUE;
}
diff --git a/testsuite/meson.build b/testsuite/meson.build
index efa4072a..28713e83 100644
--- a/testsuite/meson.build
+++ b/testsuite/meson.build
@@ -37,6 +37,7 @@ testsuite_sources = [
['test-syntax'],
['test-utils'],
['test-view'],
+ ['test-vim-text-object'],
]
foreach test: testsuite_sources
diff --git a/testsuite/test-vim-text-object.c b/testsuite/test-vim-text-object.c
new file mode 100644
index 00000000..e9f585a8
--- /dev/null
+++ b/testsuite/test-vim-text-object.c
@@ -0,0 +1,145 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2021 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView 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.
+ *
+ * GtkSourceView is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <gtksourceview/gtksource.h>
+#include <gtksourceview/vim/gtk-source-vim-text-object.h>
+
+static void
+run_test (GtkSourceVimState *text_object,
+ const char *text,
+ guint position,
+ const char *expect_selection,
+ gboolean expect_fail)
+{
+ GtkSourceBuffer *buffer;
+ GtkTextIter begin, end;
+
+ g_assert (GTK_SOURCE_IS_VIM_TEXT_OBJECT (text_object));
+ g_assert (text != NULL);
+
+ buffer = gtk_source_buffer_new (NULL);
+ gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), text, -1);
+
+ gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &begin, position);
+ end = begin;
+
+ if (!gtk_source_vim_text_object_select (GTK_SOURCE_VIM_TEXT_OBJECT (text_object), &begin, &end))
+ {
+ if (expect_fail)
+ goto cleanup;
+ g_error ("Failed to select text-object\n\n'''%s'''\npotiion: %u\nepxecting: '''%s'''",
+ text, position, expect_selection);
+ }
+
+ if (expect_fail)
+ {
+ char *out = gtk_text_iter_get_slice (&begin, &end);
+ g_error ("Expected to fail selection but got '''%s'''", out);
+ g_free (out);
+ }
+ else
+ {
+ char *selected_text = gtk_text_iter_get_slice (&begin, &end);
+ g_assert_cmpstr (selected_text, ==, expect_selection);
+ g_free (selected_text);
+ }
+
+cleanup:
+ g_clear_object (&buffer);
+ g_clear_object (&text_object);
+}
+
+static void
+test_word (void)
+{
+ run_test (gtk_source_vim_text_object_new_inner_word (), "", 0, "", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_word (), "this is some- text to modify\n", 8, "some",
FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_word (), "something here\n", 10, " ", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_word (), "something here", 9, " ", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_word (), "a", 0, "a", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_word (), "a b", 1, " ", FALSE);
+ //run_test (gtk_source_vim_text_object_new_a_word (), "a b", 1, " b", FALSE);
+}
+
+static void
+test_WORD (void)
+{
+ run_test (gtk_source_vim_text_object_new_inner_WORD (),
+ "this is some- text to modify\n", 8, "some-", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_WORD (),
+ "something here\n", 10, " ", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_WORD (),
+ "something here", 9, " ", FALSE);
+}
+
+static void
+test_block (void)
+{
+ run_test (gtk_source_vim_text_object_new_a_block_paren (),
+ "this_is_a_function (some stuff\n and some more)\ntrailing",
+ 23, "(some stuff\n and some more)", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_block_paren (),
+ "this_is_a_function (some stuff\n and some more)\ntrailing",
+ 23, "some stuff\n and some more", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_block_paren (),
+ "(should not match\n", 5, NULL, TRUE);
+
+ run_test (gtk_source_vim_text_object_new_inner_block_paren (), "(m)", 0, "m", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_block_paren (), "(m)", 1, "m", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_block_paren (), "(m)", 2, "m", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_block_paren (), "(m)", 3, NULL, TRUE);
+ run_test (gtk_source_vim_text_object_new_a_block_paren (), "(m)", 0, "(m)", FALSE);
+ run_test (gtk_source_vim_text_object_new_a_block_paren (), "(m)", 1, "(m)", FALSE);
+ run_test (gtk_source_vim_text_object_new_a_block_paren (), "(m)", 2, "(m)", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_block_paren (), "(m)", 3, NULL, TRUE);
+}
+
+static void
+test_quote (void)
+{
+ run_test (gtk_source_vim_text_object_new_inner_quote_double (), "\"this is a string.\"", 0, "this is
a string.", FALSE);
+ run_test (gtk_source_vim_text_object_new_a_quote_double (), "\"this is a string.\"", 0, "\"this is a
string.\"", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_quote_double (), "\"this is a string.\n", 0, NULL,
TRUE);
+ run_test (gtk_source_vim_text_object_new_inner_quote_double (), "\"this \"is a string.\"", 6, "this
", FALSE);
+ run_test (gtk_source_vim_text_object_new_a_quote_double (), "\"this \"is a string.\"", 6, "\"this
\"", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_quote_double (), "\"this \"is a string.\"", 7, "is a
string.", FALSE);
+ run_test (gtk_source_vim_text_object_new_inner_quote_double (), "\"this \"is a string.", 7, NULL,
TRUE);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ int ret;
+
+ gtk_init ();
+ gtk_source_init ();
+ g_test_init (&argc, &argv, NULL);
+ g_test_add_func ("/GtkSourceView/vim-text-object/word", test_word);
+ g_test_add_func ("/GtkSourceView/vim-text-object/WORD", test_WORD);
+ g_test_add_func ("/GtkSourceView/vim-text-object/block", test_block);
+ g_test_add_func ("/GtkSourceView/vim-text-object/quote", test_quote);
+ ret = g_test_run ();
+ gtk_source_finalize ();
+ return ret;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]