[gtksourceview/wip/chergert/vim] add s&r parser with tests
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/chergert/vim] add s&r parser with tests
- Date: Mon, 8 Nov 2021 23:33:53 +0000 (UTC)
commit 837d49661329ca383d5a65202532476b7ea338c1
Author: Christian Hergert <chergert redhat com>
Date: Mon Nov 8 15:33:49 2021 -0800
add s&r parser with tests
gtksourceview/vim/gtk-source-vim-command.c | 141 ++++++++++++++++++++++++++++-
gtksourceview/vim/gtk-source-vim-command.h | 24 +++--
testsuite/test-vim-input.c | 57 ++++++++++++
3 files changed, 211 insertions(+), 11 deletions(-)
---
diff --git a/gtksourceview/vim/gtk-source-vim-command.c b/gtksourceview/vim/gtk-source-vim-command.c
index 0975481f..fbb2e59f 100644
--- a/gtksourceview/vim/gtk-source-vim-command.c
+++ b/gtksourceview/vim/gtk-source-vim-command.c
@@ -764,6 +764,144 @@ gtk_source_vim_command_line_number (GtkSourceVimCommand *self)
}
}
+gboolean
+gtk_source_vim_command_parse_search_and_replace (const char *str,
+ char **search,
+ char **replace,
+ char **options)
+{
+ const char *c;
+ GString *build = NULL;
+ gunichar sep;
+ gboolean escaped;
+
+ g_assert (search != NULL);
+ g_assert (replace != NULL);
+ g_assert (options != NULL);
+
+ *search = NULL;
+ *replace = NULL;
+ *options = NULL;
+
+ if (str == NULL || *str == 0)
+ return FALSE;
+
+ sep = g_utf8_get_char (str);
+ str = g_utf8_next_char (str);
+
+ /* Check for something like "s/" */
+ if (*str == 0)
+ return TRUE;
+
+ build = g_string_new (NULL);
+ escaped = FALSE;
+ for (c = str; *c; c = g_utf8_next_char (c))
+ {
+ gunichar ch = g_utf8_get_char (c);
+
+ if (escaped)
+ {
+ escaped = FALSE;
+
+ if (ch == sep)
+ {
+ /* don't escape separator in output string */
+ g_string_truncate (build, build->len - 1);
+ }
+ }
+ else if (ch == '\\')
+ {
+ escaped = TRUE;
+ }
+ else if (ch == sep)
+ {
+ *search = g_string_free (g_steal_pointer (&build), FALSE);
+ str = g_utf8_next_char (c);
+ break;
+ }
+
+ g_string_append_unichar (build, ch);
+ }
+
+ if (escaped)
+ return FALSE;
+
+ /* Handle s/foobar (imply //) */
+ if (build != NULL)
+ {
+ *search = g_string_free (g_steal_pointer (&build), FALSE);
+ return TRUE;
+ }
+
+ if (*str == 0)
+ return TRUE;
+
+ build = g_string_new (NULL);
+ escaped = FALSE;
+ for (c = str; *c; c = g_utf8_next_char (c))
+ {
+ gunichar ch = g_utf8_get_char (c);
+
+ if (escaped)
+ {
+ escaped = FALSE;
+
+ if (ch == sep)
+ {
+ /* don't escape separator in output string */
+ g_string_truncate (build, build->len - 1);
+ }
+ }
+ else if (ch == '\\')
+ {
+ escaped = TRUE;
+ }
+ else if (ch == sep)
+ {
+ *replace = g_string_free (g_steal_pointer (&build), FALSE);
+ str = g_utf8_next_char (c);
+ break;
+ }
+
+ g_string_append_unichar (build, ch);
+ }
+
+ if (escaped)
+ return FALSE;
+
+ /* Handle s/foo/bar (imply trailing /) */
+ if (build != NULL)
+ {
+ *replace = g_string_free (g_steal_pointer (&build), FALSE);
+ return TRUE;
+ }
+
+ if (*str != 0)
+ *options = g_strdup (str);
+
+ return TRUE;
+}
+
+static void
+gtk_source_vim_command_search_replace (GtkSourceVimCommand *self)
+{
+ char *search = NULL;
+ char *replace = NULL;
+ char *options = NULL;
+
+ g_assert (GTK_SOURCE_IS_VIM_COMMAND (self));
+
+ if (gtk_source_vim_command_parse_search_and_replace (self->options, &search, &replace, &options))
+ {
+ g_print ("Search: %s\nReplace: %s\nOptions: %s\n",
+ search, replace, options);
+ }
+
+ g_free (search);
+ g_free (replace);
+ g_free (options);
+}
+
static void
gtk_source_vim_command_append_command (GtkSourceVimState *state,
GString *string)
@@ -1052,6 +1190,7 @@ gtk_source_vim_command_class_init (GtkSourceVimCommandClass *klass)
ADD_COMMAND ("line-number", gtk_source_vim_command_line_number);
ADD_COMMAND ("format", gtk_source_vim_command_format);
ADD_COMMAND ("search", gtk_source_vim_command_search);
+ ADD_COMMAND ("search-replace", gtk_source_vim_command_search_replace);
ADD_COMMAND ("search-reverse", gtk_source_vim_command_search_reverse);
#undef ADD_COMMAND
@@ -1310,7 +1449,7 @@ gtk_source_vim_command_new_parsed (GtkSourceVimState *current,
if (*command_line == 's')
{
- ret = GTK_SOURCE_VIM_COMMAND (gtk_source_vim_command_new ("search-and-replace"));
+ ret = GTK_SOURCE_VIM_COMMAND (gtk_source_vim_command_new ("search-replace"));
ret->options = g_strdup (command_line+1);
goto finish;
diff --git a/gtksourceview/vim/gtk-source-vim-command.h b/gtksourceview/vim/gtk-source-vim-command.h
index 038e4a32..2e653f50 100644
--- a/gtksourceview/vim/gtk-source-vim-command.h
+++ b/gtksourceview/vim/gtk-source-vim-command.h
@@ -31,15 +31,19 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GtkSourceVimCommand, gtk_source_vim_command, GTK_SOURCE, VIM_COMMAND,
GtkSourceVimState)
-GtkSourceVimState *gtk_source_vim_command_new (const char *command);
-GtkSourceVimState *gtk_source_vim_command_new_parsed (GtkSourceVimState *current,
- const char *command_line);
-const char *gtk_source_vim_command_get_command (GtkSourceVimCommand *self);
-void gtk_source_vim_command_set_motion (GtkSourceVimCommand *self,
- GtkSourceVimMotion *motion);
-void gtk_source_vim_command_set_selection_motion (GtkSourceVimCommand *self,
- GtkSourceVimMotion *selection_motion);
-void gtk_source_vim_command_set_text_object (GtkSourceVimCommand *self,
- GtkSourceVimTextObject *text_objet);
+GtkSourceVimState *gtk_source_vim_command_new (const char *command);
+GtkSourceVimState *gtk_source_vim_command_new_parsed (GtkSourceVimState *current,
+ const char *command_line);
+const char *gtk_source_vim_command_get_command (GtkSourceVimCommand *self);
+void gtk_source_vim_command_set_motion (GtkSourceVimCommand *self,
+ GtkSourceVimMotion *motion);
+void gtk_source_vim_command_set_selection_motion (GtkSourceVimCommand *self,
+ GtkSourceVimMotion
*selection_motion);
+void gtk_source_vim_command_set_text_object (GtkSourceVimCommand *self,
+ GtkSourceVimTextObject *text_objet);
+gboolean gtk_source_vim_command_parse_search_and_replace (const char *str,
+ char **search,
+ char **replace,
+ char **options);
G_END_DECLS
diff --git a/testsuite/test-vim-input.c b/testsuite/test-vim-input.c
index 19ec096a..0c935119 100644
--- a/testsuite/test-vim-input.c
+++ b/testsuite/test-vim-input.c
@@ -120,6 +120,62 @@ test_motion (void)
#endif
}
+static void
+test_search_and_replace (void)
+{
+ static const struct {
+ const char *command;
+ gboolean success;
+ const char *search;
+ const char *replace;
+ const char *options;
+ } parse_s_and_r[] = {
+ { "s/", TRUE, NULL, NULL, NULL },
+ { "s/a", TRUE, "a", NULL, NULL },
+ { "s/a/", TRUE, "a", NULL, NULL },
+ { "s/a/b", TRUE, "a", "b", NULL },
+ { "s/a/b/", TRUE, "a", "b", NULL },
+ { "s/a/b/c", TRUE, "a", "b", "c" },
+ { "s#a#b#c", TRUE, "a", "b", "c" },
+ { "s/^ \\//", TRUE, "^ /", NULL, NULL },
+ { "s/\\/\\/", TRUE, "//", NULL, NULL },
+ { "s/^$//gI", TRUE, "^$", "", "gI" },
+ };
+
+ for (guint i = 0; i < G_N_ELEMENTS (parse_s_and_r); i++)
+ {
+ const char *str = parse_s_and_r[i].command;
+ char *search = NULL;
+ char *replace = NULL;
+ char *options = NULL;
+ gboolean ret;
+
+ g_assert_true (*str == 's');
+
+ str++;
+ ret = gtk_source_vim_command_parse_search_and_replace (str, &search, &replace, &options);
+
+ if (!parse_s_and_r[i].success && ret)
+ {
+ g_error ("expected %s to fail, but it succeeded",
+ parse_s_and_r[i].command);
+ }
+ else if (parse_s_and_r[i].success && !ret)
+ {
+ g_error ("expected %s to pass, but it failed",
+ parse_s_and_r[i].command);
+ }
+
+ g_assert_cmpstr (search, ==, parse_s_and_r[i].search);
+ g_assert_cmpstr (replace, ==, parse_s_and_r[i].replace);
+ g_assert_cmpstr (options, ==, parse_s_and_r[i].options);
+
+ g_free (search);
+ g_free (replace);
+ g_free (options);
+ }
+}
+
int
main (int argc,
char *argv[])
@@ -130,6 +186,7 @@ main (int argc,
gtk_source_init ();
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/GtkSourceView/vim-input/motion", test_motion);
+ g_test_add_func ("/GtkSourceView/vim-input/search-and-replace", test_search_and_replace);
ret = g_test_run ();
gtk_source_finalize ();
return ret;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]