Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- From 2473d3505c88fededc373e666cec660acb93d7f8 Mon Sep 17 00:00:00 2001
- From: Sebastien Lafargue <slafargue@gnome.org>
- Date: Thu, 30 Apr 2015 18:14:22 +0200
- Subject: \vim: new parser for command line
- ---
- data/keybindings/default.css | 4 +-
- data/keybindings/emacs.css | 6 +-
- data/theme/shared.css | 23 +
- libide/Makefile.am | 28 +-
- libide/ide-source-view.c | 19 +-
- libide/ide-source-view.h | 3 +-
- libide/ide-vim-iter.c | 457 -----
- libide/ide-vim-iter.h | 39 -
- libide/ide.h | 7 +
- libide/vim/ide-vim-complete-item.c | 261 +++
- libide/vim/ide-vim-complete-item.h | 58 +
- libide/vim/ide-vim-iter.c | 457 +++++
- libide/vim/ide-vim-iter.h | 39 +
- libide/vim/ide-vim-parser-command.c | 633 +++++++
- libide/vim/ide-vim-parser-command.h | 66 +
- libide/vim/ide-vim-parser-commands.c | 29 +
- libide/vim/ide-vim-parser-commands.h | 41 +
- libide/vim/ide-vim-parser-debug.c | 151 ++
- libide/vim/ide-vim-parser-debug.h | 36 +
- libide/vim/ide-vim-parser-error.c | 340 ++++
- libide/vim/ide-vim-parser-error.h | 93 +
- libide/vim/ide-vim-parser-objects-pool.c | 496 ++++++
- libide/vim/ide-vim-parser-objects-pool.h | 63 +
- libide/vim/ide-vim-parser-private.h | 37 +
- libide/vim/ide-vim-parser-settable.c | 559 ++++++
- libide/vim/ide-vim-parser-settable.h | 93 +
- libide/vim/ide-vim-parser-token.c | 124 ++
- libide/vim/ide-vim-parser-token.h | 92 +
- libide/vim/ide-vim-parser-types.h | 28 +
- libide/vim/ide-vim-parser.c | 1926 +++++++++++++++++++++
- libide/vim/ide-vim-parser.h | 125 ++
- libide/vim/ide-vim-state-machine.c | 500 ++++++
- libide/vim/ide-vim-state-machine.h | 63 +
- libide/vim/ide-vim-state-private.h | 37 +
- libide/vim/ide-vim-state-result.c | 73 +
- libide/vim/ide-vim-state-result.h | 39 +
- libide/vim/ide-vim-state.c | 162 ++
- libide/vim/ide-vim-state.h | 71 +
- plugins/command-bar/Makefile.am | 4 +
- plugins/command-bar/gb-command-bar-item.c | 257 +++
- plugins/command-bar/gb-command-bar-item.h | 39 +
- plugins/command-bar/gb-command-bar-item.ui | 83 +
- plugins/command-bar/gb-command-bar.c | 493 +++++-
- plugins/command-bar/gb-command-bar.gresource.xml | 1 +
- plugins/command-bar/gb-command-bar.ui | 67 +-
- plugins/command-bar/gb-command-complete-item.c | 113 ++
- plugins/command-bar/gb-command-complete-item.h | 53 +
- plugins/command-bar/gb-command-gaction-provider.c | 35 +-
- plugins/command-bar/gb-command-gaction-provider.h | 1 +
- plugins/command-bar/gb-command-manager.c | 61 +-
- plugins/command-bar/gb-command-manager.h | 17 +-
- plugins/command-bar/gb-command-provider.c | 77 +-
- plugins/command-bar/gb-command-provider.h | 41 +-
- plugins/command-bar/gb-command-vim-provider.c | 195 ++-
- plugins/command-bar/gb-command-vim-provider.h | 1 +
- plugins/command-bar/gb-command-vim.c | 111 +-
- plugins/command-bar/gb-command-vim.h | 6 +
- plugins/command-bar/gb-command.c | 171 +-
- plugins/command-bar/gb-command.h | 9 +-
- plugins/command-bar/gb-vim.c | 591 ++++---
- plugins/command-bar/gb-vim.h | 98 +-
- src/editor/gb-editor-frame.c | 2 +
- src/resources/gnome-builder.gresource.xml | 1 -
- src/views/gb-view-stack-actions.c | 81 +-
- src/views/gb-view-stack-private.h | 1 -
- src/views/gb-view-stack.c | 105 +-
- tests/Makefile.am | 9 +
- tests/test-ide-vim-parser-settable.c | 280 +++
- tests/test-ide-vim-parser.c | 283 +++
- 69 files changed, 9542 insertions(+), 1022 deletions(-)
- delete mode 100644 libide/ide-vim-iter.c
- delete mode 100644 libide/ide-vim-iter.h
- create mode 100644 libide/vim/ide-vim-complete-item.c
- create mode 100644 libide/vim/ide-vim-complete-item.h
- create mode 100644 libide/vim/ide-vim-iter.c
- create mode 100644 libide/vim/ide-vim-iter.h
- create mode 100644 libide/vim/ide-vim-parser-command.c
- create mode 100644 libide/vim/ide-vim-parser-command.h
- create mode 100644 libide/vim/ide-vim-parser-commands.c
- create mode 100644 libide/vim/ide-vim-parser-commands.h
- create mode 100644 libide/vim/ide-vim-parser-debug.c
- create mode 100644 libide/vim/ide-vim-parser-debug.h
- create mode 100644 libide/vim/ide-vim-parser-error.c
- create mode 100644 libide/vim/ide-vim-parser-error.h
- create mode 100644 libide/vim/ide-vim-parser-objects-pool.c
- create mode 100644 libide/vim/ide-vim-parser-objects-pool.h
- create mode 100644 libide/vim/ide-vim-parser-private.h
- create mode 100644 libide/vim/ide-vim-parser-settable.c
- create mode 100644 libide/vim/ide-vim-parser-settable.h
- create mode 100644 libide/vim/ide-vim-parser-token.c
- create mode 100644 libide/vim/ide-vim-parser-token.h
- create mode 100644 libide/vim/ide-vim-parser-types.h
- create mode 100644 libide/vim/ide-vim-parser.c
- create mode 100644 libide/vim/ide-vim-parser.h
- create mode 100644 libide/vim/ide-vim-state-machine.c
- create mode 100644 libide/vim/ide-vim-state-machine.h
- create mode 100644 libide/vim/ide-vim-state-private.h
- create mode 100644 libide/vim/ide-vim-state-result.c
- create mode 100644 libide/vim/ide-vim-state-result.h
- create mode 100644 libide/vim/ide-vim-state.c
- create mode 100644 libide/vim/ide-vim-state.h
- create mode 100644 plugins/command-bar/gb-command-bar-item.c
- create mode 100644 plugins/command-bar/gb-command-bar-item.h
- create mode 100644 plugins/command-bar/gb-command-bar-item.ui
- create mode 100644 plugins/command-bar/gb-command-complete-item.c
- create mode 100644 plugins/command-bar/gb-command-complete-item.h
- create mode 100644 tests/test-ide-vim-parser-settable.c
- create mode 100644 tests/test-ide-vim-parser.c
- diff --git a/data/keybindings/default.css b/data/keybindings/default.css
- index 2563d71..47466cf 100644
- --- a/data/keybindings/default.css
- +++ b/data/keybindings/default.css
- @@ -38,8 +38,8 @@
- bind "F6" { "action" ("view", "preview", "") };
- bind "F9" { "action" ("workspace", "toggle-sidebar", "") };
- - bind "<alt>n" { "move-error" (down) };
- - bind "<alt>p" { "move-error" (up) };
- + bind "<alt>n" { "move-error" (down, 1) };
- + bind "<alt>p" { "move-error" (up, 1) };
- bind "<ctrl>Return" { "action" ("win", "show-command-bar", "") };
- bind "<ctrl>KP_Enter" { "action" ("win", "show-command-bar", "") };
- diff --git a/data/keybindings/emacs.css b/data/keybindings/emacs.css
- index 5f537a1..d0cd58c 100644
- --- a/data/keybindings/emacs.css
- +++ b/data/keybindings/emacs.css
- @@ -55,8 +55,8 @@
- bind "<ctrl>period" { "action" ("workbench", "global-search", "") };
- bind "<alt>period" { "goto-definition" () };
- bind "<ctrl>comma" { "action" ("app", "preferences", "") };
- - bind "<alt>n" { "move-error" (down) };
- - bind "<alt>p" { "move-error" (up) };
- + bind "<alt>n" { "move-error" (down, 1) };
- + bind "<alt>p" { "move-error" (up, 1) };
- bind "<ctrl>j" { "action" ("view-grid", "focus-neighbor", "3") };
- bind "<shift><ctrl>j" { "action" ("view-stack", "split-down", "") };
- bind "F2" { "clear-selection" ()
- @@ -111,7 +111,7 @@
- bind "2" { "action" ("view-stack", "split-down", "") };
- bind "3" { "action" ("view-stack", "split-right", "") };
- bind "o" { "action" ("view-grid", "focus-neighbor", "0") };
- - bind "grave" { "move-error" (down) };
- + bind "grave" { "move-error" (down), 1 };
- bind "h" { "select-all" (1) };
- }
- diff --git a/data/theme/shared.css b/data/theme/shared.css
- index 53e2958..9934f53 100644
- --- a/data/theme/shared.css
- +++ b/data/theme/shared.css
- @@ -78,6 +78,29 @@ GtkEntry.gb-command-bar-entry {
- color: #eeeeec;
- }
- +.gb-command-bar-results,
- +.gb-command-bar-results GtkListBox {
- + background-color: #2e3436;
- +}
- +.gb-command-bar-results GtkListBoxRow:hover {
- + background-color: #454a47;
- +}
- +.gb-command-bar-results GtkListBoxRow:selected {
- + background-color: #2e5797;
- +}
- +.gb-command-bar-results GtkListBoxRow:hover:selected {
- + background-color: #3a669f;
- +}
- +
- +.gb-command-bar-box GtkButton {
- + border-color: #43484A;
- + box-shadow: none;
- + background-image: inherit;
- +}
- +.gb-command-bar-box GtkButton:hover {
- + outline-color: rgba(238, 238, 236, 0.3);
- + background-image: linear-gradient(to bottom, #2e3436, #555753 10%);
- +}
- /*
- * Style selector widget.
- diff --git a/libide/Makefile.am b/libide/Makefile.am
- index b658b24..cd8f2c4 100644
- --- a/libide/Makefile.am
- +++ b/libide/Makefile.am
- @@ -184,6 +184,21 @@ libide_1_0_la_public_sources = \
- theatrics/ide-animation.h \
- vala/ide-vala-language.c \
- vala/ide-vala-language.h \
- + vim/ide-vim-parser.c \
- + vim/ide-vim-parser.h \
- + vim/ide-vim-parser-command.c \
- + vim/ide-vim-parser-command.h \
- + vim/ide-vim-parser-debug.c \
- + vim/ide-vim-parser-error.c \
- + vim/ide-vim-parser-error.h \
- + vim/ide-vim-parser-objects-pool.c \
- + vim/ide-vim-parser-objects-pool.h \
- + vim/ide-vim-parser-settable.c \
- + vim/ide-vim-parser-settable.h \
- + vim/ide-vim-parser-token.c \
- + vim/ide-vim-parser-token.h \
- + vim/ide-vim-complete-item.c \
- + vim/ide-vim-complete-item.h \
- xml/ide-xml-language.c \
- xml/ide-xml-language.h \
- $(NULL)
- @@ -292,8 +307,6 @@ libide_1_0_la_SOURCES = \
- ide-source-view-capture.h \
- ide-source-view-movements.c \
- ide-source-view-movements.h \
- - ide-vim-iter.c \
- - ide-vim-iter.h \
- mingw/ide-mingw-device-provider.c \
- mingw/ide-mingw-device-provider.h \
- modelines/ide-modelines-file-settings.c \
- @@ -324,6 +337,16 @@ libide_1_0_la_SOURCES = \
- util/ide-rgba.h \
- util/ide-xml.c \
- util/ide-xml.h \
- + vim/ide-vim-iter.c \
- + vim/ide-vim-iter.h \
- + vim/ide-vim-parser-commands.c \
- + vim/ide-vim-parser-commands.h \
- + vim/ide-vim-state.c \
- + vim/ide-vim-state.h \
- + vim/ide-vim-state-machine.c \
- + vim/ide-vim-state-machine.h \
- + vim/ide-vim-state-result.c \
- + vim/ide-vim-state-result.h \
- xml/ide-xml-highlighter.c \
- xml/ide-xml-highlighter.h \
- xml/ide-xml-indenter.c \
- @@ -362,6 +385,7 @@ libide_1_0_la_includes = \
- -I$(srcdir)/theatrics \
- -I$(srcdir)/util \
- -I$(srcdir)/vala \
- + -I$(srcdir)/vim \
- -I$(srcdir)/xml \
- $(NULL)
- diff --git a/libide/ide-source-view.c b/libide/ide-source-view.c
- index 1e31f16..d0d4f90 100644
- --- a/libide/ide-source-view.c
- +++ b/libide/ide-source-view.c
- @@ -3219,7 +3219,8 @@ ide_source_view_real_move_search (IdeSourceView *self,
- static void
- ide_source_view_real_move_error (IdeSourceView *self,
- - GtkDirectionType dir)
- + GtkDirectionType dir,
- + gint count)
- {
- IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
- GtkTextBuffer *buffer;
- @@ -3272,11 +3273,13 @@ ide_source_view_real_move_error (IdeSourceView *self,
- break;
- gtk_text_buffer_select_range (buffer, &iter, &iter);
- - ide_source_view_scroll_mark_onscreen (self, insert, TRUE, 0.5, 0.5);
- - return;
- + g_signal_emit_by_name (self, "save-insert-mark");
- + if (--count == 0)
- + {
- + ide_source_view_scroll_mark_onscreen (self, insert, TRUE, 0.5, 0.5);
- + return;
- + }
- }
- -
- - break;
- }
- }
- }
- @@ -5525,6 +5528,7 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
- * IdeSourceView::move-error:
- * @self: An #IdeSourceView.
- * @dir: The direction to move.
- + * @count: The nth error to go.
- *
- * Moves to the next search result either forwards or backwards.
- */
- @@ -5535,8 +5539,9 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
- G_STRUCT_OFFSET (IdeSourceViewClass, move_error),
- NULL, NULL, NULL,
- G_TYPE_NONE,
- - 1,
- - GTK_TYPE_DIRECTION_TYPE);
- + 2,
- + GTK_TYPE_DIRECTION_TYPE,
- + G_TYPE_INT);
- gSignals [MOVE_SEARCH] =
- g_signal_new ("move-search",
- diff --git a/libide/ide-source-view.h b/libide/ide-source-view.h
- index 2e6cac9..40de334 100644
- --- a/libide/ide-source-view.h
- +++ b/libide/ide-source-view.h
- @@ -222,7 +222,8 @@ struct _IdeSourceViewClass
- gboolean exclusive,
- gboolean apply_count);
- void (*move_error) (IdeSourceView *self,
- - GtkDirectionType dir);
- + GtkDirectionType dir,
- + gint count);
- void (*move_search) (IdeSourceView *self,
- GtkDirectionType dir,
- gboolean extend_selection,
- diff --git a/libide/ide-vim-iter.c b/libide/ide-vim-iter.c
- deleted file mode 100644
- index d03b829..0000000
- --- a/libide/ide-vim-iter.c
- +++ /dev/null
- @@ -1,457 +0,0 @@
- -/* ide-vim-iter.c
- - *
- - * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
- - *
- - * 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 3 of the License, or
- - * (at your option) any later version.
- - *
- - * This program 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 General Public License for more details.
- - *
- - * You should have received a copy of the GNU General Public License
- - * along with this program. If not, see <http://www.gnu.org/licenses/>.
- - */
- -
- -#include <gtk/gtk.h>
- -
- -#include "ide-debug.h"
- -#include "ide-vim-iter.h"
- -
- -typedef enum
- -{
- - SENTENCE_OK,
- - SENTENCE_PARA,
- - SENTENCE_FAILED,
- -} SentenceStatus;
- -
- -enum
- -{
- - CLASS_0,
- - CLASS_SPACE,
- - CLASS_SPECIAL,
- - CLASS_WORD,
- -};
- -
- -static int
- -_ide_vim_word_classify (gunichar ch)
- -{
- - switch (ch)
- - {
- - case ' ':
- - case '\t':
- - case '\n':
- - return CLASS_SPACE;
- -
- - case '"': case '\'':
- - case '(': case ')':
- - case '{': case '}':
- - case '[': case ']':
- - case '<': case '>':
- - case '-': case '+': case '*': case '/':
- - case '!': case '@': case '#': case '$': case '%':
- - case '^': case '&': case ':': case ';': case '?':
- - case '|': case '=': case '\\': case '.': case ',':
- - return CLASS_SPECIAL;
- -
- - case '_':
- - default:
- - return CLASS_WORD;
- - }
- -}
- -
- -static int
- -_ide_vim_WORD_classify (gunichar ch)
- -{
- - if (g_unichar_isspace (ch))
- - return CLASS_SPACE;
- - return CLASS_WORD;
- -}
- -
- -static gboolean
- -_ide_vim_iter_line_is_empty (GtkTextIter *iter)
- -{
- - return gtk_text_iter_starts_line (iter) && gtk_text_iter_ends_line (iter);
- -}
- -
- -/**
- - * _ide_vim_iter_backward_paragraph_start:
- - * @iter: A #GtkTextIter
- - *
- - * Searches backwards until we find the beginning of a paragraph.
- - *
- - * Returns: %TRUE if we are not at the beginning of the buffer; otherwise %FALSE.
- - */
- -gboolean
- -_ide_vim_iter_backward_paragraph_start (GtkTextIter *iter)
- -{
- - g_return_val_if_fail (iter, FALSE);
- -
- - /* Work our way past the current empty lines */
- - if (_ide_vim_iter_line_is_empty (iter))
- - while (_ide_vim_iter_line_is_empty (iter))
- - if (!gtk_text_iter_backward_line (iter))
- - return FALSE;
- -
- - /* Now find first line that is empty */
- - while (!_ide_vim_iter_line_is_empty (iter))
- - if (!gtk_text_iter_backward_line (iter))
- - return FALSE;
- -
- - return TRUE;
- -}
- -
- -/**
- - * _ide_vim_iter_forward_paragraph_end:
- - * @iter: A #GtkTextIter
- - *
- - * Searches forward until the end of a paragraph has been hit.
- - *
- - * Returns: %TRUE if we are not at the end of the buffer; otherwise %FALSE.
- - */
- -gboolean
- -_ide_vim_iter_forward_paragraph_end (GtkTextIter *iter)
- -{
- - g_return_val_if_fail (iter, FALSE);
- -
- - /* Work our way past the current empty lines */
- - if (_ide_vim_iter_line_is_empty (iter))
- - while (_ide_vim_iter_line_is_empty (iter))
- - if (!gtk_text_iter_forward_line (iter))
- - return FALSE;
- -
- - /* Now find first line that is empty */
- - while (!_ide_vim_iter_line_is_empty (iter))
- - if (!gtk_text_iter_forward_line (iter))
- - return FALSE;
- -
- - return TRUE;
- -}
- -
- -static gboolean
- -sentence_end_chars (gunichar ch,
- - gpointer user_data)
- -{
- - switch (ch)
- - {
- - case '!':
- - case '.':
- - case '?':
- - return TRUE;
- -
- - default:
- - return FALSE;
- - }
- -}
- -
- -static SentenceStatus
- -_ide_vim_iter_backward_sentence_end (GtkTextIter *iter)
- -{
- - GtkTextIter end_bounds;
- - GtkTextIter start_bounds;
- - gboolean found_para;
- -
- - g_return_val_if_fail (iter, FALSE);
- -
- - end_bounds = *iter;
- - start_bounds = *iter;
- - found_para = _ide_vim_iter_backward_paragraph_start (&start_bounds);
- -
- - if (!found_para)
- - gtk_text_buffer_get_start_iter (gtk_text_iter_get_buffer (iter), &start_bounds);
- -
- - while ((gtk_text_iter_compare (iter, &start_bounds) > 0) && gtk_text_iter_backward_char (iter))
- - {
- - if (gtk_text_iter_backward_find_char (iter, sentence_end_chars, NULL, &end_bounds))
- - {
- - GtkTextIter copy = *iter;
- -
- - while (gtk_text_iter_forward_char (©) && (gtk_text_iter_compare (©, &end_bounds) < 0))
- - {
- - gunichar ch;
- -
- - ch = gtk_text_iter_get_char (©);
- -
- - switch (ch)
- - {
- - case ']':
- - case ')':
- - case '"':
- - case '\'':
- - continue;
- -
- - case ' ':
- - case '\n':
- - *iter = copy;
- - return SENTENCE_OK;
- -
- - default:
- - break;
- - }
- - }
- - }
- - }
- -
- - *iter = start_bounds;
- -
- - if (found_para)
- - return SENTENCE_PARA;
- -
- - return SENTENCE_FAILED;
- -}
- -
- -gboolean
- -_ide_vim_iter_forward_sentence_end (GtkTextIter *iter)
- -{
- - GtkTextIter end_bounds;
- - gboolean found_para;
- -
- - g_return_val_if_fail (iter, FALSE);
- -
- - end_bounds = *iter;
- - found_para = _ide_vim_iter_forward_paragraph_end (&end_bounds);
- -
- - if (!found_para)
- - gtk_text_buffer_get_end_iter (gtk_text_iter_get_buffer (iter), &end_bounds);
- -
- - while ((gtk_text_iter_compare (iter, &end_bounds) < 0) && gtk_text_iter_forward_char (iter))
- - {
- - if (gtk_text_iter_forward_find_char (iter, sentence_end_chars, NULL, &end_bounds))
- - {
- - GtkTextIter copy = *iter;
- -
- - while (gtk_text_iter_forward_char (©) && (gtk_text_iter_compare (©, &end_bounds) < 0))
- - {
- - gunichar ch;
- - gboolean invalid = FALSE;
- -
- - ch = gtk_text_iter_get_char (©);
- -
- - switch (ch)
- - {
- - case ']':
- - case ')':
- - case '"':
- - case '\'':
- - continue;
- -
- - case ' ':
- - case '\n':
- - *iter = copy;
- - return SENTENCE_OK;
- -
- - default:
- - invalid = TRUE;
- - break;
- - }
- -
- - if (invalid)
- - break;
- - }
- - }
- - }
- -
- - *iter = end_bounds;
- -
- - if (found_para)
- - return SENTENCE_PARA;
- -
- - return SENTENCE_FAILED;
- -}
- -
- -gboolean
- -_ide_vim_iter_backward_sentence_start (GtkTextIter *iter)
- -{
- - GtkTextIter tmp;
- - SentenceStatus status;
- -
- - g_return_val_if_fail (iter, FALSE);
- -
- - tmp = *iter;
- - status = _ide_vim_iter_backward_sentence_end (&tmp);
- -
- - switch (status)
- - {
- - case SENTENCE_PARA:
- - case SENTENCE_OK:
- - {
- - GtkTextIter copy = tmp;
- -
- - /*
- - * try to work forward to first non-whitespace char.
- - * if we land where we started, discard the walk.
- - */
- - while (g_unichar_isspace (gtk_text_iter_get_char (©)))
- - if (!gtk_text_iter_forward_char (©))
- - break;
- - if (gtk_text_iter_compare (©, iter) < 0)
- - tmp = copy;
- - *iter = tmp;
- -
- - return TRUE;
- - }
- -
- - case SENTENCE_FAILED:
- - default:
- - gtk_text_buffer_get_start_iter (gtk_text_iter_get_buffer (iter), iter);
- - return FALSE;
- - }
- -}
- -
- -static gboolean
- -_ide_vim_iter_forward_classified_start (GtkTextIter *iter,
- - gint (*classify) (gunichar))
- -{
- - gint begin_class;
- - gint cur_class;
- - gunichar ch;
- -
- - g_assert (iter);
- -
- - ch = gtk_text_iter_get_char (iter);
- - begin_class = classify (ch);
- -
- - /* Move to the first non-whitespace character if necessary. */
- - if (begin_class == CLASS_SPACE)
- - {
- - for (;;)
- - {
- - if (!gtk_text_iter_forward_char (iter))
- - return FALSE;
- -
- - ch = gtk_text_iter_get_char (iter);
- - cur_class = classify (ch);
- - if (cur_class != CLASS_SPACE)
- - return TRUE;
- - }
- - }
- -
- - /* move to first character not at same class level. */
- - while (gtk_text_iter_forward_char (iter))
- - {
- - ch = gtk_text_iter_get_char (iter);
- - cur_class = classify (ch);
- -
- - if (cur_class == CLASS_SPACE)
- - {
- - begin_class = CLASS_0;
- - continue;
- - }
- -
- - if (cur_class != begin_class)
- - return TRUE;
- - }
- -
- - return FALSE;
- -}
- -
- -gboolean
- -_ide_vim_iter_forward_word_start (GtkTextIter *iter)
- -{
- - return _ide_vim_iter_forward_classified_start (iter, _ide_vim_word_classify);
- -}
- -
- -gboolean
- -_ide_vim_iter_forward_WORD_start (GtkTextIter *iter)
- -{
- - return _ide_vim_iter_forward_classified_start (iter, _ide_vim_WORD_classify);
- -}
- -
- -gboolean
- -_ide_vim_iter_forward_classified_end (GtkTextIter *iter,
- - gint (*classify) (gunichar))
- -{
- - gunichar ch;
- - gint begin_class;
- - gint cur_class;
- -
- - g_assert (iter);
- -
- - if (!gtk_text_iter_forward_char (iter))
- - return FALSE;
- -
- - /* If we are on space, walk to the start of the next word. */
- - ch = gtk_text_iter_get_char (iter);
- - if (classify (ch) == CLASS_SPACE)
- - if (!_ide_vim_iter_forward_classified_start (iter, classify))
- - return FALSE;
- -
- - ch = gtk_text_iter_get_char (iter);
- - begin_class = classify (ch);
- -
- - for (;;)
- - {
- - if (!gtk_text_iter_forward_char (iter))
- - return FALSE;
- -
- - ch = gtk_text_iter_get_char (iter);
- - cur_class = classify (ch);
- -
- - if (cur_class != begin_class)
- - {
- - gtk_text_iter_backward_char (iter);
- - return TRUE;
- - }
- - }
- -
- - return FALSE;
- -}
- -
- -gboolean
- -_ide_vim_iter_forward_word_end (GtkTextIter *iter)
- -{
- - return _ide_vim_iter_forward_classified_end (iter, _ide_vim_word_classify);
- -}
- -
- -gboolean
- -_ide_vim_iter_forward_WORD_end (GtkTextIter *iter)
- -{
- - return _ide_vim_iter_forward_classified_end (iter, _ide_vim_WORD_classify);
- -}
- -
- -static gboolean
- -_ide_vim_iter_backward_classified_end (GtkTextIter *iter,
- - gint (*classify) (gunichar))
- -{
- - gunichar ch;
- - gint begin_class;
- - gint cur_class;
- -
- - g_assert (iter);
- -
- - ch = gtk_text_iter_get_char (iter);
- - begin_class = classify (ch);
- -
- - for (;;)
- - {
- - if (!gtk_text_iter_backward_char (iter))
- - return FALSE;
- -
- - ch = gtk_text_iter_get_char (iter);
- - cur_class = classify (ch);
- -
- - /* reset begin_class if we hit space, we can take anything after that */
- - if (cur_class == CLASS_SPACE)
- - begin_class = CLASS_SPACE;
- -
- - if (cur_class != begin_class && cur_class != CLASS_SPACE)
- - return TRUE;
- - }
- -
- - return FALSE;
- -}
- -
- -gboolean
- -_ide_vim_iter_backward_word_end (GtkTextIter *iter)
- -{
- - return _ide_vim_iter_backward_classified_end (iter, _ide_vim_word_classify);
- -}
- -
- -gboolean
- -_ide_vim_iter_backward_WORD_end (GtkTextIter *iter)
- -{
- - return _ide_vim_iter_backward_classified_end (iter, _ide_vim_WORD_classify);
- -}
- diff --git a/libide/ide-vim-iter.h b/libide/ide-vim-iter.h
- deleted file mode 100644
- index 3777238..0000000
- --- a/libide/ide-vim-iter.h
- +++ /dev/null
- @@ -1,39 +0,0 @@
- -/* ide-vim-iter.h
- - *
- - * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
- - *
- - * 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 3 of the License, or
- - * (at your option) any later version.
- - *
- - * This program 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 General Public License for more details.
- - *
- - * You should have received a copy of the GNU General Public License
- - * along with this program. If not, see <http://www.gnu.org/licenses/>.
- - */
- -
- -#ifndef IDE_VIM_ITER_H
- -#define IDE_VIM_ITER_H
- -
- -#include <gtk/gtk.h>
- -
- -G_BEGIN_DECLS
- -
- -gboolean _ide_vim_iter_forward_word_start (GtkTextIter *iter);
- -gboolean _ide_vim_iter_forward_WORD_start (GtkTextIter *iter);
- -gboolean _ide_vim_iter_forward_word_end (GtkTextIter *iter);
- -gboolean _ide_vim_iter_forward_WORD_end (GtkTextIter *iter);
- -gboolean _ide_vim_iter_backward_paragraph_start (GtkTextIter *iter);
- -gboolean _ide_vim_iter_forward_paragraph_end (GtkTextIter *iter);
- -gboolean _ide_vim_iter_backward_sentence_start (GtkTextIter *iter);
- -gboolean _ide_vim_iter_forward_sentence_end (GtkTextIter *iter);
- -gboolean _ide_vim_iter_backward_WORD_end (GtkTextIter *iter);
- -gboolean _ide_vim_iter_backward_word_end (GtkTextIter *iter);
- -
- -G_END_DECLS
- -
- -#endif /* IDE_VIM_ITER_H */
- diff --git a/libide/ide.h b/libide/ide.h
- index b5e6a17..127e5d6 100644
- --- a/libide/ide.h
- +++ b/libide/ide.h
- @@ -108,6 +108,13 @@ G_BEGIN_DECLS
- #include "python/ide-python-language.h"
- #include "theatrics/ide-animation.h"
- #include "vala/ide-vala-language.h"
- +#include "vim/ide-vim-parser.h"
- +#include "vim/ide-vim-parser-debug.h"
- +#include "vim/ide-vim-parser-error.h"
- +#include "vim/ide-vim-parser-token.h"
- +#include "vim/ide-vim-parser-command.h"
- +#include "vim/ide-vim-parser-objects-pool.h"
- +#include "vim/ide-vim-parser-settable.h"
- #include "xml/ide-xml-language.h"
- #undef IDE_INSIDE
- diff --git a/libide/vim/ide-vim-complete-item.c b/libide/vim/ide-vim-complete-item.c
- new file mode 100644
- index 0000000..f0dde0e
- --- /dev/null
- +++ b/libide/vim/ide-vim-complete-item.c
- @@ -0,0 +1,261 @@
- +/* ide-vim-complete-item.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +#include <string.h>
- +#include <errno.h>
- +#include <glib/gi18n.h>
- +#include <glib/gprintf.h>
- +
- +#include "ide-debug.h"
- +#include "ide-macros.h"
- +
- +#include <glib/gi18n.h>
- +
- +#include "ide-vim-complete-item.h"
- +
- +typedef struct
- +{
- + IdeVimCompleteItemKind kind;
- + gchar *name;
- + gchar *shortname;
- +} IdeVimCompleteItemPrivate;
- +
- +G_DEFINE_TYPE_WITH_PRIVATE (IdeVimCompleteItem, ide_vim_complete_item, G_TYPE_OBJECT)
- +
- +enum {
- + PROP_0,
- + PROP_KIND,
- + PROP_NAME,
- + PROP_SHORTNAME,
- + LAST_PROP
- +};
- +
- +static GParamSpec *gParamSpecs [LAST_PROP];
- +
- +/**
- + * ide_vim_complete_item_get_kind:
- + * @self: (in): #IdeClangCompletionItem instance.
- + *
- + * Get the item's kind.
- + *
- + * Returns: the item's kind.
- + */
- +IdeVimCompleteItemKind
- +ide_vim_complete_item_get_kind (IdeVimCompleteItem *self)
- +{
- + IdeVimCompleteItemPrivate *priv = ide_vim_complete_item_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_COMPLETE_ITEM (self), IDE_VIM_COMPLETE_ITEM_KIND_NONE);
- +
- + return priv->kind;
- +}
- +
- +/**
- + * ide_vim_complete_item_get_name:
- + * @self: (in): #IdeClangCompletionItem instance.
- + *
- + * Return the item's name.
- + *
- + * Returns: the item's name.
- + */
- +const gchar *
- +ide_vim_complete_item_get_name (IdeVimCompleteItem *self)
- +{
- + IdeVimCompleteItemPrivate *priv = ide_vim_complete_item_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_COMPLETE_ITEM (self), NULL);
- +
- + return priv->name;
- +}
- +
- +/**
- + * ide_vim_complete_item_get_shortname:
- + * @self: (in): #IdeClangCompletionItem instance.
- + *
- + * Return the item's shortname.
- + *
- + * Returns: the item's shortname.
- + */
- +const gchar *
- +ide_vim_complete_item_get_shortname (IdeVimCompleteItem *self)
- +{
- + IdeVimCompleteItemPrivate *priv = ide_vim_complete_item_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_COMPLETE_ITEM (self), NULL);
- +
- + return priv->shortname;
- +}
- +
- +IdeVimCompleteItem *
- +ide_vim_complete_item_new (IdeVimCompleteItemKind kind,
- + gchar *name,
- + gchar *shortname)
- +{
- + return g_object_new (IDE_TYPE_VIM_COMPLETE_ITEM,
- + "kind", kind,
- + "name", name,
- + "shortname", shortname,
- + NULL);
- +}
- +
- +static void
- +ide_vim_complete_item_finalize (GObject *object)
- +{
- + IdeVimCompleteItem *self = (IdeVimCompleteItem *)object;
- + IdeVimCompleteItemPrivate *priv = ide_vim_complete_item_get_instance_private (self);
- +
- + g_clear_pointer (&priv->name, g_free);
- + g_clear_pointer (&priv->shortname, g_free);
- +
- + G_OBJECT_CLASS (ide_vim_complete_item_parent_class)->finalize (object);
- +}
- +
- +static void
- +ide_vim_complete_item_get_property (GObject *object,
- + guint prop_id,
- + GValue *value,
- + GParamSpec *pspec)
- +{
- + IdeVimCompleteItem *self = IDE_VIM_COMPLETE_ITEM (object);
- +
- + switch (prop_id)
- + {
- + case PROP_KIND:
- + g_value_set_enum (value, ide_vim_complete_item_get_kind (self));
- + break;
- +
- + case PROP_NAME:
- + g_value_set_string (value, ide_vim_complete_item_get_name (self));
- + break;
- +
- + case PROP_SHORTNAME:
- + g_value_set_string (value, ide_vim_complete_item_get_shortname (self));
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_complete_item_set_property (GObject *object,
- + guint prop_id,
- + const GValue *value,
- + GParamSpec *pspec)
- +{
- + IdeVimCompleteItem *self = IDE_VIM_COMPLETE_ITEM (object);
- + IdeVimCompleteItemPrivate *priv = ide_vim_complete_item_get_instance_private (self);
- +
- + switch (prop_id)
- + {
- + case PROP_KIND:
- + priv->kind = g_value_get_enum (value);
- + break;
- +
- + case PROP_NAME:
- + priv->name = g_value_dup_string (value);
- + break;
- +
- + case PROP_SHORTNAME:
- + priv->shortname = g_value_dup_string (value);
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_complete_item_init (IdeVimCompleteItem *self)
- +{
- +}
- +
- +/**
- + * ide_vim_complete_item_kind_get_type:
- + *
- + * Retrieves the GType for #IdeVimCompleteItemKind.
- + *
- + * Returns: A GType.
- + * Side effects: GType registered on first call.
- + */
- +GType
- +ide_vim_complete_item_kind_get_type (void)
- +{
- + static GType type_id = 0;
- + static const GEnumValue values[] = {
- + { IDE_VIM_COMPLETE_ITEM_KIND_NONE, "IDE_VIM_COMPLETE_ITEM_KIND_NONE", "NONE" },
- + { IDE_VIM_COMPLETE_ITEM_KIND_SET, "IDE_VIM_COMPLETE_ITEM_KIND_SET", "SET" },
- + { IDE_VIM_COMPLETE_ITEM_KIND_COLORSCHEME, "IDE_VIM_COMPLETE_ITEM_KIND_COLORSCHEME", "COLORSCHEME" },
- + { IDE_VIM_COMPLETE_ITEM_KIND_COMMAND, "IDE_VIM_COMPLETE_ITEM_KIND_COMMAND", "COMMAND" },
- + { IDE_VIM_COMPLETE_ITEM_KIND_PATH, "IDE_VIM_COMPLETE_ITEM_KIND_PATH", "PATH" },
- + { 0 }
- + };
- +
- + if (G_UNLIKELY (!type_id))
- + type_id = g_enum_register_static ("IdeVimCompleteItemKind", values);
- +
- + return type_id;
- +}
- +
- +static void
- +ide_vim_complete_item_class_init (IdeVimCompleteItemClass *klass)
- +{
- + GObjectClass *object_class = G_OBJECT_CLASS (klass);
- +
- + object_class->finalize = ide_vim_complete_item_finalize;
- + object_class->get_property = ide_vim_complete_item_get_property;
- + object_class->set_property = ide_vim_complete_item_set_property;
- +
- +/**
- + * IdeVimCompleteItem:kind:
- + *
- + * The kind of content the Complete item represent.
- + */
- + gParamSpecs[PROP_KIND] =
- + g_param_spec_enum ("kind",
- + _("Item kind"),
- + _("The kind of the Item"),
- + IDE_TYPE_VIM_COMPLETE_ITEM_KIND,
- + IDE_VIM_COMPLETE_ITEM_KIND_NONE,
- + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
- +
- + /**
- + * IdeVimCompleteItem:name:
- + *
- + * A string holding the name of the item.
- + */
- + gParamSpecs[PROP_NAME] =
- + g_param_spec_string ("name",
- + _("item name"),
- + _("The name of the item."),
- + NULL,
- + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimCompleteItem:shortname:
- + *
- + * A string holding the shortname of the item.
- + */
- + gParamSpecs[PROP_SHORTNAME] =
- + g_param_spec_string ("shortname",
- + _("item shortname"),
- + _("The shortname of the item."),
- + NULL,
- + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- +
- + g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
- +}
- diff --git a/libide/vim/ide-vim-complete-item.h b/libide/vim/ide-vim-complete-item.h
- new file mode 100644
- index 0000000..160653d
- --- /dev/null
- +++ b/libide/vim/ide-vim-complete-item.h
- @@ -0,0 +1,58 @@
- +/* ide-vim-complete-item.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_COMPLETE_ITEM_H
- +#define IDE_VIM_COMPLETE_ITEM_H
- +
- +#include <glib.h>
- +
- +G_BEGIN_DECLS
- +
- +#define IDE_TYPE_VIM_COMPLETE_ITEM (ide_vim_complete_item_get_type())
- +#define IDE_TYPE_VIM_COMPLETE_ITEM_KIND (ide_vim_complete_item_kind_get_type())
- +
- +G_DECLARE_FINAL_TYPE (IdeVimCompleteItem , ide_vim_complete_item, IDE, VIM_COMPLETE_ITEM, GObject)
- +
- +struct _IdeVimCompleteItem
- +{
- + GObject parent;
- +};
- +
- +typedef enum _IdeVimCompleteItemKind IdeVimCompleteItemKind;
- +
- +enum _IdeVimCompleteItemKind
- +{
- + IDE_VIM_COMPLETE_ITEM_KIND_NONE,
- + IDE_VIM_COMPLETE_ITEM_KIND_SET,
- + IDE_VIM_COMPLETE_ITEM_KIND_COLORSCHEME,
- + IDE_VIM_COMPLETE_ITEM_KIND_COMMAND,
- + IDE_VIM_COMPLETE_ITEM_KIND_PATH,
- +
- + IDE_VIM_COMPLETE_ITEM_KIND_LAST
- +};
- +
- +IdeVimCompleteItem *ide_vim_complete_item_new (IdeVimCompleteItemKind kind,
- + gchar *name,
- + gchar *shortname);
- +IdeVimCompleteItemKind ide_vim_complete_item_get_kind (IdeVimCompleteItem *self);
- +const gchar *ide_vim_complete_item_get_name (IdeVimCompleteItem *self);
- +const gchar *ide_vim_complete_item_get_shortname (IdeVimCompleteItem *self);
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_COMPLETE_ITEM_H */
- diff --git a/libide/vim/ide-vim-iter.c b/libide/vim/ide-vim-iter.c
- new file mode 100644
- index 0000000..d03b829
- --- /dev/null
- +++ b/libide/vim/ide-vim-iter.c
- @@ -0,0 +1,457 @@
- +/* ide-vim-iter.c
- + *
- + * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <gtk/gtk.h>
- +
- +#include "ide-debug.h"
- +#include "ide-vim-iter.h"
- +
- +typedef enum
- +{
- + SENTENCE_OK,
- + SENTENCE_PARA,
- + SENTENCE_FAILED,
- +} SentenceStatus;
- +
- +enum
- +{
- + CLASS_0,
- + CLASS_SPACE,
- + CLASS_SPECIAL,
- + CLASS_WORD,
- +};
- +
- +static int
- +_ide_vim_word_classify (gunichar ch)
- +{
- + switch (ch)
- + {
- + case ' ':
- + case '\t':
- + case '\n':
- + return CLASS_SPACE;
- +
- + case '"': case '\'':
- + case '(': case ')':
- + case '{': case '}':
- + case '[': case ']':
- + case '<': case '>':
- + case '-': case '+': case '*': case '/':
- + case '!': case '@': case '#': case '$': case '%':
- + case '^': case '&': case ':': case ';': case '?':
- + case '|': case '=': case '\\': case '.': case ',':
- + return CLASS_SPECIAL;
- +
- + case '_':
- + default:
- + return CLASS_WORD;
- + }
- +}
- +
- +static int
- +_ide_vim_WORD_classify (gunichar ch)
- +{
- + if (g_unichar_isspace (ch))
- + return CLASS_SPACE;
- + return CLASS_WORD;
- +}
- +
- +static gboolean
- +_ide_vim_iter_line_is_empty (GtkTextIter *iter)
- +{
- + return gtk_text_iter_starts_line (iter) && gtk_text_iter_ends_line (iter);
- +}
- +
- +/**
- + * _ide_vim_iter_backward_paragraph_start:
- + * @iter: A #GtkTextIter
- + *
- + * Searches backwards until we find the beginning of a paragraph.
- + *
- + * Returns: %TRUE if we are not at the beginning of the buffer; otherwise %FALSE.
- + */
- +gboolean
- +_ide_vim_iter_backward_paragraph_start (GtkTextIter *iter)
- +{
- + g_return_val_if_fail (iter, FALSE);
- +
- + /* Work our way past the current empty lines */
- + if (_ide_vim_iter_line_is_empty (iter))
- + while (_ide_vim_iter_line_is_empty (iter))
- + if (!gtk_text_iter_backward_line (iter))
- + return FALSE;
- +
- + /* Now find first line that is empty */
- + while (!_ide_vim_iter_line_is_empty (iter))
- + if (!gtk_text_iter_backward_line (iter))
- + return FALSE;
- +
- + return TRUE;
- +}
- +
- +/**
- + * _ide_vim_iter_forward_paragraph_end:
- + * @iter: A #GtkTextIter
- + *
- + * Searches forward until the end of a paragraph has been hit.
- + *
- + * Returns: %TRUE if we are not at the end of the buffer; otherwise %FALSE.
- + */
- +gboolean
- +_ide_vim_iter_forward_paragraph_end (GtkTextIter *iter)
- +{
- + g_return_val_if_fail (iter, FALSE);
- +
- + /* Work our way past the current empty lines */
- + if (_ide_vim_iter_line_is_empty (iter))
- + while (_ide_vim_iter_line_is_empty (iter))
- + if (!gtk_text_iter_forward_line (iter))
- + return FALSE;
- +
- + /* Now find first line that is empty */
- + while (!_ide_vim_iter_line_is_empty (iter))
- + if (!gtk_text_iter_forward_line (iter))
- + return FALSE;
- +
- + return TRUE;
- +}
- +
- +static gboolean
- +sentence_end_chars (gunichar ch,
- + gpointer user_data)
- +{
- + switch (ch)
- + {
- + case '!':
- + case '.':
- + case '?':
- + return TRUE;
- +
- + default:
- + return FALSE;
- + }
- +}
- +
- +static SentenceStatus
- +_ide_vim_iter_backward_sentence_end (GtkTextIter *iter)
- +{
- + GtkTextIter end_bounds;
- + GtkTextIter start_bounds;
- + gboolean found_para;
- +
- + g_return_val_if_fail (iter, FALSE);
- +
- + end_bounds = *iter;
- + start_bounds = *iter;
- + found_para = _ide_vim_iter_backward_paragraph_start (&start_bounds);
- +
- + if (!found_para)
- + gtk_text_buffer_get_start_iter (gtk_text_iter_get_buffer (iter), &start_bounds);
- +
- + while ((gtk_text_iter_compare (iter, &start_bounds) > 0) && gtk_text_iter_backward_char (iter))
- + {
- + if (gtk_text_iter_backward_find_char (iter, sentence_end_chars, NULL, &end_bounds))
- + {
- + GtkTextIter copy = *iter;
- +
- + while (gtk_text_iter_forward_char (©) && (gtk_text_iter_compare (©, &end_bounds) < 0))
- + {
- + gunichar ch;
- +
- + ch = gtk_text_iter_get_char (©);
- +
- + switch (ch)
- + {
- + case ']':
- + case ')':
- + case '"':
- + case '\'':
- + continue;
- +
- + case ' ':
- + case '\n':
- + *iter = copy;
- + return SENTENCE_OK;
- +
- + default:
- + break;
- + }
- + }
- + }
- + }
- +
- + *iter = start_bounds;
- +
- + if (found_para)
- + return SENTENCE_PARA;
- +
- + return SENTENCE_FAILED;
- +}
- +
- +gboolean
- +_ide_vim_iter_forward_sentence_end (GtkTextIter *iter)
- +{
- + GtkTextIter end_bounds;
- + gboolean found_para;
- +
- + g_return_val_if_fail (iter, FALSE);
- +
- + end_bounds = *iter;
- + found_para = _ide_vim_iter_forward_paragraph_end (&end_bounds);
- +
- + if (!found_para)
- + gtk_text_buffer_get_end_iter (gtk_text_iter_get_buffer (iter), &end_bounds);
- +
- + while ((gtk_text_iter_compare (iter, &end_bounds) < 0) && gtk_text_iter_forward_char (iter))
- + {
- + if (gtk_text_iter_forward_find_char (iter, sentence_end_chars, NULL, &end_bounds))
- + {
- + GtkTextIter copy = *iter;
- +
- + while (gtk_text_iter_forward_char (©) && (gtk_text_iter_compare (©, &end_bounds) < 0))
- + {
- + gunichar ch;
- + gboolean invalid = FALSE;
- +
- + ch = gtk_text_iter_get_char (©);
- +
- + switch (ch)
- + {
- + case ']':
- + case ')':
- + case '"':
- + case '\'':
- + continue;
- +
- + case ' ':
- + case '\n':
- + *iter = copy;
- + return SENTENCE_OK;
- +
- + default:
- + invalid = TRUE;
- + break;
- + }
- +
- + if (invalid)
- + break;
- + }
- + }
- + }
- +
- + *iter = end_bounds;
- +
- + if (found_para)
- + return SENTENCE_PARA;
- +
- + return SENTENCE_FAILED;
- +}
- +
- +gboolean
- +_ide_vim_iter_backward_sentence_start (GtkTextIter *iter)
- +{
- + GtkTextIter tmp;
- + SentenceStatus status;
- +
- + g_return_val_if_fail (iter, FALSE);
- +
- + tmp = *iter;
- + status = _ide_vim_iter_backward_sentence_end (&tmp);
- +
- + switch (status)
- + {
- + case SENTENCE_PARA:
- + case SENTENCE_OK:
- + {
- + GtkTextIter copy = tmp;
- +
- + /*
- + * try to work forward to first non-whitespace char.
- + * if we land where we started, discard the walk.
- + */
- + while (g_unichar_isspace (gtk_text_iter_get_char (©)))
- + if (!gtk_text_iter_forward_char (©))
- + break;
- + if (gtk_text_iter_compare (©, iter) < 0)
- + tmp = copy;
- + *iter = tmp;
- +
- + return TRUE;
- + }
- +
- + case SENTENCE_FAILED:
- + default:
- + gtk_text_buffer_get_start_iter (gtk_text_iter_get_buffer (iter), iter);
- + return FALSE;
- + }
- +}
- +
- +static gboolean
- +_ide_vim_iter_forward_classified_start (GtkTextIter *iter,
- + gint (*classify) (gunichar))
- +{
- + gint begin_class;
- + gint cur_class;
- + gunichar ch;
- +
- + g_assert (iter);
- +
- + ch = gtk_text_iter_get_char (iter);
- + begin_class = classify (ch);
- +
- + /* Move to the first non-whitespace character if necessary. */
- + if (begin_class == CLASS_SPACE)
- + {
- + for (;;)
- + {
- + if (!gtk_text_iter_forward_char (iter))
- + return FALSE;
- +
- + ch = gtk_text_iter_get_char (iter);
- + cur_class = classify (ch);
- + if (cur_class != CLASS_SPACE)
- + return TRUE;
- + }
- + }
- +
- + /* move to first character not at same class level. */
- + while (gtk_text_iter_forward_char (iter))
- + {
- + ch = gtk_text_iter_get_char (iter);
- + cur_class = classify (ch);
- +
- + if (cur_class == CLASS_SPACE)
- + {
- + begin_class = CLASS_0;
- + continue;
- + }
- +
- + if (cur_class != begin_class)
- + return TRUE;
- + }
- +
- + return FALSE;
- +}
- +
- +gboolean
- +_ide_vim_iter_forward_word_start (GtkTextIter *iter)
- +{
- + return _ide_vim_iter_forward_classified_start (iter, _ide_vim_word_classify);
- +}
- +
- +gboolean
- +_ide_vim_iter_forward_WORD_start (GtkTextIter *iter)
- +{
- + return _ide_vim_iter_forward_classified_start (iter, _ide_vim_WORD_classify);
- +}
- +
- +gboolean
- +_ide_vim_iter_forward_classified_end (GtkTextIter *iter,
- + gint (*classify) (gunichar))
- +{
- + gunichar ch;
- + gint begin_class;
- + gint cur_class;
- +
- + g_assert (iter);
- +
- + if (!gtk_text_iter_forward_char (iter))
- + return FALSE;
- +
- + /* If we are on space, walk to the start of the next word. */
- + ch = gtk_text_iter_get_char (iter);
- + if (classify (ch) == CLASS_SPACE)
- + if (!_ide_vim_iter_forward_classified_start (iter, classify))
- + return FALSE;
- +
- + ch = gtk_text_iter_get_char (iter);
- + begin_class = classify (ch);
- +
- + for (;;)
- + {
- + if (!gtk_text_iter_forward_char (iter))
- + return FALSE;
- +
- + ch = gtk_text_iter_get_char (iter);
- + cur_class = classify (ch);
- +
- + if (cur_class != begin_class)
- + {
- + gtk_text_iter_backward_char (iter);
- + return TRUE;
- + }
- + }
- +
- + return FALSE;
- +}
- +
- +gboolean
- +_ide_vim_iter_forward_word_end (GtkTextIter *iter)
- +{
- + return _ide_vim_iter_forward_classified_end (iter, _ide_vim_word_classify);
- +}
- +
- +gboolean
- +_ide_vim_iter_forward_WORD_end (GtkTextIter *iter)
- +{
- + return _ide_vim_iter_forward_classified_end (iter, _ide_vim_WORD_classify);
- +}
- +
- +static gboolean
- +_ide_vim_iter_backward_classified_end (GtkTextIter *iter,
- + gint (*classify) (gunichar))
- +{
- + gunichar ch;
- + gint begin_class;
- + gint cur_class;
- +
- + g_assert (iter);
- +
- + ch = gtk_text_iter_get_char (iter);
- + begin_class = classify (ch);
- +
- + for (;;)
- + {
- + if (!gtk_text_iter_backward_char (iter))
- + return FALSE;
- +
- + ch = gtk_text_iter_get_char (iter);
- + cur_class = classify (ch);
- +
- + /* reset begin_class if we hit space, we can take anything after that */
- + if (cur_class == CLASS_SPACE)
- + begin_class = CLASS_SPACE;
- +
- + if (cur_class != begin_class && cur_class != CLASS_SPACE)
- + return TRUE;
- + }
- +
- + return FALSE;
- +}
- +
- +gboolean
- +_ide_vim_iter_backward_word_end (GtkTextIter *iter)
- +{
- + return _ide_vim_iter_backward_classified_end (iter, _ide_vim_word_classify);
- +}
- +
- +gboolean
- +_ide_vim_iter_backward_WORD_end (GtkTextIter *iter)
- +{
- + return _ide_vim_iter_backward_classified_end (iter, _ide_vim_WORD_classify);
- +}
- diff --git a/libide/vim/ide-vim-iter.h b/libide/vim/ide-vim-iter.h
- new file mode 100644
- index 0000000..3777238
- --- /dev/null
- +++ b/libide/vim/ide-vim-iter.h
- @@ -0,0 +1,39 @@
- +/* ide-vim-iter.h
- + *
- + * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_ITER_H
- +#define IDE_VIM_ITER_H
- +
- +#include <gtk/gtk.h>
- +
- +G_BEGIN_DECLS
- +
- +gboolean _ide_vim_iter_forward_word_start (GtkTextIter *iter);
- +gboolean _ide_vim_iter_forward_WORD_start (GtkTextIter *iter);
- +gboolean _ide_vim_iter_forward_word_end (GtkTextIter *iter);
- +gboolean _ide_vim_iter_forward_WORD_end (GtkTextIter *iter);
- +gboolean _ide_vim_iter_backward_paragraph_start (GtkTextIter *iter);
- +gboolean _ide_vim_iter_forward_paragraph_end (GtkTextIter *iter);
- +gboolean _ide_vim_iter_backward_sentence_start (GtkTextIter *iter);
- +gboolean _ide_vim_iter_forward_sentence_end (GtkTextIter *iter);
- +gboolean _ide_vim_iter_backward_WORD_end (GtkTextIter *iter);
- +gboolean _ide_vim_iter_backward_word_end (GtkTextIter *iter);
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_ITER_H */
- diff --git a/libide/vim/ide-vim-parser-command.c b/libide/vim/ide-vim-parser-command.c
- new file mode 100644
- index 0000000..0ce86d4
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-command.c
- @@ -0,0 +1,633 @@
- +/* ide-vim-parser-command.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <string.h>
- +
- +#include <glib/gprintf.h>
- +#include <glib/gi18n.h>
- +
- +#include "ide-debug.h"
- +#include "ide-macros.h"
- +
- +#include "ide-vim-parser-command.h"
- +
- +typedef struct
- +{
- + gchar *name;
- + gchar *shortname;
- + IdeVimParserCommandFunc func;
- + guint id;
- + GPtrArray *args;
- + gboolean has_bang : 1;
- +} IdeVimParserCommandPrivate;
- +
- +G_DEFINE_TYPE_WITH_PRIVATE (IdeVimParserCommand, ide_vim_parser_command, G_TYPE_OBJECT)
- +
- +enum {
- + PROP_0,
- + PROP_ARGS,
- + PROP_NAME,
- + PROP_SHORTNAME,
- + PROP_ID,
- + PROP_FUNC,
- + PROP_SYNTAX,
- + LAST_PROP
- +};
- +
- +static GParamSpec *gParamSpecs [LAST_PROP];
- +
- +/**
- + * ide_vim_parser_command_has_bang:
- + * @self: (in): a #IdeVimParserCommand instance.
- + *
- + * Return TRUE if the parsed command is ended by a bang, FALSE otherwise.
- + *
- + * Returns: TRUE if the parsed command is ended by a bang, FALSE otherwise.
- + */
- +gboolean
- +ide_vim_parser_command_has_bang (IdeVimParserCommand *self)
- +{
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (self), FALSE);
- +
- + return priv->has_bang;
- +}
- +
- +static IdeVimParserToken *
- +get_token_from_command (IdeVimParserCommand *self,
- + gint position,
- + IdeVimParserTokenKind kind)
- +{
- + const GPtrArray *args;
- + IdeVimParserToken *token;
- +
- + args = ide_vim_parser_command_get_args (self);
- + if (position >= args->len)
- + {
- + g_critical (_("The arguments position %i is outside of arguments array bounds\n"), position);
- + return FALSE;
- + }
- +
- + token = g_ptr_array_index (args, position);
- + if (token->kind != kind)
- + {
- + g_critical (_("The argument at position %i is not a string\n"), position);
- + return FALSE;
- + }
- +
- + return token;
- +}
- +
- +/**
- + * ide_vim_parser_command_get_string_arg:
- + * @self: (in): a #IdeVimParserCommand instance.
- + * @position: (in): the argument position, starting from 0.
- + * @string: (out) (transfer none): an adress of a pointer to a gchar variable.
- + *
- + * Get the location of the string contained in an argument of kind string.
- + * If the argument is not set then FALSE is returned.
- + *
- + * Returns: TRUE on succes, FALSE otherwise.
- + */
- +gboolean
- +ide_vim_parser_command_get_string_arg (IdeVimParserCommand *self,
- + guint position,
- + const gchar **string)
- +{
- + IdeVimParserToken *token;
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (self), FALSE);
- + g_return_val_if_fail (string != NULL, FALSE);
- +
- +
- + token = get_token_from_command (self, position, IDE_VIM_PARSER_TOKEN_STRING);
- + *string = token->content;
- +
- + return token->is_set;
- +}
- +
- +/**
- + * ide_vim_parser_command_get_number_arg:
- + * @self: (in): a #IdeVimParserCommand instance.
- + * @position: (in): the argument position, starting from 0.
- + * @number: (out): an adress of a gint variable.
- + *
- + * Get the value of an argument of kind number.
- + * If the argument is not set then FALSE is returned.
- + *
- + * Returns: TRUE on succes, FALSE otherwise.
- + */
- +gboolean
- +ide_vim_parser_command_get_number_arg (IdeVimParserCommand *self,
- + guint position,
- + gint *number)
- +{
- + IdeVimParserToken *token;
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (self), FALSE);
- + g_return_val_if_fail (number != NULL, FALSE);
- +
- + token = get_token_from_command (self, position, IDE_VIM_PARSER_TOKEN_NUMBER);
- + *number = token->number;
- +
- + return token->is_set;
- +}
- +
- +/**
- + * ide_vim_parser_command_get_func:
- + * @self: (in): a #IdeVimParserCommand instance.
- + *
- + * Get a #IdeVimParserCommandFunc pointer to the command function.
- + *
- + * Returns: (skip): a #IdeVimParserCommandFunc pointer.
- + */
- +IdeVimParserCommandFunc
- +ide_vim_parser_command_get_func (IdeVimParserCommand *self)
- +{
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (self), NULL);
- +
- + return priv->func;
- +}
- +
- +/**
- + * ide_vim_parser_command_get_name:
- + * @self: (in): a #IdeVimParserCommand instance.
- + *
- + * Get the command name.
- + *
- + * Returns: (transfer none): a string holding the command name.
- + */
- +const gchar *
- +ide_vim_parser_command_get_name (IdeVimParserCommand *self)
- +{
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (self), NULL);
- +
- + return priv->name;
- +}
- +
- +/**
- + * ide_vim_parser_command_get_shortname:
- + * @self: (in): a #IdeVimParserCommand instance.
- + *
- + * Get the command shortname.
- + *
- + * Returns: (transfer none) (nullable): a string holding the command shortname.
- + */
- +const gchar *
- +ide_vim_parser_command_get_shortname (IdeVimParserCommand *self)
- +{
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (self), NULL);
- +
- + return priv->shortname;
- +}
- +
- +/**
- + * ide_vim_parser_command_set_shortname:
- + * @self: (in): a #IdeVimParserCommand instance.
- + * @shortname: (in): the command shortname.
- + *
- + * Set the command shortname. The shortname should be a prefix of the name,
- + * at least one char and shorter than the complete name.
- + */
- +static void
- +ide_vim_parser_command_set_shortname (IdeVimParserCommand *self,
- + const gchar *shortname)
- +{
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- + guint shortname_len;
- +
- + g_return_if_fail (IDE_IS_VIM_PARSER_COMMAND (self));
- +
- + if (ide_str_empty0 (shortname))
- + {
- + priv->shortname = NULL;
- + return;
- + }
- + shortname_len = strlen (shortname);
- +
- + if (shortname_len > 0 && shortname_len < strlen (priv->name) && g_str_has_prefix (priv->name, shortname))
- + priv->shortname = g_strdup (shortname);
- + else
- + g_warning ("The shortname must be a prefix of the name and its length between 1 and name length - 1");
- +}
- +
- +/**
- + * ide_vim_parser_command_get_syntax:
- + * @self: (in): a #IdeVimParserCommand instance.
- + *
- + * Get the command syntax.
- + *
- + * Returns: (transfer none): a string holding the command syntax.
- + */
- +const gchar *
- +ide_vim_parser_command_get_syntax (IdeVimParserCommand *self)
- +{
- + gchar *str = NULL;
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (self), NULL);
- +
- + /* TODO: not yet implemented */
- +
- + return str;
- +}
- +
- +/**
- + * ide_vim_parser_command_get_id:
- + * @self: (in): a #IdeVimParserCommand instance.
- + *
- + * Get the command id.
- + *
- + * Returns: a guint holding the command id.
- + */
- +guint
- +ide_vim_parser_command_get_id (IdeVimParserCommand *self)
- +{
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (self), 0);
- +
- + return priv->id;
- +}
- +
- +/**
- + * ide_vim_parser_command_get_args:
- + * @self: (in): a #IdeVimParserCommand instance.
- + *
- + * Get a pointer to a #GPtrArray holding the #IdeVimParserToken command arguments.
- + *
- + * Returns: (transfer none) (element-type IdeVimParserToken): a #GPtrArray pointer
- + */
- +const GPtrArray *
- +ide_vim_parser_command_get_args (IdeVimParserCommand *self)
- +{
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (self), NULL);
- +
- + return priv->args;
- +}
- +
- +/**
- + * ide_vim_parser_command_add_arg:
- + * @self: (in): a #IdeVimParserCommand instance.
- + * @kind: (in): a #IdeVimParserTokenKind kind.
- + * @flag: (in): one or more (ored) #IdeVimParserTokenFlag flags.
- + *
- + * Add an argument to the #IdeVimParserCommand command.
- + */
- +void
- +ide_vim_parser_command_add_arg (IdeVimParserCommand *self,
- + IdeVimParserTokenKind kind,
- + IdeVimParserTokenFlag flag)
- +{
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- + IdeVimParserToken *token;
- +
- + g_assert (IDE_IS_VIM_PARSER_COMMAND (self));
- +
- + token = ide_vim_parser_token_new ();
- + token->kind = kind;
- + token->flag = flag;
- +
- + g_ptr_array_add (priv->args, token);
- +}
- +
- +static void
- +ide_vim_parser_command_add_arg_full (IdeVimParserCommand *self,
- + IdeVimParserToken *token)
- +{
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- +
- + g_assert (IDE_IS_VIM_PARSER_COMMAND (self));
- +
- + token->is_set = TRUE;
- + g_ptr_array_add (priv->args, token);
- +}
- +
- +/**
- + * ide_vim_parser_command_parsed_new:
- + * @self: (in): a #IdeVimParserCommand instance.
- + * @args: (element-type IdeVimParserToken): a #GList of parsed #IdeVimParserToken.
- + * @error: an adress of a #IdeVimParserError error pointer.
- + *
- + * Inject a #IdeVimParserToken list into a copy of
- + * a #IdeVimParserCommand. The list and the command args
- + * must match and only differ by optional arguments.
- + *
- + * Returns: (transfer full): A parsed #IdeVimParserCommand.
- + */
- +IdeVimParserCommand *
- +ide_vim_parser_command_parsed_new (IdeVimParserCommand *self,
- + GList *args,
- + IdeVimParserError **error)
- +{
- + IdeVimParserCommand *new_command;
- + IdeVimParserCommandPrivate *new_command_priv;
- + IdeVimParserToken *src_token;
- + IdeVimParserToken *dst_token;
- + const GPtrArray *src_args;
- + gboolean is_matching;
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (self), NULL);
- + g_return_val_if_fail (args != NULL, NULL);
- +
- + /* src_args is a list of registered arguments for the given command,
- + * dst_args is a list of parsed arguments.
- + * Both must match according to the kinds and flags.
- + */
- + new_command = ide_vim_parser_command_new (ide_vim_parser_command_get_name (self),
- + ide_vim_parser_command_get_shortname (self),
- + ide_vim_parser_command_get_func (self));
- +
- + new_command_priv = ide_vim_parser_command_get_instance_private (new_command);
- + src_args = ide_vim_parser_command_get_args (self);
- + g_return_val_if_fail (src_args->len > 0, NULL);
- +
- + for (gint i = 0; i < src_args->len; i++)
- + {
- + src_token = g_ptr_array_index (src_args, i);
- + if (args == NULL)
- + {
- + if (src_token->flag == IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL)
- + {
- + ide_vim_parser_command_add_arg (new_command, src_token->kind, src_token->flag);
- + continue;
- + }
- + else
- + {
- + ide_vim_parser_error_literal_set (error, IDE_VIM_PARSER_ERROR_MISMATCH_LESS_ARGS,
- + _("The %s command syntax need at least one more argument of kind %s\n"),
- + ide_vim_parser_command_get_name (self),
- + ide_vim_parser_token_get_kind_name (src_token));
- + return NULL;
- + }
- + }
- +
- + dst_token = args->data;
- + is_matching = (src_token->kind == dst_token->kind ||
- + (src_token->kind == IDE_VIM_PARSER_TOKEN_NUMBER && dst_token->kind == IDE_VIM_PARSER_TOKEN_RANGE));
- +
- + if (is_matching )
- + {
- + if (src_token->kind == IDE_VIM_PARSER_TOKEN_COMMAND_NAME)
- + new_command_priv->has_bang = dst_token->command_has_bang;
- +
- + dst_token->flag = src_token->flag;
- + ide_vim_parser_command_add_arg_full (new_command, dst_token);
- + args = args->next;
- + }
- + else if (src_token->flag == IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL)
- + {
- + ide_vim_parser_command_add_arg (new_command, src_token->kind, src_token->flag);
- + }
- + else
- + {
- + ide_vim_parser_error_literal_set (error, IDE_VIM_PARSER_ERROR_MISMATCH_KIND,
- + _("%s should be of kind %s (%s found)\n"),
- + ide_vim_parser_token_get_content (dst_token),
- + ide_vim_parser_token_get_kind_name (dst_token),
- + ide_vim_parser_token_get_kind_name (src_token));
- + return NULL;
- + }
- + }
- +
- + if (args != NULL)
- + {
- + dst_token = args->data;
- + ide_vim_parser_error_literal_set (error, IDE_VIM_PARSER_ERROR_MISMATCH_MORE_ARGS,
- + _("You provide too much arguments for the %s command syntax, starting with:%s\n"),
- + ide_vim_parser_command_get_name (self),
- + ide_vim_parser_token_get_content (dst_token));
- + return NULL;
- + }
- +
- + return new_command;
- +}
- +
- +static void
- +ide_vim_parser_command_get_property (GObject *object,
- + guint prop_id,
- + GValue *value,
- + GParamSpec *pspec)
- +{
- + IdeVimParserCommand *self = IDE_VIM_PARSER_COMMAND (object);
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- +
- + switch (prop_id)
- + {
- + case PROP_ARGS:
- + g_value_set_boxed (value, priv->args);
- + break;
- +
- + case PROP_ID:
- + g_value_set_uint (value, priv->id);
- + break;
- +
- + case PROP_FUNC:
- + g_value_set_pointer (value, priv->func);
- + break;
- +
- + case PROP_NAME:
- + g_value_set_string (value, priv->name);
- + break;
- +
- + case PROP_SHORTNAME:
- + g_value_set_string (value, priv->shortname);
- + break;
- +
- + case PROP_SYNTAX:
- + g_value_set_string (value, ide_vim_parser_command_get_syntax (self));
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_parser_command_set_property (GObject *object,
- + guint prop_id,
- + const GValue *value,
- + GParamSpec *pspec)
- +{
- + IdeVimParserCommand *self = IDE_VIM_PARSER_COMMAND (object);
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- +
- + switch (prop_id)
- + {
- + case PROP_FUNC:
- + priv->func = g_value_get_pointer (value);
- + break;
- +
- + case PROP_NAME:
- + priv->name = g_value_dup_string (value);
- + break;
- +
- + case PROP_SHORTNAME:
- + ide_vim_parser_command_set_shortname (self, g_value_get_string (value));
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_parser_command_finalize (GObject *object)
- +{
- + IdeVimParserCommand *self = (IdeVimParserCommand *)object;
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- +
- + g_clear_pointer (&priv->name, g_free);
- + g_clear_pointer (&priv->shortname, g_free);
- + g_ptr_array_free (priv->args, TRUE);
- +
- + G_OBJECT_CLASS (ide_vim_parser_command_parent_class)->finalize (object);
- +}
- +
- +/**
- + * ide_vim_parser_command_new:
- + * @name: (in): the command name.
- + * @shortname: (in): the command shortname.
- + * @func: (in) (skip): the #IdeVimParserCommandFunc command function pointer.
- + *
- + * Create a new #IdeVimParserCommand command.
- + * The shortname should be a prefix of the name,
- + * at least one char and shorter than the complete name.
- + *
- + * Returns: (transfer full): A new #IdeVimParserCommand command.
- + */
- +IdeVimParserCommand *
- +ide_vim_parser_command_new (const gchar *name,
- + const gchar *shortname,
- + IdeVimParserCommandFunc func)
- +{
- + return g_object_new (IDE_TYPE_VIM_PARSER_COMMAND,
- + "name", name,
- + "shortname", shortname,
- + "func", func,
- + NULL);
- +}
- +
- +static void
- +ide_vim_parser_command_init (IdeVimParserCommand *self)
- +{
- + IdeVimParserCommandPrivate *priv = ide_vim_parser_command_get_instance_private (self);
- + static guint id_count = 1;
- +
- + priv->id = id_count++;
- + priv->args = g_ptr_array_new_full (8, (GDestroyNotify)ide_vim_parser_token_unref);
- +}
- +
- +static void
- +ide_vim_parser_command_class_init (IdeVimParserCommandClass *klass)
- +{
- + GObjectClass *object_class = G_OBJECT_CLASS (klass);
- +
- + object_class->finalize = ide_vim_parser_command_finalize;
- + object_class->get_property = ide_vim_parser_command_get_property;
- + object_class->set_property = ide_vim_parser_command_set_property;
- +
- + /**
- + * IdeVimParserCommand:args:
- + *
- + * A #GPtrArray holding the #IdeVimParserToken args of the command.
- + *
- + */
- + gParamSpecs[PROP_ARGS] =
- + g_param_spec_boxed ("args",
- + _("Command arg array"),
- + _("The arg array of the command."),
- + G_TYPE_PTR_ARRAY,
- + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserCommand:func:
- + *
- + * A IdeVimParserCommandFunc pointer to the function use to execute the command.
- + *
- + */
- + gParamSpecs[PROP_FUNC] =
- + g_param_spec_pointer ("func",
- + _("Command function pointer"),
- + _("A pointer to the command function."),
- + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserCommand:id:
- + *
- + * A uint holding the id of the command.
- + *
- + */
- + gParamSpecs[PROP_ID] =
- + g_param_spec_uint ("id",
- + _("Command id"),
- + _("The id of the command."),
- + 0,
- + G_MAXUINT,
- + 0,
- + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserCommand:name:
- + *
- + * A string holding the name of the command.
- + */
- + gParamSpecs[PROP_NAME] =
- + g_param_spec_string ("name",
- + _("Command name"),
- + _("The name of the command."),
- + NULL,
- + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserCommand:shortname:
- + *
- + * A string holding the shortname of the command.
- + * By design, it is ensured that the shortname string
- + * is a prefix of the name string.
- + */
- + gParamSpecs[PROP_SHORTNAME] =
- + g_param_spec_string ("shortname",
- + _("Command shortname"),
- + _("The shortname of the command."),
- + NULL,
- + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserCommand:syntax:
- + *
- + * A string holding the syntax of the command,
- + * mostly used for helping purpose.
- + */
- + gParamSpecs[PROP_SYNTAX] =
- + g_param_spec_string ("syntax",
- + _("Command syntax"),
- + _("The syntax of the command."),
- + NULL,
- + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- +
- + g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
- +}
- diff --git a/libide/vim/ide-vim-parser-command.h b/libide/vim/ide-vim-parser-command.h
- new file mode 100644
- index 0000000..292cb13
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-command.h
- @@ -0,0 +1,66 @@
- +/* ide-vim-parser-command.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_PARSER_COMMAND_H
- +#define IDE_VIM_PARSER_COMMAND_H
- +
- +#include <glib.h>
- +
- +#include "ide-vim-parser-error.h"
- +#include "ide-vim-parser-token.h"
- +#include "ide-vim-parser-commands.h"
- +
- +G_BEGIN_DECLS
- +
- +#define IDE_TYPE_VIM_PARSER_COMMAND (ide_vim_parser_command_get_type())
- +
- +G_DECLARE_FINAL_TYPE (IdeVimParserCommand , ide_vim_parser_command, IDE, VIM_PARSER_COMMAND, GObject)
- +
- +struct _IdeVimParserCommand
- +{
- + GObject parent;
- +};
- +
- +
- +
- +IdeVimParserCommand *ide_vim_parser_command_new (const gchar *name,
- + const gchar *shortname,
- + IdeVimParserCommandFunc func);
- +const GPtrArray *ide_vim_parser_command_get_args (IdeVimParserCommand *self);
- +gboolean ide_vim_parser_command_get_number_arg (IdeVimParserCommand *self,
- + guint position,
- + gint *number);
- +gboolean ide_vim_parser_command_get_string_arg (IdeVimParserCommand *self,
- + guint position,
- + const gchar **string);
- +IdeVimParserCommandFunc ide_vim_parser_command_get_func (IdeVimParserCommand *self);
- +const gchar *ide_vim_parser_command_get_name (IdeVimParserCommand *self);
- +const gchar *ide_vim_parser_command_get_shortname (IdeVimParserCommand *self);
- +const gchar *ide_vim_parser_command_get_syntax (IdeVimParserCommand *self);
- +guint ide_vim_parser_command_get_id (IdeVimParserCommand *self);
- +void ide_vim_parser_command_add_arg (IdeVimParserCommand *self,
- + IdeVimParserTokenKind kind,
- + IdeVimParserTokenFlag flag);
- +gboolean ide_vim_parser_command_has_bang (IdeVimParserCommand *self);
- +/* TODO: should be private */
- +IdeVimParserCommand *ide_vim_parser_command_parsed_new (IdeVimParserCommand *self,
- + GList *args,
- + IdeVimParserError **error);
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_PARSER_COMMAND_H */
- diff --git a/libide/vim/ide-vim-parser-commands.c b/libide/vim/ide-vim-parser-commands.c
- new file mode 100644
- index 0000000..68023e6
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-commands.c
- @@ -0,0 +1,29 @@
- +/* ide-vim-parser-commands.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <string.h>
- +
- +#include <glib/gprintf.h>
- +#include <glib/gi18n.h>
- +
- +#include "ide-debug.h"
- +#include "ide-macros.h"
- +
- +#include "ide-vim-parser-command.h"
- +#include "ide-vim-parser-commands.h"
- +
- diff --git a/libide/vim/ide-vim-parser-commands.h b/libide/vim/ide-vim-parser-commands.h
- new file mode 100644
- index 0000000..381084c
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-commands.h
- @@ -0,0 +1,41 @@
- +/* ide-vim-parser-commands.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_PARSER_COMMANDS_H
- +#define IDE_VIM_PARSER_COMMANDS_H
- +
- +#include <glib.h>
- +#include <gtk/gtk.h>
- +#include <gtksourceview/gtksource.h>
- +
- +#include "ide-vim-parser-error.h"
- +#include "ide-vim-parser-token.h"
- +
- +G_BEGIN_DECLS
- +
- +typedef struct _IdeVimParserCommand IdeVimParserCommand;
- +typedef struct _IdeVimParser IdeVimParser;
- +
- +typedef gboolean (*IdeVimParserCommandFunc) (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_PARSER_COMMANDS_H */
- diff --git a/libide/vim/ide-vim-parser-debug.c b/libide/vim/ide-vim-parser-debug.c
- new file mode 100644
- index 0000000..d54b287
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-debug.c
- @@ -0,0 +1,151 @@
- +/* ide-vim-parser-debug.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <glib/gprintf.h>
- +#include <glib/gi18n.h>
- +
- +#include "ide-macros.h"
- +
- +#include "ide-vim-parser-debug.h"
- +
- +#pragma GCC diagnostic push
- +#pragma GCC diagnostic ignored "-Wswitch-enum"
- +
- +gchar *
- +ide_vim_parser_debug_token_to_string (IdeVimParserToken *token)
- +{
- + GString *string = g_string_new (NULL);
- +
- + string = g_string_append (string, ide_vim_parser_token_get_kind_name (token));
- + if (!token->is_set)
- + {
- + g_string_append_printf (string, ": not set");
- + return g_string_free (string, FALSE);
- + }
- +
- + switch (token->kind)
- + {
- + case IDE_VIM_PARSER_TOKEN_MARK:
- + case IDE_VIM_PARSER_TOKEN_NUMBER:
- + case IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER:
- + case IDE_VIM_PARSER_TOKEN_RANGE_SEPARATOR:
- + case IDE_VIM_PARSER_TOKEN_REGISTER:
- + case IDE_VIM_PARSER_TOKEN_STRING:
- + g_string_append_printf (string, ":%s", ide_vim_parser_token_get_content (token));
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_PATTERN:
- + g_string_append_printf (string, "type:%c, %s", token->pattern_type, ide_vim_parser_token_get_content (token));
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_RANGE:
- + g_string_append_printf (string, ":[%i,%i]", token->range_start, token->range_end);
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_UNKNOW:
- + case IDE_VIM_PARSER_TOKEN_END_OF_STRING:
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_COMMAND_NAME:
- + g_string_append_printf (string, ":%s%c",
- + ide_vim_parser_command_get_name (token->command_entry),
- + token->command_has_bang ? '!' : '\0');
- + break;
- +
- + default:
- + g_assert_not_reached ();
- + break;
- + }
- +
- + return g_string_free (string, FALSE);
- +}
- +
- +#pragma GCC diagnostic pop
- +
- +void
- +ide_vim_parser_debug_show_stack (GList *token_list)
- +{
- + GList *l = NULL;
- + gchar *str;
- +
- + if (token_list != NULL)
- + g_printf ("--------------------------------------------\n"
- + "Debug - Show stack :\n");
- +
- + for (l = token_list; l != NULL; l = l->next)
- + {
- + str = ide_vim_parser_debug_token_to_string (l->data);
- + g_printf ("%s\n", str);
- + g_free (str);
- + }
- +}
- +
- +/**
- + * ide_vim_parser_debug_show_parsed:
- + * @parsed_command: (in): A #IdeVimParserCommand command.
- + *
- + * Show the tokens of a parsed command line.
- + */
- +void
- +ide_vim_parser_debug_show_parsed (IdeVimParserCommand *parsed_command)
- +{
- + const GPtrArray *args;
- + gchar *str;
- +
- + args = ide_vim_parser_command_get_args (parsed_command);
- + if (args == NULL || args->len == 0)
- + {
- + g_printf ("no tokens in list\n");
- + return;
- + }
- +
- + for (gint i = 0; i < args->len; i++)
- + {
- + str = ide_vim_parser_debug_token_to_string (g_ptr_array_index (args, i));
- + g_printf ("%s\n", str);
- + g_free (str);
- + }
- +}
- +
- +void
- +ide_vim_parser_debug_show_info (const IdeVimParserInfo *info)
- +{
- + const gchar *state_names [] =
- + {
- + "Not parsed",
- + "Complete",
- + "Incomplete",
- + "Error"
- + };
- +
- + const gchar *state_name;
- + const gchar *error_code_name;
- +
- + state_name = state_names [info->state];
- + error_code_name = ide_vim_parser_error_get_message (info->error_code);
- +
- + g_printf ("state:%s, error code:%i %s\n", state_name, info->error_code, error_code_name);
- + g_printf ("last token kind:%s, last good token kind:%s\n",
- + ide_vim_parser_token_kind_get_name (info->last_token_kind),
- + ide_vim_parser_token_kind_get_name (info->last_good_token_kind));
- +
- + g_printf ("last token content:%s\n", info->last_token_content);
- + g_printf ("command found:%s\n\n", info->command_name_found);
- +}
- +
- +
- diff --git a/libide/vim/ide-vim-parser-debug.h b/libide/vim/ide-vim-parser-debug.h
- new file mode 100644
- index 0000000..259c0fc
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-debug.h
- @@ -0,0 +1,36 @@
- +/* ide-vim-parser-debug.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_PARSER_DEBUG_H
- +#define IDE_VIM_PARSER_DEBUG_H
- +
- +#include <glib-object.h>
- +
- +#include "ide-vim-parser.h"
- +#include "ide-vim-parser-command.h"
- +#include "ide-vim-parser-token.h"
- +
- +G_BEGIN_DECLS
- +
- +void ide_vim_parser_debug_show_parsed (IdeVimParserCommand *parsed_command);
- +gchar *ide_vim_parser_debug_token_to_string (IdeVimParserToken *token);
- +void ide_vim_parser_debug_show_stack (GList *token_list);
- +void ide_vim_parser_debug_show_info (const IdeVimParserInfo *info);
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_PARSER_DEBUG_H */
- diff --git a/libide/vim/ide-vim-parser-error.c b/libide/vim/ide-vim-parser-error.c
- new file mode 100644
- index 0000000..5d2e541
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-error.c
- @@ -0,0 +1,340 @@
- +/* ide-vim-parser-error.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +#include <glib/gprintf.h>
- +#include <glib/gi18n.h>
- +
- +#include "ide-macros.h"
- +
- +#include "ide-vim-parser-error.h"
- +
- +/* Keep it in sync with IdeVimParserErrorCode enum */
- +static const gchar *error_messages [] = {
- + N_("No error"),
- + N_("Unknow parser error"),
- + N_("Feature not yet implemented"),
- + N_("Vim mode requires GtkSourceView"),
- + N_("Failed to locate working directory"),
- + N_("There's no buffer referenced by the view"),
- + N_("Not found"),
- + N_("This is not a number"),
- + N_("The Number is out of range"),
- + N_("There's no command found in the command line text"),
- + N_("The command is empty or NULL"),
- + N_("This is an unknow option"),
- + N_("Your command line syntax doesn't match the registered command syntax"),
- + N_("You provide less arguments than the registered command syntax need"),
- + N_("You provide more arguments than the registered command syntax need"),
- + N_("The set value you provide is invalid"),
- + N_("The set command can't be parsed."),
- + N_("Unknow range specifier."),
- + N_("Unknow mark."),
- + N_("Unknow register."),
- + N_("You can't use this token here.")
- +};
- +
- +/**
- + * ide_vim_parser_error_get_detail:
- + * @error: (in): a #IdeVimParserError pointer.
- + *
- + * Return the detail string of the IdeVimParserError error.
- + *
- + * Returns: (transfer full): the detail string.
- + */
- +gchar *
- +ide_vim_parser_error_get_detail (IdeVimParserError *error)
- +{
- + g_autofree gchar *error_cursor = NULL;
- +
- + g_assert (error->pos >= -1 || error->pos < strlen (error->detail_text));
- +
- + if (!ide_str_empty0 (error->detail_text))
- + {
- + if (error->pos == -1)
- + return g_strdup (error->detail_text);
- +
- + if (error->pos == 0)
- + return g_strdup_printf ("%s\n^", error->detail_text);
- +
- + error_cursor = g_strnfill (error->pos, ' ');
- + return g_strdup_printf ("%s\n%s^", error->detail_text, error_cursor);
- + }
- +
- + return NULL;
- +}
- +
- +/**
- + * ide_vim_parser_error_print:
- + * @error: (in): a #IdeVimParserError pointer.
- + *
- + * Print the message and detail of the #IdeVimParserError error.
- + * Mainly used for debug stuffs.
- + */
- +void
- +ide_vim_parser_error_print (IdeVimParserError *error)
- +{
- + g_autofree gchar *detail = NULL;
- +
- + g_assert (error != NULL);
- +
- + g_printf ("%s\n", error->code_text);
- + detail = ide_vim_parser_error_get_detail (error);
- + g_printf ("%s", detail);
- +}
- +
- +const gchar *
- +ide_vim_parser_error_get_message (IdeVimParserErrorCode error_code)
- +{
- + return error_messages [error_code];
- +}
- +
- +IdeVimParserErrorCode
- +ide_vim_parser_error_get_error_code (IdeVimParserError *error)
- +{
- + if (error == NULL)
- + return IDE_VIM_PARSER_ERROR_NONE;
- + else
- + return error->code;
- +}
- +
- +/**
- + * ide_vim_parser_error_propagate:
- + * @dest: (in): an adress of the destination #IdeVimParserError error pointer.
- + * @src: (in): a source #IdeVimParserError error pointer.
- + *
- + * If src error is set, then tranfer it to the dest error,
- + * otherwise, do nothing.
- + */
- +void
- +ide_vim_parser_error_propagate (IdeVimParserError **dest,
- + IdeVimParserError *src)
- +{
- + if (dest == NULL)
- + {
- + if (src)
- + ide_vim_parser_error_free (src);
- + return;
- + }
- + else
- + {
- + if (*dest != NULL)
- + {
- + g_warning ("You are overwriting an already set IdeVimParserError");
- + if (src)
- + ide_vim_parser_error_free (src);
- + }
- + else
- + {
- + *dest = src;
- + }
- + }
- +}
- +
- +#pragma GCC diagnostic push
- +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
- +static IdeVimParserError *
- +ide_vim_parser_error_new_valist (IdeVimParserErrorCode code,
- + const gchar *message,
- + va_list args)
- +{
- + IdeVimParserError *self;
- +
- + self = g_new0 (IdeVimParserError, 1);
- +
- + self->code = code;
- + self->code_text = g_strdup (gettext (error_messages [code]));
- + self->detail_text = (message) ? g_strdup_vprintf (message, args) : NULL;
- + self->pos = -1;
- +
- + return self;
- +}
- +#pragma GCC diagnostic pop
- +
- +/**
- + * ide_vim_parser_error_new:
- + * @code: a #IdeVimParserErrorCode error code.
- + * @message: a text error string.
- + *
- + * Returns: (skip) (transfer full): a new @IdeVimParserError error.
- + */
- +IdeVimParserError *
- +ide_vim_parser_error_new (IdeVimParserErrorCode code,
- + const gchar *message)
- +{
- + return ide_vim_parser_error_cursor_new (code, message, -1);
- +}
- +
- +/**
- + * ide_vim_parser_error_cursor_new:
- + * @code: a #IdeVimParserErrorCode error code.
- + * @message: a text error string (command line for example).
- + * @pos: the position, starting from 0, of an error indicator for the #cmdline text.
- + *
- + * Returns: (skip) (transfer full): a new @IdeVimParserError error.
- + */
- +IdeVimParserError *
- +ide_vim_parser_error_cursor_new (IdeVimParserErrorCode code,
- + const gchar *message,
- + gint pos)
- +{
- + IdeVimParserError *self;
- +
- + self = g_new0 (IdeVimParserError, 1);
- +
- + self->code = code;
- + self->code_text = g_strdup (gettext (error_messages [code]));
- + self->detail_text = (message) ? g_strdup (message) : NULL;
- + self->pos = pos;
- +
- + return self;
- +}
- +
- +/**
- + * ide_vim_parser_error_literal_new:
- + * @code: (in): a #IdeVimParserErrorCode error code.
- + * @message: (in): a printf style string.
- + * @...: (in): arguments for the printf style string.
- + *
- + * Returns: (skip) (transfer full): a new @IdeVimParserError error.
- + */
- +IdeVimParserError *
- +ide_vim_parser_error_literal_new (IdeVimParserErrorCode code,
- + const gchar *message,
- + ...)
- +{
- + IdeVimParserError *self;
- + va_list args;
- +
- + self = g_new0 (IdeVimParserError, 1);
- +
- + va_start(args, message);
- + self = ide_vim_parser_error_new_valist (code, message, args);
- + va_end (args);
- +
- + return self;
- +}
- +
- +/**
- + * ide_vim_parser_error_set:
- + * @error_p: (in): an adress of the destination #IdeVimParserError error pointer.
- + * @code: (in): a #IdeVimParserErrorCode error code.
- + * @message: (in): a text error string (command line for example).
- + *
- + * Set the content of a @IdeVimParserError error.
- + */
- +void
- +ide_vim_parser_error_set (IdeVimParserError **error_p,
- + IdeVimParserErrorCode code,
- + const gchar *message)
- +{
- + if (error_p == NULL)
- + return;
- +
- + if (*error_p == NULL)
- + *error_p = ide_vim_parser_error_cursor_new (code, message, -1);
- + else
- + g_warning ("You are overwriting an already set IdeVimParserError");
- +}
- +
- +/**
- + * ide_vim_parser_error_cursor_set:
- + * @error_p: (in): an adress of the destination #IdeVimParserError error pointer.
- + * @code: (in): a #IdeVimParserErrorCode error code.
- + * @message: (in): a text error string (command line for example).
- + * @pos: (in): the position, starting from 0, of an error indicator for the #cmdline text.
- + *
- + * Set the content of a @IdeVimParserError error.
- + */
- +void
- +ide_vim_parser_error_cursor_set (IdeVimParserError **error_p,
- + IdeVimParserErrorCode code,
- + const gchar *message,
- + guint pos)
- +{
- + if (error_p == NULL)
- + return;
- +
- + if (*error_p == NULL)
- + *error_p = ide_vim_parser_error_cursor_new (code, message, pos);
- + else
- + g_warning ("You are overwriting an already set IdeVimParserError");
- +}
- +
- +/**
- + * ide_vim_parser_error_literal_set:
- + * @error_p: (in): an adress of the destination #IdeVimParserError error pointer.
- + * @code: (in): a #IdeVimParserErrorCode error code.
- + * @message: (in): a printf style string.
- + * @...: (in): arguments for the printf style string.
- + *
- + * Set the content of a @IdeVimParserError error.
- + */
- +void
- +ide_vim_parser_error_literal_set (IdeVimParserError **error_p,
- + IdeVimParserErrorCode code,
- + const gchar *message,
- + ...)
- +{
- + va_list args;
- +
- + if (error_p == NULL)
- + return;
- +
- + if (*error_p == NULL)
- + {
- + va_start(args, message);
- + *error_p = ide_vim_parser_error_new_valist (code, message, args);
- + va_end (args);
- + }
- + else
- + {
- + g_warning ("You are overwriting an already set IdeVimParserError");
- + }
- +}
- +
- +/**
- + * ide_vim_parser_error_clear:
- + * @error: (in): an adress of the destination #IdeVimParserError error pointer.
- + *
- + * Free the @IdeVimParserError pointed by error and set it to NULL.
- + */
- +void
- +ide_vim_parser_error_clear (IdeVimParserError **error)
- +{
- + if (error && *error)
- + {
- + ide_vim_parser_error_free (*error);
- + *error = NULL;
- + }
- +}
- +
- +/**
- + * ide_vim_parser_error_free:
- + * @self: (in): a IdeVimParserError error.
- + *
- + * Free the @IdeVimParserError error.
- + */
- +void
- +ide_vim_parser_error_free (IdeVimParserError *self)
- +{
- + g_assert (self != NULL);
- +
- + g_clear_pointer (&self->code_text, g_free);
- + g_clear_pointer (&self->detail_text, g_free);
- +
- + g_free (self);
- +}
- diff --git a/libide/vim/ide-vim-parser-error.h b/libide/vim/ide-vim-parser-error.h
- new file mode 100644
- index 0000000..7fd466c
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-error.h
- @@ -0,0 +1,93 @@
- +/* ide-vim-parser-error.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_PARSER_ERROR_H
- +#define IDE_VIM_PARSER_ERROR_H
- +
- +#include <glib-object.h>
- +
- +G_BEGIN_DECLS
- +
- +#define IDE_VIM_PARSER_ERROR (ide_vim_parser_error_quark())
- +
- +typedef struct _IdeVimParserError IdeVimParserError;
- +
- +/* Keep it in sync with error_messages array */
- +typedef enum
- +{
- + IDE_VIM_PARSER_ERROR_NONE,
- + IDE_VIM_PARSER_ERROR_FAILED,
- + IDE_VIM_PARSER_ERROR_NOT_IMPLEMENTED,
- + IDE_VIM_PARSER_ERROR_NOT_SOURCE_VIEW,
- + IDE_VIM_PARSER_ERROR_NO_WORKING_DIR,
- + IDE_VIM_PARSER_ERROR_NO_BUFFER,
- + IDE_VIM_PARSER_ERROR_NOT_FOUND,
- + IDE_VIM_PARSER_ERROR_NOT_NUMBER,
- + IDE_VIM_PARSER_ERROR_NUMBER_OUT_OF_RANGE,
- + IDE_VIM_PARSER_ERROR_COMMAND_NOT_FOUND,
- + IDE_VIM_PARSER_ERROR_CMDLINE_EMPTY,
- + IDE_VIM_PARSER_ERROR_UNKNOWN_OPTION,
- + IDE_VIM_PARSER_ERROR_MISMATCH_KIND,
- + IDE_VIM_PARSER_ERROR_MISMATCH_LESS_ARGS,
- + IDE_VIM_PARSER_ERROR_MISMATCH_MORE_ARGS,
- + IDE_VIM_PARSER_ERROR_SET_VALUE_INVALID,
- + IDE_VIM_PARSER_ERROR_SET_CANT_PARSE,
- + IDE_VIM_PARSER_ERROR_UNKNOWN_RANGE_SPECIFIER,
- + IDE_VIM_PARSER_ERROR_UNKNOWN_MARK,
- + IDE_VIM_PARSER_ERROR_UNKNOWN_REGISTER,
- + IDE_VIM_PARSER_ERROR_UNWANTED_TOKEN
- +} IdeVimParserErrorCode;
- +
- +struct _IdeVimParserError
- +{
- + IdeVimParserErrorCode code;
- + const gchar *code_text;
- + const gchar *detail_text;
- + gint pos;
- +};
- +
- +void ide_vim_parser_error_clear (IdeVimParserError **error);
- +gchar *ide_vim_parser_error_get_detail (IdeVimParserError *error);
- +void ide_vim_parser_error_free (IdeVimParserError *self);
- +IdeVimParserError *ide_vim_parser_error_literal_new (IdeVimParserErrorCode code,
- + const gchar *message,
- + ...) G_GNUC_PRINTF (2,3);
- +IdeVimParserError *ide_vim_parser_error_new (IdeVimParserErrorCode code,
- + const gchar *message);
- +IdeVimParserError *ide_vim_parser_error_cursor_new (IdeVimParserErrorCode code,
- + const gchar *message,
- + gint pos);
- +void ide_vim_parser_error_literal_set (IdeVimParserError **error_p,
- + IdeVimParserErrorCode code,
- + const gchar *message,
- + ...) G_GNUC_PRINTF (3,4);
- +void ide_vim_parser_error_cursor_set (IdeVimParserError **error_p,
- + IdeVimParserErrorCode code,
- + const gchar *message,
- + guint pos);
- +void ide_vim_parser_error_set (IdeVimParserError **error_p,
- + IdeVimParserErrorCode code,
- + const gchar *message);
- +void ide_vim_parser_error_print (IdeVimParserError *error);
- +void ide_vim_parser_error_propagate (IdeVimParserError **dest,
- + IdeVimParserError *src);
- +IdeVimParserErrorCode ide_vim_parser_error_get_error_code (IdeVimParserError *error);
- +const gchar *ide_vim_parser_error_get_message (IdeVimParserErrorCode error_code);
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_PARSER_ERROR_H */
- diff --git a/libide/vim/ide-vim-parser-objects-pool.c b/libide/vim/ide-vim-parser-objects-pool.c
- new file mode 100644
- index 0000000..7423ef0
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-objects-pool.c
- @@ -0,0 +1,496 @@
- +/* ide-vim-parser-objects-pool.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <string.h>
- +
- +#include <glib/gprintf.h>
- +#include <glib/gi18n.h>
- +
- +#include "ide-debug.h"
- +#include "ide-macros.h"
- +
- +#include "ide-vim-parser-objects-pool.h"
- +#include "ide-vim-complete-item.h"
- +
- +typedef struct
- +{
- + GHashTable *command_name_table;
- + GHashTable *command_shortname_table;
- +
- + GHashTable *settable_name_table;
- + GHashTable *settable_shortname_table;
- +} IdeVimParserObjectsPoolPrivate;
- +
- +G_DEFINE_TYPE_WITH_PRIVATE (IdeVimParserObjectsPool, ide_vim_parser_objects_pool, G_TYPE_OBJECT)
- +
- +enum {
- + PROP_0,
- + LAST_PROP
- +};
- +
- +static GParamSpec *gParamSpecs [LAST_PROP];
- +
- +IdeVimParserSettable *
- +ide_vim_parser_objects_pool_lookup_settable (IdeVimParserObjectsPool *self,
- + const gchar *string)
- +{
- + gpointer value;
- + IdeVimParserObjectsPoolPrivate *priv = ide_vim_parser_objects_pool_get_instance_private (self);
- +
- + value = g_hash_table_lookup (priv->settable_name_table, string);
- + if (value == NULL)
- + value = g_hash_table_lookup (priv->settable_shortname_table, string);
- +
- + return IDE_VIM_PARSER_SETTABLE (value);
- +}
- +
- +IdeVimParserCommand *
- +ide_vim_parser_objects_pool_lookup_command (IdeVimParserObjectsPool *self,
- + const gchar *string)
- +{
- + gpointer value;
- + IdeVimParserObjectsPoolPrivate *priv = ide_vim_parser_objects_pool_get_instance_private (self);
- +
- + value = g_hash_table_lookup (priv->command_name_table, string);
- + if (value == NULL)
- + value = g_hash_table_lookup (priv->command_shortname_table, string);
- +
- + return IDE_VIM_PARSER_COMMAND (value);
- +}
- +
- +/*
- + * ar is a GPtrArray of IdeVimCompleteItem corresponding to
- + * the commands with prefix match_name.
- + *
- + * Returns: FALSE if there is no element retrived, TRUE otherwise.
- + */
- +gboolean
- +ide_vim_parser_objects_pool_complete_command (IdeVimParserObjectsPool *self,
- + GPtrArray *ar,
- + const gchar *match_text)
- +{
- + IdeVimParserObjectsPoolPrivate *priv;
- + GHashTable *dup_table = NULL;
- + GHashTableIter iter;
- + gpointer key, value;
- + IdeVimCompleteItem *complete_entry = NULL;
- + const gchar *name;
- + const gchar *shortname;
- + gboolean is_get_all = FALSE;
- + gboolean has_entry = FALSE;
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_OBJECTS_POOL (self), FALSE);
- + priv = ide_vim_parser_objects_pool_get_instance_private (self);
- +
- + /* If the matching text is empty, we want all the existing commands */
- + if (ide_str_empty0 (match_text))
- + is_get_all = TRUE;
- + else
- + dup_table = g_hash_table_new ((GHashFunc)g_str_hash, (GEqualFunc)g_str_equal);
- +
- + g_hash_table_iter_init (&iter, priv->command_name_table);
- + while (g_hash_table_iter_next (&iter, &key, &value))
- + {
- + name = (gchar *)key;
- + if (is_get_all || g_str_has_prefix (name, match_text))
- + {
- + shortname = ide_vim_parser_command_get_shortname (IDE_VIM_PARSER_COMMAND (value));
- + if (!is_get_all && !ide_str_empty0 (shortname))
- + g_hash_table_add (dup_table, (gpointer)shortname);
- +
- + complete_entry = ide_vim_complete_item_new (IDE_VIM_COMPLETE_ITEM_KIND_COMMAND,
- + g_strdup (name),
- + g_strdup (shortname));
- + g_ptr_array_add (ar, complete_entry);
- + has_entry = TRUE;
- + }
- + }
- +
- + if (!is_get_all)
- + {
- + g_hash_table_iter_init (&iter, priv->command_shortname_table);
- + while (g_hash_table_iter_next (&iter, &key, &value))
- + {
- + shortname = (gchar *)key;
- + if (g_str_has_prefix (shortname, match_text) && !g_hash_table_contains (dup_table, shortname))
- + {
- + name = ide_vim_parser_command_get_name (IDE_VIM_PARSER_COMMAND (value));
- + complete_entry = ide_vim_complete_item_new (IDE_VIM_COMPLETE_ITEM_KIND_COMMAND,
- + g_strdup (name),
- + g_strdup (shortname));
- + g_ptr_array_add (ar, complete_entry);
- + has_entry = TRUE;
- + }
- + }
- + }
- +
- + if (!is_get_all)
- + g_hash_table_destroy (dup_table);
- +
- + return has_entry;
- +}
- +
- +/*
- + * ar is a GPtrArray of IdeVimCompleteItem corresponding to
- + * the settables with prefix match_name.
- + *
- + * Returns: FALSE if there is no element retrived, TRUE otherwise.
- + */
- +gboolean
- +ide_vim_parser_objects_pool_complete_settable (IdeVimParserObjectsPool *self,
- + GPtrArray *ar,
- + const gchar *match_text)
- +{
- + IdeVimParserObjectsPoolPrivate *priv;
- + GHashTable *dup_table = NULL;
- + GHashTableIter iter;
- + gpointer key, value;
- + IdeVimCompleteItem *complete_entry = NULL;
- + const gchar *name;
- + const gchar *shortname;
- + gboolean is_get_all = FALSE;
- + gboolean has_entry = FALSE;
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_OBJECTS_POOL (self), FALSE);
- + priv = ide_vim_parser_objects_pool_get_instance_private (self);
- +
- + /* If the matching text is empty, we want all the existing commands */
- + if (ide_str_empty0 (match_text))
- + is_get_all = TRUE;
- + else
- + dup_table = g_hash_table_new ((GHashFunc)g_str_hash, (GEqualFunc)g_str_equal);
- +
- + g_hash_table_iter_init (&iter, priv->settable_name_table);
- + while (g_hash_table_iter_next (&iter, &key, &value))
- + {
- + name = (gchar *)key;
- + if (is_get_all || g_str_has_prefix (name, match_text))
- + {
- + shortname = ide_vim_parser_settable_get_shortname (IDE_VIM_PARSER_SETTABLE (value));
- + if (!is_get_all && !ide_str_empty0 (shortname))
- + g_hash_table_add (dup_table, (gpointer)shortname);
- +
- + complete_entry = ide_vim_complete_item_new (IDE_VIM_COMPLETE_ITEM_KIND_SET,
- + g_strdup (name),
- + g_strdup (shortname));
- + g_ptr_array_add (ar, complete_entry);
- + has_entry = TRUE;
- + }
- + }
- +
- + if (!is_get_all)
- + {
- + g_hash_table_iter_init (&iter, priv->settable_shortname_table);
- + while (g_hash_table_iter_next (&iter, &key, &value))
- + {
- + shortname = (gchar *)key;
- + if (g_str_has_prefix (shortname, match_text) && !g_hash_table_contains (dup_table, shortname))
- + {
- + name = ide_vim_parser_settable_get_name (IDE_VIM_PARSER_SETTABLE (value));
- + complete_entry = ide_vim_complete_item_new (IDE_VIM_COMPLETE_ITEM_KIND_SET,
- + g_strdup (name),
- + g_strdup (shortname));
- + g_ptr_array_add (ar, complete_entry);
- + has_entry = TRUE;
- + }
- + }
- + }
- +
- + if (!is_get_all)
- + g_hash_table_destroy (dup_table);
- +
- + return has_entry;
- +}
- +
- +gboolean
- +ide_vim_parser_objects_pool_add_settable (IdeVimParserObjectsPool *self,
- + IdeVimParserSettable *settable,
- + gboolean replace)
- +{
- + const gchar *name;
- + const gchar *shortname;
- + const gchar *found_settable_shortname;
- + IdeVimParserSettable *found_settable;
- + gboolean is_conflict;
- + IdeVimParserObjectsPoolPrivate *priv;
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_OBJECTS_POOL (self), FALSE);
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_SETTABLE (settable), FALSE);
- +
- + priv = ide_vim_parser_objects_pool_get_instance_private (self);
- + name = ide_vim_parser_settable_get_name (settable);
- + shortname = ide_vim_parser_settable_get_shortname (settable);
- +
- + found_settable = IDE_VIM_PARSER_SETTABLE (g_hash_table_lookup (priv->settable_name_table, name));
- +
- + is_conflict = (g_hash_table_lookup (priv->settable_shortname_table, name) != NULL ||
- + g_hash_table_lookup (priv->settable_name_table, shortname) != NULL ||
- + g_hash_table_lookup (priv->settable_shortname_table, shortname) != NULL);
- +
- + if (is_conflict)
- + {
- + g_warning (_("This Settable can't be added because of a conflict with an existing name and/or shortname"));
- + return FALSE;
- + }
- +
- + if (found_settable == NULL)
- + {
- + g_object_ref (settable);
- + g_hash_table_insert (priv->settable_name_table, g_strdup (name), settable);
- + g_hash_table_insert (priv->settable_shortname_table, g_strdup (shortname), settable);
- +
- + return TRUE;
- + }
- +
- + if (settable == found_settable)
- + {
- + g_warning (_("This Settable is already in the pool"));
- + return FALSE;
- + }
- +
- + if (replace)
- + {
- + found_settable_shortname = ide_vim_parser_settable_get_shortname (found_settable);
- + g_hash_table_remove (priv->settable_shortname_table, found_settable_shortname);
- +
- + g_object_ref (settable);
- + g_hash_table_replace (priv->settable_name_table, g_strdup (name), settable);
- + g_hash_table_insert (priv->settable_shortname_table, g_strdup (shortname), settable);
- +
- + return TRUE;
- + }
- +
- + return FALSE;
- +}
- +
- +gboolean
- +ide_vim_parser_objects_pool_add_command (IdeVimParserObjectsPool *self,
- + IdeVimParserCommand *command,
- + gboolean replace)
- +{
- + const gchar *name;
- + const gchar *shortname;
- + const gchar *found_command_shortname;
- + IdeVimParserCommand *found_command;
- + gboolean is_conflict;
- + gboolean is_shortname_empty;
- + IdeVimParserObjectsPoolPrivate *priv;
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_OBJECTS_POOL (self), FALSE);
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (command), FALSE);
- +
- + priv = ide_vim_parser_objects_pool_get_instance_private (self);
- + name = ide_vim_parser_command_get_name (command);
- + shortname = ide_vim_parser_command_get_shortname (command);
- + is_shortname_empty = ide_str_empty0 (shortname);
- +
- + found_command = IDE_VIM_PARSER_COMMAND (g_hash_table_lookup (priv->command_name_table, name));
- +
- + is_conflict = (g_hash_table_lookup (priv->command_shortname_table, name) != NULL ||
- + (!is_shortname_empty && (g_hash_table_lookup (priv->command_name_table, shortname) != NULL ||
- + g_hash_table_lookup (priv->command_shortname_table, shortname) != NULL)));
- +
- + if (is_conflict)
- + {
- + g_warning (_("This command can't be added because of a conflict with an existing name and/or shortname"));
- + return FALSE;
- + }
- +
- + if (found_command == NULL)
- + {
- + g_object_ref (command);
- + g_hash_table_insert (priv->command_name_table, g_strdup (name), command);
- + if (!is_shortname_empty)
- + g_hash_table_insert (priv->command_shortname_table, g_strdup (shortname), command);
- +
- + return TRUE;
- + }
- +
- + if (command == found_command)
- + {
- + g_warning (_("This command is already in the pool"));
- + return FALSE;
- + }
- +
- + if (replace)
- + {
- + found_command_shortname = ide_vim_parser_command_get_shortname (found_command);
- + if (found_command_shortname != NULL)
- + g_hash_table_remove (priv->command_shortname_table, found_command_shortname);
- +
- + g_object_ref (command);
- + g_hash_table_replace (priv->command_name_table, g_strdup (name), command);
- + if (!is_shortname_empty)
- + g_hash_table_insert (priv->command_shortname_table, g_strdup (shortname), command);
- +
- + return TRUE;
- + }
- +
- + return FALSE;
- +}
- +
- +/* @string can be the name or the shortname */
- +gboolean
- +ide_vim_parser_objects_pool_remove_settable (IdeVimParserObjectsPool *self,
- + const gchar *string)
- +{
- + IdeVimParserSettable *settable;
- + const gchar *name;
- + const gchar *shortname;
- + IdeVimParserObjectsPoolPrivate *priv;
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_OBJECTS_POOL (self), FALSE);
- + g_return_val_if_fail (!ide_str_empty0 (string), FALSE);
- +
- + priv = ide_vim_parser_objects_pool_get_instance_private (self);
- + settable = ide_vim_parser_objects_pool_lookup_settable (self, string);
- + if (settable != NULL)
- + {
- + shortname = ide_vim_parser_settable_get_shortname (settable);
- + g_hash_table_remove (priv->settable_shortname_table, shortname);
- + name = ide_vim_parser_settable_get_name (settable);
- + g_hash_table_remove (priv->settable_name_table, name);
- + return TRUE;
- + }
- +
- + return FALSE;
- +}
- +
- +/* @string can be the name or the shortname */
- +gboolean
- +ide_vim_parser_objects_pool_remove_command (IdeVimParserObjectsPool *self,
- + const gchar *string)
- +{
- + IdeVimParserCommand *command;
- + const gchar *name;
- + const gchar *shortname;
- + IdeVimParserObjectsPoolPrivate *priv;
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_OBJECTS_POOL (self), FALSE);
- + g_return_val_if_fail (!ide_str_empty0 (string), FALSE);
- +
- + priv = ide_vim_parser_objects_pool_get_instance_private (self);
- + command = ide_vim_parser_objects_pool_lookup_command (self, string);
- + if (command != NULL)
- + {
- + shortname = ide_vim_parser_command_get_shortname (command);
- + g_hash_table_remove (priv->command_shortname_table, shortname);
- + name = ide_vim_parser_command_get_name (command);
- + g_hash_table_remove (priv->command_name_table, name);
- + return TRUE;
- + }
- +
- + return FALSE;
- +}
- +
- +static void
- +ide_vim_parser_objects_pool_get_property (GObject *object,
- + guint prop_id,
- + GValue *value,
- + GParamSpec *pspec)
- +{
- + IdeVimParserObjectsPool *self = IDE_VIM_PARSER_OBJECTS_POOL (object);
- +
- + switch (prop_id)
- + {
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_parser_objects_pool_set_property (GObject *object,
- + guint prop_id,
- + const GValue *value,
- + GParamSpec *pspec)
- +{
- + IdeVimParserObjectsPool *self = IDE_VIM_PARSER_OBJECTS_POOL (object);
- + IdeVimParserObjectsPoolPrivate *priv = ide_vim_parser_objects_pool_get_instance_private (self);
- +
- + switch (prop_id)
- + {
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_parser_objects_pool_finalize (GObject *object)
- +{
- + IdeVimParserObjectsPool *self = IDE_VIM_PARSER_OBJECTS_POOL (object);
- + IdeVimParserObjectsPoolPrivate *priv = ide_vim_parser_objects_pool_get_instance_private (self);
- +
- + g_hash_table_destroy (priv->command_name_table);
- + g_hash_table_destroy (priv->command_shortname_table);
- +
- + g_hash_table_destroy (priv->settable_name_table);
- + g_hash_table_destroy (priv->settable_shortname_table);
- +
- + G_OBJECT_CLASS (ide_vim_parser_objects_pool_parent_class)->finalize (object);
- +}
- +
- +/**
- + * ide_vim_parser_objects_pool_new:
- + *
- + * Create a new #IdeVimParserSObjectsPool instance.
- + *
- + * Returns: (transfer full): A new #IdeVimParserObjectsPool instance.
- + */
- +IdeVimParserObjectsPool *
- +ide_vim_parser_objects_pool_new (void)
- +{
- + return g_object_new (IDE_TYPE_VIM_PARSER_OBJECTS_POOL, NULL);
- +}
- +
- +static void
- +ide_vim_parser_objects_pool_init (IdeVimParserObjectsPool *self)
- +{
- + IdeVimParserObjectsPoolPrivate *priv = ide_vim_parser_objects_pool_get_instance_private (self);
- +
- + priv->command_name_table = g_hash_table_new_full ((GHashFunc)g_str_hash,
- + (GEqualFunc)g_str_equal,
- + (GDestroyNotify)g_free,
- + (GDestroyNotify)g_object_unref);
- +
- + priv->command_shortname_table = g_hash_table_new_full ((GHashFunc)g_str_hash,
- + (GEqualFunc)g_str_equal,
- + (GDestroyNotify)g_free,
- + NULL);
- +
- + priv->settable_name_table = g_hash_table_new_full ((GHashFunc)g_str_hash,
- + (GEqualFunc)g_str_equal,
- + (GDestroyNotify)g_free,
- + (GDestroyNotify)g_object_unref);
- +
- + priv->settable_shortname_table = g_hash_table_new_full ((GHashFunc)g_str_hash,
- + (GEqualFunc)g_str_equal,
- + (GDestroyNotify)g_free,
- + NULL);
- +}
- +
- +static void
- +ide_vim_parser_objects_pool_class_init (IdeVimParserObjectsPoolClass *klass)
- +{
- + GObjectClass *object_class = G_OBJECT_CLASS (klass);
- +
- + object_class->finalize = ide_vim_parser_objects_pool_finalize;
- + object_class->get_property = ide_vim_parser_objects_pool_get_property;
- + object_class->set_property = ide_vim_parser_objects_pool_set_property;
- +
- + //g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
- +}
- diff --git a/libide/vim/ide-vim-parser-objects-pool.h b/libide/vim/ide-vim-parser-objects-pool.h
- new file mode 100644
- index 0000000..f6f3e17
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-objects-pool.h
- @@ -0,0 +1,63 @@
- +/* ide-vim-parser-objects-pool.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_PARSER_OBJECTS_POOL_H
- +#define IDE_VIM_PARSER_OBJECTS_POOL_H
- +
- +#include <glib.h>
- +
- +#include "ide-vim-parser-error.h"
- +#include "ide-vim-parser-settable.h"
- +#include "ide-vim-parser-command.h"
- +
- +G_BEGIN_DECLS
- +
- +#define IDE_TYPE_VIM_PARSER_OBJECTS_POOL (ide_vim_parser_objects_pool_get_type())
- +
- +G_DECLARE_FINAL_TYPE (IdeVimParserObjectsPool, ide_vim_parser_objects_pool, IDE, VIM_PARSER_OBJECTS_POOL, GObject)
- +
- +struct _IdeVimParserObjectsPool
- +{
- + GObject parent;
- +};
- +
- +IdeVimParserObjectsPool *ide_vim_parser_objects_pool_new (void);
- +gboolean ide_vim_parser_objects_pool_add_settable (IdeVimParserObjectsPool *self,
- + IdeVimParserSettable *settable,
- + gboolean replace);
- +gboolean ide_vim_parser_objects_pool_add_command (IdeVimParserObjectsPool *self,
- + IdeVimParserCommand *command,
- + gboolean replace);
- +gboolean ide_vim_parser_objects_pool_complete_command (IdeVimParserObjectsPool *self,
- + GPtrArray *ar,
- + const gchar *match_text);
- +gboolean ide_vim_parser_objects_pool_complete_settable (IdeVimParserObjectsPool *self,
- + GPtrArray *ar,
- + const gchar *match_text);
- +IdeVimParserSettable *ide_vim_parser_objects_pool_lookup_settable (IdeVimParserObjectsPool *self,
- + const gchar *string);
- +IdeVimParserCommand *ide_vim_parser_objects_pool_lookup_command (IdeVimParserObjectsPool *self,
- + const gchar *string);
- +gboolean ide_vim_parser_objects_pool_remove_settable (IdeVimParserObjectsPool *self,
- + const gchar *string);
- +gboolean ide_vim_parser_objects_pool_remove_command (IdeVimParserObjectsPool *self,
- + const gchar *string);
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_PARSER_OBJECTS_H */
- diff --git a/libide/vim/ide-vim-parser-private.h b/libide/vim/ide-vim-parser-private.h
- new file mode 100644
- index 0000000..8128365
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-private.h
- @@ -0,0 +1,37 @@
- +/* ide-vim-parser-private.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_PARSER_PRIVATE_H
- +#define IDE_VIM_PARSER_PRIVATE_H
- +
- +#include "ide-vim-parser.h"
- +#include "ide-vim-state-machine.h"
- +
- +G_BEGIN_DECLS
- +
- +typedef enum
- +{
- + FSM_STATE_INITIAL,
- + FSM_STATE_RANGE,
- + FSM_STATE_PATTERN,
- + FSM_STATE_COMMAND
- +} FsmState;
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_PARSER_PRIVATE_H */
- diff --git a/libide/vim/ide-vim-parser-settable.c b/libide/vim/ide-vim-parser-settable.c
- new file mode 100644
- index 0000000..319b7f5
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-settable.c
- @@ -0,0 +1,559 @@
- +/* ide-vim-parser-settable.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <string.h>
- +
- +#include <glib/gprintf.h>
- +#include <glib/gi18n.h>
- +
- +#include "ide-debug.h"
- +#include "ide-macros.h"
- +
- +#include "ide-vim-parser-settable.h"
- +
- +typedef struct
- +{
- + GParamSpec *value_spec;
- + GValue value;
- + GValue default_value;
- + IdeVimParserSettableFunc func;
- + IdeVimParserSettableValuesFunc values_func;
- + gboolean constructed : 1;
- +} IdeVimParserSettablePrivate;
- +
- +G_DEFINE_TYPE_WITH_PRIVATE (IdeVimParserSettable, ide_vim_parser_settable, G_TYPE_OBJECT)
- +
- +enum {
- + PROP_0,
- + PROP_NAME,
- + PROP_SHORTNAME,
- + PROP_HELP,
- + PROP_FUNC,
- + PROP_VALUES_FUNC,
- + PROP_VALUE_SPEC,
- + PROP_VALUE,
- + PROP_DEFAULT_VALUE,
- + LAST_PROP
- +};
- +
- +static GParamSpec *gParamSpecs [LAST_PROP];
- +
- +/**
- + * ide_vim_parser_settable_set_value:
- + * @self: a #IdeVimParserSettable instance.
- + * @value: a #GValue value.
- + *
- + * Set the settable to a new value.
- + * The #IdeVimParserSettableFunc function is called.
- + *
- + * Returns: TRUE on succes, FALSE otherwise
- + * (wrong Value type or out of bounds value)
- + */
- +gboolean
- +ide_vim_parser_settable_set_value (IdeVimParserSettable *self,
- + GValue *value,
- + IdeVimParserError **error)
- +{
- + IdeVimParserSettableFunc func;
- + g_autofree gchar *msg = NULL;
- + IdeVimParserError *tmp_error = NULL;
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_SETTABLE (self), FALSE);
- +
- + if (!g_param_value_validate (priv->value_spec, value))
- + {
- + func = priv->func;
- + if (!func (self, value, IDE_VIM_PARSER_SETTABLE_OP_SET, &tmp_error))
- + {
- + ide_vim_parser_error_propagate (error, tmp_error);
- + return FALSE;
- + }
- + }
- + else
- + {
- + msg = g_strdup_value_contents (value);
- + ide_vim_parser_error_set (error, IDE_VIM_PARSER_ERROR_SET_VALUE_INVALID, msg);
- + return FALSE;
- + }
- +
- + return TRUE;
- +}
- +
- +/**
- + * ide_vim_parser_settable_reset_value:
- + * @self: a #IdeVimParserSettable instance.
- + *
- + * Reset the settable to its default value.
- + */
- +void
- +ide_vim_parser_settable_reset_value (IdeVimParserSettable *self)
- +{
- + IdeVimParserSettableFunc func;
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +
- + g_return_if_fail (IDE_IS_VIM_PARSER_SETTABLE (self));
- +
- + g_param_value_set_default (priv->value_spec, &priv->value);
- +
- + func = priv->func;
- + func (self, &priv->value, IDE_VIM_PARSER_SETTABLE_OP_RESET, NULL);
- +}
- +
- +/**
- + * ide_vim_parser_settable_get_name:
- + * @self: (in): a #IdeVimParserSettable instance.
- + *
- + * Get the settable name.
- + *
- + * Returns: (transfer none): a string holding the settable name.
- + */
- +const gchar *
- +ide_vim_parser_settable_get_name (IdeVimParserSettable *self)
- +{
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_SETTABLE (self), NULL);
- +
- + return g_param_spec_get_name (priv->value_spec);
- +}
- +
- +/**
- + * ide_vim_parser_settable_get_shortname:
- + * @self: (in): a #IdeVimParserSettable instance.
- + *
- + * Get the settable shortname.
- + *
- + * Returns: (transfer none) (nullable): a string holding the settable shortname.
- + */
- +const gchar *
- +ide_vim_parser_settable_get_shortname (IdeVimParserSettable *self)
- +{
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_SETTABLE (self), NULL);
- +
- + return g_param_spec_get_nick (priv->value_spec);
- +}
- +
- +/**
- + * ide_vim_parser_settable_get_help:
- + * @self: (in): a #IdeVimParserSettable instance.
- + *
- + * Get the settable help string.
- + *
- + * Returns: (transfer none): a string holding the settable help.
- + */
- +const gchar *
- +ide_vim_parser_settable_get_help (IdeVimParserSettable *self)
- +{
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_SETTABLE (self), NULL);
- +
- + return g_param_spec_get_blurb (priv->value_spec);
- +}
- +
- +/**
- + * ide_vim_parser_settable_get_value:
- + * @self: (in): a #IdeVimParserSettable instance.
- + *
- + * Get the settable value.
- + *
- + * Returns: (transfer none): a #GValue holding the settable current value.
- + */
- +const GValue *
- +ide_vim_parser_settable_get_value (IdeVimParserSettable *self)
- +{
- + IdeVimParserSettableFunc func;
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_SETTABLE (self), NULL);
- +
- + func = priv->func;
- + func (self, &priv->value, IDE_VIM_PARSER_SETTABLE_OP_GET, NULL);
- + return &priv->value;
- +}
- +
- +/**
- + * ide_vim_parser_settable_get_default_value:
- + * @self: (in): a #IdeVimParserSettable instance.
- + *
- + * Get the settable default value.
- + *
- + * Returns: (transfer none): a #GValue holding the settable default value.
- + */
- +const GValue *
- +ide_vim_parser_settable_get_default_value (IdeVimParserSettable *self)
- +{
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_SETTABLE (self), NULL);
- +
- + return g_param_spec_get_default_value (priv->value_spec);
- +}
- +
- +static void
- +ide_vim_parser_settable_get_property (GObject *object,
- + guint prop_id,
- + GValue *value,
- + GParamSpec *pspec)
- +{
- + IdeVimParserSettable *self = IDE_VIM_PARSER_SETTABLE (object);
- +
- + switch (prop_id)
- + {
- + case PROP_NAME:
- + g_value_set_string (value, ide_vim_parser_settable_get_name (self));
- + break;
- +
- + case PROP_SHORTNAME:
- + g_value_set_string (value, ide_vim_parser_settable_get_shortname (self));
- + break;
- +
- + case PROP_HELP:
- + g_value_set_string (value, ide_vim_parser_settable_get_help (self));
- + break;
- +
- + case PROP_VALUE:
- + g_value_set_pointer (value, (gpointer)ide_vim_parser_settable_get_value (self));
- + break;
- +
- + case PROP_DEFAULT_VALUE:
- + g_value_set_pointer (value, (gpointer)ide_vim_parser_settable_get_default_value (self));
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_parser_settable_set_property (GObject *object,
- + guint prop_id,
- + const GValue *value,
- + GParamSpec *pspec)
- +{
- + IdeVimParserSettable *self = IDE_VIM_PARSER_SETTABLE (object);
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +
- + switch (prop_id)
- + {
- + case PROP_FUNC:
- + priv->func = g_value_get_pointer (value);
- + break;
- +
- + case PROP_VALUES_FUNC:
- + priv->values_func = g_value_get_pointer (value);
- + break;
- +
- + case PROP_VALUE:
- + /* To be sure value_spec and funcs are set, we finish init in ide_vim_parser_settable_constructed */
- + if (priv->constructed)
- + {
- + ide_vim_parser_settable_set_value (self, g_value_get_pointer (value), NULL);
- + }
- + else
- + {
- + GValue *value_p = g_value_get_pointer (value);
- +
- + g_value_init (&priv->value, G_VALUE_TYPE (value_p));
- + g_value_copy (value_p, &priv->value);
- + }
- + break;
- +
- + case PROP_VALUE_SPEC:
- + priv->value_spec = g_param_spec_ref (g_value_get_param (value));
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_parser_settable_constructed (GObject *object)
- +{
- + IdeVimParserSettable *self = IDE_VIM_PARSER_SETTABLE (object);
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +
- + if (!G_VALUE_HOLDS (&priv->value, G_PARAM_SPEC_VALUE_TYPE(priv->value_spec)))
- + g_critical (_("Error during setting of IdeVimParserSettable value at creation time : wrong type"));
- + else if (!ide_vim_parser_settable_set_value (self, &priv->value, NULL))
- + g_warning (_("Error during setting of IdeVimParserSettable value at creation time : wrong value"));
- +
- + priv->constructed = TRUE;
- +}
- +
- +static void
- +ide_vim_parser_settable_finalize (GObject *object)
- +{
- + IdeVimParserSettable *self = IDE_VIM_PARSER_SETTABLE (object);
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +
- + g_clear_pointer (&priv->value_spec, g_param_spec_unref);
- +
- + G_OBJECT_CLASS (ide_vim_parser_settable_parent_class)->finalize (object);
- +}
- +
- +/**
- + * ide_vim_parser_settable_new:
- + * @g_value_spec:
- + * @g_value:
- + * @func: (scope call): the #IdeVimParserSettableFunc settable function pointer.
- + * @values_func: (scope call)
- + *
- + * Create a new #IdeVimParserSettable settable.
- + *
- + * Returns: (transfer full): A new #IdeVimParserSettable settable.
- + */
- +IdeVimParserSettable *
- +ide_vim_parser_settable_new (GParamSpec *g_value_spec,
- + GValue g_value,
- + IdeVimParserSettableFunc func,
- + IdeVimParserSettableValuesFunc values_func)
- +{
- + g_assert (G_PARAM_SPEC_VALUE_TYPE (g_value_spec) == G_VALUE_TYPE (&g_value));
- +
- + return g_object_new (IDE_TYPE_VIM_PARSER_SETTABLE,
- + "value-spec", g_value_spec,
- + "value", &g_value,
- + "func", func,
- + "values-func", values_func,
- + NULL);
- +}
- +
- +/**
- + * ide_vim_parser_settable_boolean_new:
- + * @name: the settable name.
- + * @shortname: the settable shortname.
- + * @help:
- + * @value:
- + * @default_value:
- + * @func: (scope call): the #IdeVimParserSettableFunc settable function pointer.
- + * @values_func: (scope call)
- + *
- + * Create a new #IdeVimParserSettable boolean settable.
- + *
- + * Returns: (transfer full): A new #IdeVimParserSettable boolean settable.
- + */
- +IdeVimParserSettable *
- +ide_vim_parser_settable_boolean_new (const gchar *name,
- + const gchar *shortname,
- + const gchar *help,
- + gboolean value,
- + gboolean default_value,
- + IdeVimParserSettableFunc func,
- + IdeVimParserSettableValuesFunc values_func)
- +{
- + GParamSpec *g_value_spec;
- + GValue g_value = G_VALUE_INIT;
- +
- + g_value_init (&g_value, G_TYPE_BOOLEAN);
- + g_value_set_boolean (&g_value, value);
- +
- + g_value_spec = g_param_spec_boolean (name, shortname, help, default_value,
- + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- +
- + return ide_vim_parser_settable_new (g_value_spec, g_value, func, values_func);
- +}
- +
- +/**
- + * ide_vim_parser_settable_integer_new:
- + * @name: the settable name.
- + * @shortname: the settable shortname.
- + * @help:
- + * @value:
- + * @default_value:
- + * @func: (scope call): the #IdeVimParserSettableFunc settable function pointer.
- + * @values_func: (scope call)
- + *
- + * Create a new #IdeVimParserSettable integer settable.
- + *
- + * Returns: (transfer full): A new #IdeVimParserSettable integer settable.
- + */
- +IdeVimParserSettable *
- +ide_vim_parser_settable_integer_new (const gchar *name,
- + const gchar *shortname,
- + const gchar *help,
- + gint value,
- + gint default_value,
- + gint minimum,
- + gint maximum,
- + IdeVimParserSettableFunc func,
- + IdeVimParserSettableValuesFunc values_func)
- +{
- + GParamSpec *g_value_spec;
- + GValue g_value = G_VALUE_INIT;
- +
- + g_value_init (&g_value, G_TYPE_INT64);
- + g_value_set_int64 (&g_value, value);
- +
- + g_value_spec = g_param_spec_int64 (name, shortname, help, minimum, maximum, default_value,
- + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- +
- + return ide_vim_parser_settable_new (g_value_spec, g_value, func, values_func);
- +}
- +
- +/**
- + * ide_vim_parser_settable_string_new:
- + * @name: the settable name.
- + * @shortname: the settable shortname.
- + * @help:
- + * @value:
- + * @default_value:
- + * @func: (scope call): the #IdeVimParserSettableFunc settable function pointer.
- + * @values_func: (scope call)
- + *
- + * Create a new #IdeVimParserSettable string settable.
- + *
- + * Returns: (transfer full): A new #IdeVimParserSettable string settable.
- + */
- +IdeVimParserSettable *
- +ide_vim_parser_settable_string_new (const gchar *name,
- + const gchar *shortname,
- + const gchar *help,
- + const gchar *value,
- + const gchar *default_value,
- + IdeVimParserSettableFunc func,
- + IdeVimParserSettableValuesFunc values_func)
- +{
- + GParamSpec *g_value_spec;
- + GValue g_value = G_VALUE_INIT;
- +
- + g_value_init (&g_value, G_TYPE_STRING);
- + g_value_set_string (&g_value, value);
- +
- + g_value_spec = g_param_spec_string (name, shortname, help, default_value,
- + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- +
- + return ide_vim_parser_settable_new (g_value_spec, g_value, func, values_func);
- +}
- +
- +static void
- +ide_vim_parser_settable_init (IdeVimParserSettable *self)
- +{
- + IdeVimParserSettablePrivate *priv = ide_vim_parser_settable_get_instance_private (self);
- +}
- +
- +static void
- +ide_vim_parser_settable_class_init (IdeVimParserSettableClass *klass)
- +{
- + GObjectClass *object_class = G_OBJECT_CLASS (klass);
- +
- + object_class->constructed = ide_vim_parser_settable_constructed;
- + object_class->finalize = ide_vim_parser_settable_finalize;
- + object_class->get_property = ide_vim_parser_settable_get_property;
- + object_class->set_property = ide_vim_parser_settable_set_property;
- +
- + /**
- + * IdeVimParserSettable:func:
- + *
- + * A IdeVimParserSettableFunc pointer to the function use to execute the settable.
- + *
- + */
- + gParamSpecs[PROP_FUNC] =
- + g_param_spec_pointer ("func",
- + _("Settable function pointer"),
- + _("A pointer to the settable function."),
- + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserSettable:values-func:
- + *
- + * A IdeVimParserSettableValuesFunc pointer to the function use to collect the possibles values of the settable.
- + *
- + */
- + gParamSpecs[PROP_VALUES_FUNC] =
- + g_param_spec_pointer ("values-func",
- + _("Settable collect values function pointer"),
- + _("A pointer to the settable collect values function."),
- + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserSettable:name:
- + *
- + * A string holding the name of the settable.
- + */
- + gParamSpecs[PROP_NAME] =
- + g_param_spec_string ("name",
- + _("Settable name"),
- + _("The name of the settable."),
- + NULL,
- + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserSettable:shortname:
- + *
- + * A string holding the shortname of the settable.
- + */
- + gParamSpecs[PROP_SHORTNAME] =
- + g_param_spec_string ("shortname",
- + _("Settable shortname"),
- + _("The shortname of the settable."),
- + NULL,
- + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserSettable:help:
- + *
- + * A string holding the help text of the settable.
- + */
- + gParamSpecs[PROP_HELP] =
- + g_param_spec_string ("help",
- + _("Settable help text"),
- + _("The help text of the settable."),
- + NULL,
- + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserSettable:value-spec:
- + *
- + * A #GParamSpec holding the spec of the settable value.
- + */
- + gParamSpecs[PROP_VALUE_SPEC] =
- + g_param_spec_param ("value-spec",
- + _("Settable GParamSpec"),
- + _("The settable GParamSpec."),
- + G_TYPE_PARAM,
- + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserSettable:value:
- + *
- + * A #GValue holding the value of the settable.
- + */
- + gParamSpecs[PROP_VALUE] =
- + g_param_spec_pointer ("value",
- + _("Settable value"),
- + _("The value of the settable."),
- + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimParserSettable:default-value:
- + *
- + * A #GValue holding the default value of the settable.
- + */
- + gParamSpecs[PROP_DEFAULT_VALUE] =
- + g_param_spec_pointer ("default-value",
- + _("Settable default value"),
- + _("The default value of the settable."),
- + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- +
- + g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
- +}
- diff --git a/libide/vim/ide-vim-parser-settable.h b/libide/vim/ide-vim-parser-settable.h
- new file mode 100644
- index 0000000..483c6dd
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-settable.h
- @@ -0,0 +1,93 @@
- +/* ide-vim-parser-settable.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_PARSER_SETTABLE_H
- +#define IDE_VIM_PARSER_SETTABLE_H
- +
- +#include <glib.h>
- +
- +#include "ide-vim-parser-error.h"
- +
- +G_BEGIN_DECLS
- +
- +#define IDE_TYPE_VIM_PARSER_SETTABLE (ide_vim_parser_settable_get_type())
- +
- +G_DECLARE_FINAL_TYPE (IdeVimParserSettable, ide_vim_parser_settable, IDE, VIM_PARSER_SETTABLE, GObject)
- +
- +struct _IdeVimParserSettable
- +{
- + GObject parent;
- +};
- +
- +typedef enum
- +{
- + IDE_VIM_PARSER_SETTABLE_OP_SET,
- + IDE_VIM_PARSER_SETTABLE_OP_GET,
- + IDE_VIM_PARSER_SETTABLE_OP_RESET
- +} IdeVimParserSettableOp;
- +
- +typedef gboolean (*IdeVimParserSettableFunc) (IdeVimParserSettable *settable,
- + GValue *value,
- + IdeVimParserSettableOp op,
- + IdeVimParserError **error);
- +
- +typedef GArray * (*IdeVimParserSettableValuesFunc) (IdeVimParserSettable *settable,
- + IdeVimParserError **error);
- +
- +const gchar *ide_vim_parser_settable_get_help (IdeVimParserSettable *self);
- +const gchar *ide_vim_parser_settable_get_name (IdeVimParserSettable *self);
- +const gchar *ide_vim_parser_settable_get_shortname (IdeVimParserSettable *self);
- +const GValue *ide_vim_parser_settable_get_value (IdeVimParserSettable *self);
- +const GValue *ide_vim_parser_settable_get_default_value (IdeVimParserSettable *self);
- +
- +gboolean ide_vim_parser_settable_set_value (IdeVimParserSettable *self,
- + GValue *value,
- + IdeVimParserError **error);
- +void ide_vim_parser_settable_reset_value (IdeVimParserSettable *self);
- +
- +IdeVimParserSettable *ide_vim_parser_settable_new (GParamSpec *g_value_spec,
- + GValue g_value,
- + IdeVimParserSettableFunc func,
- + IdeVimParserSettableValuesFunc values_func);
- +IdeVimParserSettable *ide_vim_parser_settable_boolean_new (const gchar *name,
- + const gchar *shortname,
- + const gchar *help,
- + gboolean value,
- + gboolean default_value,
- + IdeVimParserSettableFunc func,
- + IdeVimParserSettableValuesFunc values_func);
- +IdeVimParserSettable *ide_vim_parser_settable_integer_new (const gchar *name,
- + const gchar *shortname,
- + const gchar *help,
- + gint value,
- + gint default_value,
- + gint minimum,
- + gint maximum,
- + IdeVimParserSettableFunc func,
- + IdeVimParserSettableValuesFunc values_func);
- +IdeVimParserSettable *ide_vim_parser_settable_string_new (const gchar *name,
- + const gchar *shortname,
- + const gchar *help,
- + const gchar *value,
- + const gchar *default_value,
- + IdeVimParserSettableFunc func,
- + IdeVimParserSettableValuesFunc values_func);
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_PARSER_SETTABLE_H */
- diff --git a/libide/vim/ide-vim-parser-token.c b/libide/vim/ide-vim-parser-token.c
- new file mode 100644
- index 0000000..94ad3dd
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-token.c
- @@ -0,0 +1,124 @@
- +/* ide-vim-parser-token.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <string.h>
- +#include <errno.h>
- +#include <glib/gi18n.h>
- +#include <glib/gprintf.h>
- +
- +#include "ide-debug.h"
- +#include "ide-macros.h"
- +
- +#include "ide-vim-parser-token.h"
- +
- +G_DEFINE_BOXED_TYPE (IdeVimParserToken, ide_vim_parser_token, ide_vim_parser_token_ref, ide_vim_parser_token_unref)
- +
- +const gchar *
- +ide_vim_parser_token_get_content (IdeVimParserToken *token)
- +{
- + return token->content;
- +}
- +
- +static gchar *token_kind_name [] =
- +{
- + "UNKNOW",
- + "COMMAND_NAME",
- + "END OF STRING",
- + "MARK",
- + "NUMBER",
- + "PATTERN",
- + "RANGE",
- + "RANGE SEPARATOR",
- + "RANGE SPECIFIER",
- + "REGISTER",
- + "STRING",
- + "PATH",
- + "SET ARGUMENT"
- +};
- +
- +const gchar *
- +ide_vim_parser_token_get_kind_name (IdeVimParserToken *token)
- +{
- + return token_kind_name [token->kind];
- +}
- +
- +const gchar *
- +ide_vim_parser_token_kind_get_name (IdeVimParserTokenKind kind)
- +{
- + return token_kind_name [kind];
- +}
- +
- +static void
- +ide_vim_parser_token_finalize (IdeVimParserToken *self)
- +{
- + g_clear_pointer (&self->content, g_free);
- + g_free (self);
- +}
- +
- +/**
- + * ide_vim_parser_token_ref:
- + * @self: (in): An #IdeVimParserToken instance.
- + *
- + * Increment #IdeVimParserToken ref count.
- + *
- + * Returns: (transfer none): a #IdeVimParserToken ref.
- + */
- +IdeVimParserToken *
- +ide_vim_parser_token_ref (IdeVimParserToken *self)
- +{
- + g_return_val_if_fail (self, NULL);
- + g_return_val_if_fail (self->ref_count > 0, NULL);
- +
- + g_atomic_int_inc (&self->ref_count);
- +
- + return self;
- +}
- +
- +/**
- + * ide_vim_parser_token_unref:
- + * @self: (in): #IdeVimParserToken instance.
- + *
- + * Decrement #IdeVimParserToken ref count.
- + */
- +void
- +ide_vim_parser_token_unref (IdeVimParserToken *self)
- +{
- + g_return_if_fail (self);
- + g_return_if_fail (self->ref_count > 0);
- +
- + if (g_atomic_int_dec_and_test (&self->ref_count))
- + ide_vim_parser_token_finalize (self);
- +}
- +
- +/**
- + * ide_vim_parser_token_new:
- + *
- + * Return a new #IdeVimParserToken instance.
- + *
- + * Returns: (transfer full) (skip): A new #IdeVimParserToken.
- + */
- +IdeVimParserToken *
- +ide_vim_parser_token_new (void)
- +{
- + IdeVimParserToken *self;
- +
- + self = g_new0 (IdeVimParserToken, 1);
- + self->ref_count = 1;
- +
- + return self;
- +}
- diff --git a/libide/vim/ide-vim-parser-token.h b/libide/vim/ide-vim-parser-token.h
- new file mode 100644
- index 0000000..1c78ac3
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-token.h
- @@ -0,0 +1,92 @@
- +/* ide-vim-parser-token.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_PARSER_TOKEN_H
- +#define IDE_VIM_PARSER_TOKEN_H
- +
- +#include <glib-object.h>
- +
- +G_BEGIN_DECLS
- +
- +#define IDE_TYPE_VIM_PARSER_TOKEN (ide_vim_parser_token_get_type())
- +
- +typedef struct _IdeVimParserCommand IdeVimParserCommand;
- +
- +typedef enum _IdeVimParserTokenKind
- +{
- + IDE_VIM_PARSER_TOKEN_UNKNOW,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME,
- + IDE_VIM_PARSER_TOKEN_END_OF_STRING,
- + IDE_VIM_PARSER_TOKEN_MARK,
- + IDE_VIM_PARSER_TOKEN_NUMBER,
- + IDE_VIM_PARSER_TOKEN_PATTERN,
- + IDE_VIM_PARSER_TOKEN_RANGE,
- + IDE_VIM_PARSER_TOKEN_RANGE_SEPARATOR,
- + IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER,
- + IDE_VIM_PARSER_TOKEN_REGISTER,
- + IDE_VIM_PARSER_TOKEN_STRING,
- + IDE_VIM_PARSER_TOKEN_PATH,
- + IDE_VIM_PARSER_TOKEN_SET_ARG
- +} IdeVimParserTokenKind;
- +
- +typedef enum _IdeVimParserTokenFlag
- +{
- + /* Don't use value 0, it's used for error checking */
- + IDE_VIM_PARSER_TOKEN_FLAG_NONE = 1,
- + /* FIXME: optional, one n */
- + IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- +} IdeVimParserTokenFlag;
- +
- +/* TODO: drop error and use return status ? */
- +typedef enum _IdeVimParserTokenError
- +{
- + IDE_VIM_PARSER_TOKEN_ERROR_NO_ERROR,
- + IDE_VIM_PARSER_TOKEN_ERROR_INCOMPLETE,
- + IDE_VIM_PARSER_TOKEN_ERROR_WRONG_KIND
- +} IdeVimParserTokenError;
- +
- +struct _IdeVimParserToken
- +{
- + volatile gint ref_count;
- +
- + IdeVimParserTokenKind kind;
- + IdeVimParserTokenFlag flag;
- + //IdeVimParserTokenError error;
- + const gchar *content;
- + gint number;
- + gint range_start;
- + gint range_end;
- + IdeVimParserCommand *command_entry;
- + gchar pattern_type;
- + gboolean command_has_bang : 1;
- + gboolean range_is_native : 1;
- + gboolean is_set : 1;
- +};
- +
- +typedef struct _IdeVimParserToken IdeVimParserToken;
- +
- +const gchar *ide_vim_parser_token_get_content (IdeVimParserToken *token);
- +const gchar *ide_vim_parser_token_get_kind_name (IdeVimParserToken *token);
- +const gchar *ide_vim_parser_token_kind_get_name (IdeVimParserTokenKind kind);
- +IdeVimParserToken *ide_vim_parser_token_new (void);
- +IdeVimParserToken *ide_vim_parser_token_ref (IdeVimParserToken *self);
- +void ide_vim_parser_token_unref (IdeVimParserToken *self);
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_PARSER_TOKEN_H */
- diff --git a/libide/vim/ide-vim-parser-types.h b/libide/vim/ide-vim-parser-types.h
- new file mode 100644
- index 0000000..db5f14c
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser-types.h
- @@ -0,0 +1,28 @@
- +/* ide-vim-parser-types.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_PARSER_TYPES_H
- +#define IDE_VIM_PARSER_TYPES_H
- +
- +#include <glib.h>
- +
- +G_BEGIN_DECLS
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_PARSER_TYPES_H */
- diff --git a/libide/vim/ide-vim-parser.c b/libide/vim/ide-vim-parser.c
- new file mode 100644
- index 0000000..cc192f5
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser.c
- @@ -0,0 +1,1926 @@
- +/* ide-vim-parser.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#define G_LOG_DOMAIN "ide-vim-parser"
- +
- +#include <string.h>
- +#include <stdio.h>
- +#include <errno.h>
- +
- +#include <glib/gi18n.h>
- +#include <glib/gprintf.h>
- +#include <gtksourceview/gtksource.h>
- +
- +#include "ide-debug.h"
- +#include "ide-macros.h"
- +
- +#include "ide-vim-parser.h"
- +#include "ide-vim-parser-private.h"
- +#include "ide-vim-parser-debug.h"
- +#include "ide-vim-parser-objects-pool.h"
- +#include "ide-vim-parser-error.h"
- +
- +#pragma GCC diagnostic push
- +#pragma GCC diagnostic ignored "-Wswitch-enum"
- +
- +typedef struct
- +{
- + IdeVimParserObjectsPool *objects_pool;
- + IdeVimStateMachine *machine;
- + GQueue *stack;
- + IdeVimParserInfo *info;
- +
- +} IdeVimParserPrivate;
- +
- +G_DEFINE_TYPE_WITH_PRIVATE (IdeVimParser, ide_vim_parser, G_TYPE_OBJECT)
- +
- +enum {
- + PROP_0,
- + LAST_PROP
- +};
- +
- +static GParamSpec *gParamSpecs [LAST_PROP];
- +
- +#define ide_vim_str_equal0(s1,s2) \
- + (((s1) == (s2)) || ((s1) && (s2) && g_str_equal(s1,s2)))
- +
- +#define BUFFER_TO_VIM_LINE_COORDS (1)
- +#define VALUE_NOT_SET (-1)
- +
- +static gint
- +_ide_vim_parser_add_command_entry (IdeVimParser *self,
- + const gchar *name,
- + const gchar *shortname,
- + IdeVimParserCommandFunc func,
- + IdeVimParserCommand **command_entry)
- +{
- + IdeVimParserPrivate *priv = ide_vim_parser_get_instance_private (self);
- + IdeVimParserCommand *entry;
- +
- + entry = g_object_new (IDE_TYPE_VIM_PARSER_COMMAND,
- + "name", name,
- + "shortname", shortname,
- + "func", func,
- + NULL);
- +
- + ide_vim_parser_objects_pool_add_command (priv->objects_pool, entry, TRUE);
- + *command_entry = entry;
- +
- + return ide_vim_parser_command_get_id (entry);
- +}
- +
- +/* TODO: Add a _v() function for introspection */
- +
- +/**
- + * ide_vim_parser_add_command:
- + * @self: (in): a #IdeVimParser instance.
- + * @name: (in): the name of the command to add.
- + * @shortname: (in) (nullable): the shortname of the command, must be null
- + * or a prefix of the command.
- + * @func: (in) (skip): a #IdeVimParserCommand command function.
- + * @...: (in) (nullable): a succession of #IdeVimParserTokenKind and #IdeVimParserTokenFlag,
- + * ended by 0 to describe the command arguments.
- + *
- + * Add a command to the parser :
- + *
- + * the variadic list is a sequence of
- + * IdeVimParserTokenKind, IdeVimParserTokenFlags
- + * pairs, ended with 0.
- + *
- + * A command with a name already registred replace the old command
- + *
- + * Returns: id of the command
- + */
- +gint
- +ide_vim_parser_add_command (IdeVimParser *self,
- + const gchar *name,
- + const gchar *shortname,
- + IdeVimParserCommandFunc func,
- + ...)
- +{
- + IdeVimParserPrivate *priv = ide_vim_parser_get_instance_private (self);
- + va_list args;
- + IdeVimParserCommand *command_entry;
- + gint command_id;
- + IdeVimParserTokenKind kind;
- + IdeVimParserTokenFlag flag;
- + gint nb_args = 0;
- + gint name_arg_count = 0;
- +
- + g_assert (IDE_IS_VIM_PARSER (self));
- + g_return_val_if_fail (!ide_str_empty0 (name), 0);
- + g_return_val_if_fail (func != NULL, 0);
- +
- + command_id = _ide_vim_parser_add_command_entry (self, name, shortname, func, &command_entry);
- +
- + va_start(args, func);
- +
- + while ((kind = va_arg(args, gint)) != 0)
- + {
- + if ((flag = va_arg(args, gint)) != 0)
- + {
- + ++nb_args;
- + if (kind == IDE_VIM_PARSER_TOKEN_COMMAND_NAME)
- + {
- + ++name_arg_count;
- + if (name_arg_count > 1)
- + {
- + g_critical ("Wrong entry format: one and only one argument must be of type command_name");
- + goto error;
- + }
- + }
- +
- + ide_vim_parser_command_add_arg (command_entry, kind, flag);
- + continue;
- + }
- +
- + g_critical ("Wrong entry format: a flag is missing");
- + goto error;
- + }
- +
- + va_end(args);
- +
- + if (nb_args == 0)
- + {
- + g_critical ("Wrong entry format: no arguments");
- + goto error;
- + }
- +
- + return command_id;
- +
- +error:
- + ide_vim_parser_objects_pool_remove_command (priv->objects_pool, name);
- + return 0;
- +}
- +
- +static gchar *
- +get_last_word (const gchar *str)
- +{
- + const gchar *str_end;
- + const gchar *cursor;
- + const gchar *prev;
- + gint len;
- +
- + if (ide_str_empty0 (str))
- + return NULL;
- +
- + prev = cursor = str_end = str + strlen (str);
- + while ((cursor = g_utf8_find_prev_char (str, cursor)))
- + {
- + if (g_unichar_isspace (g_utf8_get_char (cursor)))
- + break;
- +
- + prev = cursor;
- + }
- +
- + if (cursor == NULL)
- + return g_strdup (str);
- +
- + len = str_end - prev;
- + if (len == 0)
- + return NULL;
- +
- + return g_strndup (prev, len);
- +}
- +
- +/**
- + * ide_vim_parser_complete:
- + * @self: (in): a #IdeVimParser instance.
- + * @match_name: (in) (nullable): a prefix for the items to find.
- + *
- + * Return all the items matching match_name:
- + * This can be commands, set command variables, colorscheme names
- + * or paths used with file commands.
- + *
- + * Returns: (transfer container) (nullable) (element-type IdeVimCompleteItem)
- + * A GPtrArray of #IdeVimCompleteItem items matching match_name.
- + */
- +GPtrArray *
- +ide_vim_parser_complete (IdeVimParser *self,
- + GtkTextBuffer *buffer,
- + const gchar *match_name)
- +{
- + IdeVimParserPrivate *priv;
- + IdeVimParserCommand *command = NULL;
- + IdeVimParserError *tmp_error = NULL;
- + const IdeVimParserInfo *info;
- + GPtrArray *ar;
- + const gchar *match_word = NULL;
- +
- + g_assert (IDE_IS_VIM_PARSER (self));
- +
- + priv = ide_vim_parser_get_instance_private (self);
- + ar = g_ptr_array_new_full (32, g_object_unref);
- +
- + /* TODO: parse to find command
- + if (ide_str_equal0 (name, "set"))
- + {
- + g_printf ("not implemented yet\n");
- + return NULL;
- + }
- +
- + if (ide_str_equal0 (name, "colorscheme"))
- + {
- + g_printf ("not implemented yet\n");
- + return NULL;
- + }
- +
- + if (ide_str_equal0 (name, "edit"))
- + {
- + g_printf ("not implemented yet\n");
- + return NULL;
- + }
- + */
- +
- + //match_word = get_last_word (match_name);
- + if (!ide_str_empty0 (match_name))
- + {
- + command = ide_vim_parser_parse (self, buffer, match_name, &tmp_error);
- + info = ide_vim_parser_get_info (self);
- + if (command != NULL)
- + {
- + g_printf ("No parsing Error\n");
- + ide_vim_parser_debug_show_parsed (command);
- + //ide_vim_parser_error_propagate (error, tmp_error);
- + g_ptr_array_free (ar, TRUE);
- + ar = NULL;
- + }
- + else if (info->last_token_kind == IDE_VIM_PARSER_TOKEN_STRING)
- + {
- + match_word = info->last_token_content;
- + }
- + }
- +
- + g_printf ("match word:%s\n", match_word);
- + if (!ide_vim_parser_objects_pool_complete_command (priv->objects_pool, ar, match_word))
- + {
- + g_ptr_array_free (ar, TRUE);
- + ar = NULL;
- + }
- +
- + return ar;
- +}
- +
- +static gboolean
- +token_range_resolve_mark (IdeVimParserContext *context,
- + IdeVimParserToken *token,
- + gint *line)
- +{
- + g_printf ("not implemented yet\n");
- + return FALSE;
- +}
- +
- +static gboolean
- +token_range_resolve_pattern (IdeVimParserContext *context,
- + IdeVimParserToken *token,
- + gint start_line,
- + gint *end_of_pattern_line)
- +{
- + GtkSourceSearchContext *search_context;
- + GtkSourceSearchSettings *search_settings;
- + g_autofree gchar *content;
- + GtkTextIter begin;
- + GtkTextIter match_begin;
- + GtkTextIter match_end;
- + gint len;
- + gboolean ret;
- +
- + len = strlen (token->content);
- + g_assert (len >= 2);
- +
- + if (len == 2)
- + {
- + /*TODO: get previous pattern */
- + }
- +
- + content = g_strndup (token->content + 1, len - 1);
- +
- + search_settings = gtk_source_search_settings_new ();
- + gtk_source_search_settings_set_search_text (search_settings, content);
- + gtk_source_search_settings_set_case_sensitive (search_settings, TRUE);
- + gtk_source_search_settings_set_regex_enabled (search_settings, TRUE);
- +
- + /* TODO: handle wrap around ? */
- + gtk_text_buffer_get_iter_at_line (context->buffer, &begin, start_line);
- +
- + search_context = gtk_source_search_context_new (GTK_SOURCE_BUFFER (context->buffer), search_settings);
- + gtk_source_search_context_set_highlight (search_context, FALSE);
- +
- + if (token->pattern_type == '/')
- + ret = gtk_source_search_context_forward (search_context, &begin, &match_begin, &match_end);
- + else
- + ret = gtk_source_search_context_backward (search_context, &begin, &match_begin, &match_end);
- +
- + g_clear_object (&search_settings);
- + g_clear_object (&search_context);
- +
- + if (ret)
- + *end_of_pattern_line = gtk_text_iter_get_line (&match_end) + BUFFER_TO_VIM_LINE_COORDS;
- +
- + return ret;
- +}
- +
- +static gboolean
- +token_range_resolve_specifier (IdeVimParserContext *context,
- + IdeVimParserToken *token,
- + gint *line_start,
- + gint *line_end)
- +{
- + const gchar *content = token->content;
- +
- + g_assert (line_start !=NULL);
- + g_assert (line_end !=NULL);
- + g_assert (!ide_str_empty0 (content));
- +
- + if (ide_str_equal0 (content, "."))
- + {
- + *line_start = context->insert_line;
- + }
- + else if (ide_str_equal0 (content, "$"))
- + {
- + *line_start = context->end_line;
- + }
- + else if (ide_str_equal0 (content, "%"))
- + {
- + *line_start = 1;
- + *line_end = context->end_line;
- + }
- + else if (ide_str_equal0 (content, "\\/"))
- + {
- + /* TODO: get from previous search forward */
- + g_printf ("not implemented yet\n");
- + }
- + else if (ide_str_equal0 (content, "\\?"))
- + {
- + /* TODO: get from previous search backward */
- + g_printf ("not implemented yet\n");
- + }
- + else if (ide_str_equal0 (content, "\\&"))
- + {
- + /* TODO: get from previous substitute forward */
- + g_printf ("not implemented yet\n");
- + }
- +
- + return TRUE;
- +}
- +
- +/* Line values are resolved in term of Vim coordinates,
- + * so that lines begin at 1 but as the work always start
- + * on the next line, 0 can be use to take line 1 into account.
- + * -1 is used for not set values. */
- +static gboolean
- +token_range_resolve (IdeVimParserContext *context,
- + IdeVimParserToken *token)
- +{
- + gint line_start = VALUE_NOT_SET;
- + gint line_end = VALUE_NOT_SET;
- + gint begin_line = 0;
- + gboolean ret = FALSE;
- +
- + g_assert (context !=NULL);
- + g_assert (token !=NULL);
- +
- + switch (token->kind)
- + {
- + case IDE_VIM_PARSER_TOKEN_MARK:
- + ret = token_range_resolve_mark (context, token, &line_start);
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_NUMBER:
- + line_start = token->number;
- + ret = TRUE;
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_PATTERN:
- + if (context->previous_token_is_separator)
- + begin_line = context->insert_line;
- + else
- + begin_line = context->range_end_line;
- +
- + ret = token_range_resolve_pattern (context, token, begin_line, &line_start);
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER:
- + ret = token_range_resolve_specifier (context, token, &line_start, &line_end);
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_RANGE_SEPARATOR:
- + if (context->previous_token_is_separator)
- + return FALSE;
- +
- + context->previous_token_is_separator = TRUE;
- + if (*token->content == ';' && context->range_end_line != VALUE_NOT_SET)
- + context->insert_line += context->range_end_line;
- +
- + context->range_start_line = context->range_end_line;
- + context->range_end_line = VALUE_NOT_SET;
- + return TRUE;
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_UNKNOW:
- + case IDE_VIM_PARSER_TOKEN_COMMAND_NAME:
- + case IDE_VIM_PARSER_TOKEN_END_OF_STRING:
- + case IDE_VIM_PARSER_TOKEN_RANGE:
- + case IDE_VIM_PARSER_TOKEN_REGISTER:
- + case IDE_VIM_PARSER_TOKEN_STRING:
- + context->range_start_line = VALUE_NOT_SET;
- + context->range_end_line = VALUE_NOT_SET;
- + ret = FALSE;
- + break;
- +
- + default:
- + g_assert_not_reached ();
- + break;
- + }
- +
- + if (line_end != VALUE_NOT_SET)
- + {
- + context->range_start_line = line_start;
- + context->range_end_line = line_end;
- + }
- + else if (line_start != VALUE_NOT_SET)
- + {
- + if (context->range_end_line != VALUE_NOT_SET)
- + context->range_end_line += line_start;
- + else
- + context->range_end_line = line_start;
- + }
- +
- + context->previous_token_is_separator = FALSE;
- + return ret;
- +}
- +
- +static gboolean
- +token_check_rules (IdeVimParserContext *context,
- + IdeVimParserToken *new_token)
- +{
- + GQueue *stack;
- + IdeVimParserTokenKind previous_kind;
- + IdeVimParserTokenKind new_kind;
- + IdeVimParserToken *previous_token;
- +
- + stack = context->stack;
- + previous_token = g_queue_peek_head (stack);
- + if (previous_token == NULL)
- + return TRUE;
- +
- + previous_kind = previous_token->kind;
- + new_kind = new_token->kind;
- +
- + /* In addition to the registered command arguments, these rules
- + * help catching errors before finding a command name.
- + */
- +
- + /* A mark must be at the start of the command line or preceded by a range separator or a command name */
- + if (new_kind == IDE_VIM_PARSER_TOKEN_MARK &&
- + !(context->previous_token_is_separator || previous_kind == IDE_VIM_PARSER_TOKEN_COMMAND_NAME))
- + return FALSE;
- +
- + /* A number can't be preceded by a register */
- + if (new_kind == IDE_VIM_PARSER_TOKEN_NUMBER && previous_kind == IDE_VIM_PARSER_TOKEN_REGISTER)
- + return FALSE;
- +
- + /* A pattern can't be preceded by a register */
- + if (new_kind == IDE_VIM_PARSER_TOKEN_PATTERN && previous_kind == IDE_VIM_PARSER_TOKEN_REGISTER)
- + return FALSE;
- +
- + /* A range specifier must be at the start of the command line or preceded by a range separator */
- + if (new_kind == IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER && !context->previous_token_is_separator)
- + return FALSE;
- +
- + /* A register can only be preceded by a command name */
- + if (new_kind == IDE_VIM_PARSER_TOKEN_REGISTER && !(previous_kind == IDE_VIM_PARSER_TOKEN_COMMAND_NAME))
- + return FALSE;
- +
- + /* TODO: new rule: no more than one successive separator
- + * see and fix token_range_resolve*/
- +
- + return TRUE;
- +}
- +
- +static gboolean
- +token_range_try_compact (IdeVimParserContext *context,
- + IdeVimParserToken *new_token)
- +{
- + GQueue *stack;
- + IdeVimParserTokenKind previous_kind;
- + IdeVimParserTokenKind new_kind;
- + IdeVimParserToken *previous_token;
- + IdeVimParserToken *token;
- + gboolean previous_eligible;
- + gboolean new_eligible;
- +
- + stack = context->stack;
- + previous_token = g_queue_peek_head (stack);
- + if (previous_token == NULL)
- + return FALSE;
- +
- + previous_kind = previous_token->kind;
- + new_kind = new_token->kind;
- +
- + previous_eligible = (previous_kind == IDE_VIM_PARSER_TOKEN_MARK ||
- + previous_kind == IDE_VIM_PARSER_TOKEN_NUMBER ||
- + previous_kind == IDE_VIM_PARSER_TOKEN_PATTERN ||
- + previous_kind == IDE_VIM_PARSER_TOKEN_RANGE ||
- + previous_kind == IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER);
- +
- + new_eligible = (new_kind == IDE_VIM_PARSER_TOKEN_MARK ||
- + new_kind == IDE_VIM_PARSER_TOKEN_NUMBER ||
- + new_kind == IDE_VIM_PARSER_TOKEN_PATTERN ||
- + new_kind == IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER);
- +
- + if (previous_eligible && new_eligible)
- + {
- + token = ide_vim_parser_token_new ();
- +
- + token->kind = IDE_VIM_PARSER_TOKEN_RANGE;
- + /* TODO: we miss the separator in the content string ? */
- + token->content = g_strconcat (previous_token->content, " ", new_token->content, NULL);
- + token->range_start = context->range_start_line;
- + token->range_end = context->range_end_line;
- +
- + g_printf ("=> Stack Compaction: %s + %s = %s\n",
- + ide_vim_parser_token_get_kind_name (previous_token),
- + ide_vim_parser_token_get_kind_name (new_token),
- + ide_vim_parser_token_get_kind_name (token));
- +
- + ide_vim_parser_token_unref (g_queue_pop_head (stack));
- + g_queue_push_head (stack, token);
- +
- + return TRUE;
- + }
- +
- + return FALSE;
- +}
- +
- +/* TODO: handle errors */
- +static gboolean
- +ide_vim_parser_push_to_stack (IdeVimParserContext *context,
- + IdeVimParserToken *token)
- +{
- + IdeVimParserPrivate *parser_priv = ide_vim_parser_get_instance_private (context->parser);
- + IdeVimParserInfo *info = parser_priv->info;
- +
- + info->last_token_kind = token->kind;
- + if (token->content)
- + info->last_token_content = strdup (token->content);
- +
- + if (!token_check_rules (context, token))
- + {
- + /* TODO: free context->token or later ? */
- + /* error code and update info ? */
- + return FALSE;
- + }
- +
- + token_range_resolve (context, token);
- +
- + if (token_range_try_compact (context, token))
- + g_clear_pointer (&context->token, ide_vim_parser_token_unref);
- + else if (token->kind != IDE_VIM_PARSER_TOKEN_RANGE_SEPARATOR)
- + g_queue_push_head (context->stack, token);
- +
- + info->last_good_token_kind = token->kind;
- + return TRUE;
- +}
- +
- +/* get char at *ptr */
- +static inline gchar
- +get_char (const gchar **ptr)
- +{
- + return **ptr;
- +}
- +
- +/* move *ptr to next char then return it.
- + * If the current char == 0 then *ptr don't move
- + */
- +static inline gchar
- +get_next_char (const gchar **ptr)
- +{
- + if (get_char (ptr))
- + (*ptr)++;
- +
- + return **ptr;
- +}
- +
- +/* get char at *ptr and move next char, unless char == 0 */
- +static inline gchar
- +get_char_and_forward (const gchar **ptr)
- +{
- + gchar c = get_char (ptr);
- +
- + if (c)
- + (*ptr)++;
- +
- + return c;
- +}
- +
- +/* Skip spaces and return the first char after */
- +static gchar
- +skip_spaces (const gchar **ptr)
- +{
- + gchar c = get_char (ptr);
- +
- + while (g_ascii_isspace(c))
- + {
- + c = get_next_char (ptr);
- + };
- +
- + return c;
- +}
- +
- +/* Skip all up to a space. An escaped space is also skiped.
- + * We return in case of a space at the start of the string,
- + * so that you should perhaps g_strchug your string before.
- + * We also return if we reach the end of the string ( \0 ).
- + * Update *ptr to the new position and return the char it point to */
- +static gchar
- +skip_till_spaces (const gchar **ptr)
- +{
- + const gchar *cursor = *ptr;
- + gchar previous = '\0';
- + gchar c = get_char (&cursor);
- +
- + while (c != '\0')
- + {
- + while (!g_ascii_isspace(c) && c != '\0')
- + {
- + previous = c;
- + c = get_next_char (&cursor);
- + };
- +
- + if (c == '\0' || cursor == *ptr)
- + break;
- +
- + if (previous != '\\')
- + break;
- + }
- +
- + *ptr = cursor;
- + return c;
- +}
- +
- +static gboolean
- +get_number (const gchar **ptr,
- + gint *number,
- + IdeVimParserErrorCode *error_code)
- +{
- + gchar c;
- + const gchar *real_ptr = *ptr;
- + gint sign = 1;
- + guint number_digits = 0;
- + gboolean sign_set = FALSE;
- +
- + /* TODO: use parser error */
- + c = get_char (&real_ptr);
- + if (strchr ("+-", c))
- + {
- + sign = (c == '+') ? 1 : -1;
- + sign_set = TRUE;
- +
- + c = get_next_char (&real_ptr);
- + }
- +
- + if (g_ascii_isdigit (c))
- + {
- + do
- + {
- + number_digits += 1;
- + if (number_digits > 9)
- + {
- + /* Number rangge limit. Approximation a digit less
- + * than 32bits int32 but crazy enough for an editor
- + */
- + get_next_char (&real_ptr);
- + *ptr = real_ptr;
- + *error_code = IDE_VIM_PARSER_ERROR_NUMBER_OUT_OF_RANGE;
- + return FALSE;
- + }
- +
- + *number = *number * 10 + g_ascii_digit_value (c);
- + } while ((c = get_next_char (&real_ptr)) && g_ascii_isdigit (c));
- +
- + *number *= sign;
- + }
- + else if (sign_set)
- + {
- + *number = sign;
- + }
- + else
- + {
- + /* Not a number */
- + return FALSE;
- + }
- +
- + *ptr = real_ptr;
- + return TRUE;
- +}
- +
- +static gboolean
- +update_state (IdeVimParserContext *context,
- + IdeVimParserToken *token,
- + IdeVimParserErrorCode error_code,
- + const gchar *ptr)
- +{
- + IdeVimParserInfo *info;
- + IdeVimParserPrivate *parser_priv;
- +
- + parser_priv = ide_vim_parser_get_instance_private (context->parser);
- + info = parser_priv->info;
- +
- + context->token = token;
- + context->token_size = (gint)(ptr - context->position);
- + info ->last_token_kind = token->kind;
- + info->cmdline_error_offset = (ptr - context->cmdline);
- +
- + if (context->token_size)
- + {
- + token->content = g_strndup (context->position, context->token_size);
- + info->last_token_content = strdup (token->content);
- + }
- +
- + if (error_code == IDE_VIM_PARSER_ERROR_NONE)
- + {
- + context->position += context->token_size;
- + context->status = TRUE;
- + }
- + else
- + {
- + info->state = IDE_VIM_PARSER_STATE_ERROR;
- + /* TODO: check if not set elsewhere */
- + ide_vim_parser_error_cursor_set (&context->error, error_code, context->position, context->token_size);
- + info->error_code = error_code;
- + context->status = FALSE;
- + }
- +
- + return context->status;
- +}
- +
- +/* From a string, return a token type and it's size.
- + * On error, size contain the error position.
- + */
- +static gboolean
- +tokenize (IdeVimParserContext *context)
- +{
- + IdeVimParserObjectsPool *objects_pool;
- + IdeVimParserCommand *command_entry = NULL;
- + IdeVimParserInfo *info;
- + IdeVimParserPrivate *parser_priv;
- + IdeVimParserToken *token;
- + IdeVimParserErrorCode error_code = IDE_VIM_PARSER_ERROR_NONE;
- + g_autofree gchar *command = NULL;
- + const gchar *ptr;
- + const gchar *tmp_ptr;
- + gchar c;
- + gboolean has_bang = FALSE;
- +
- + parser_priv = ide_vim_parser_get_instance_private (context->parser);
- + info = parser_priv->info;
- +
- + /* Skip any preceding spaces */
- + c = skip_spaces (&context->position);
- + ptr = context->position;
- +
- + token = ide_vim_parser_token_new ();
- + token->kind = IDE_VIM_PARSER_TOKEN_UNKNOW;
- +
- + if (c == '\0')
- + {
- + /* End of string */
- + token->kind = IDE_VIM_PARSER_TOKEN_END_OF_STRING;
- + goto out;
- + }
- +
- + /* TODO: Work on a slightly more large copy of the string so we don't need
- + * to worry about reading beyond the end of the string
- + * then destroy it (g_auto free on exit) because we only need the size
- + * Not sure this is still aplying.
- + */
- +
- + /* Numbers */
- + if (get_number (&ptr, &token->number, &error_code) ||
- + error_code != IDE_VIM_PARSER_ERROR_NONE)
- + {
- + token->kind = IDE_VIM_PARSER_TOKEN_NUMBER;
- + goto out;
- + }
- +
- + /* Range separator */
- +
- + if (strchr (",;", c))
- + {
- + token->kind = IDE_VIM_PARSER_TOKEN_RANGE_SEPARATOR;
- + get_next_char (&ptr);
- + goto out;
- + }
- +
- + /* Range specifier and range */
- +
- + if (strchr ("%", c))
- + {
- + token->kind = IDE_VIM_PARSER_TOKEN_RANGE;
- + token->range_is_native = TRUE;
- + get_next_char (&ptr);
- + goto out;
- + }
- +
- + if (strchr (".$", c))
- + {
- + token->kind = IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER;
- + get_next_char (&ptr);
- + goto out;
- + }
- +
- + if (c == '\\')
- + {
- + token->kind = IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER;
- + c = get_next_char (&ptr);
- + get_next_char (&ptr);
- + if (strchr ("/?&", c))
- + goto out;
- +
- + error_code = IDE_VIM_PARSER_ERROR_UNKNOWN_RANGE_SPECIFIER;
- + goto out;
- + }
- +
- + /* Marks */
- +
- + if (c == '\'')
- + {
- + token->kind = IDE_VIM_PARSER_TOKEN_MARK;
- + c = get_next_char (&ptr);
- + get_next_char (&ptr);
- +
- + if (c != '\0' && (g_ascii_isalnum (c) || strchr ("'\"^.[](){}<>", c)))
- + goto out;
- +
- + error_code = IDE_VIM_PARSER_ERROR_UNKNOWN_MARK;
- + goto out;
- + }
- +
- + /* Registers */
- +
- + if (c == '"')
- + {
- + token->kind = IDE_VIM_PARSER_TOKEN_REGISTER;
- + c = get_next_char (&ptr);
- + if (c != '\0')
- + {
- + if (g_ascii_isalnum (c) || strchr ("\"-=+~_/%#", c))
- + {
- + get_next_char (&ptr);
- + goto out;
- + }
- +
- + if (c == ':' || c == '.')
- + {
- + c = get_next_char (&ptr);
- + if (c == ',')
- + goto out;
- + }
- +
- + get_next_char (&ptr);
- + error_code = IDE_VIM_PARSER_ERROR_UNKNOWN_REGISTER;
- + goto out;
- + }
- +
- + error_code = IDE_VIM_PARSER_ERROR_UNKNOWN_REGISTER;
- + goto out;
- + }
- +
- + /* Range Patterns */
- +
- + if (strchr ("/?", c))
- + {
- + gchar c_end = c;
- + gchar prev = c;
- +
- + tmp_ptr = ptr;
- + token->pattern_type = prev;
- + token->kind = IDE_VIM_PARSER_TOKEN_PATTERN;
- +
- + /* A pattern end on the matching / or ? so can't be incomplete
- + * end run till end of the line in worst case but we need to
- + * take care of the matching / or ? in the pattern itself.
- + */
- + while ((c = get_next_char (&ptr)))
- + {
- + if (c == c_end && prev != '\\')
- + goto out;
- +
- + prev = c;
- + }
- +
- + /* Unclosed pattern : search command / OR ?
- + * the rest of the line will be a raw pattern */
- + /* TODO: fill a search command entry */
- + token->kind = IDE_VIM_PARSER_TOKEN_COMMAND_NAME;
- + ptr = tmp_ptr;
- + goto out;
- + }
- +
- + /* Various strings */
- + /* TODO: Command name is only letters and we can find number just after without spaces,
- + * is string more than letters can be find before command name ? */
- + tmp_ptr = ptr;
- + while ((c = get_next_char (&ptr)) && !g_ascii_isspace (c))
- + tmp_ptr = ptr;
- +
- + /* Check for a bang just after a possible command name */
- + if (*tmp_ptr == '!')
- + {
- + command = g_strndup (context->position, (gint)(tmp_ptr - context->position));
- + has_bang = TRUE;
- + }
- + else
- + {
- + command = g_strndup (context->position, (gint)(ptr - context->position));
- + }
- +
- + /* Check for an existing command name */
- + objects_pool = parser_priv->objects_pool;
- + command_entry = ide_vim_parser_objects_pool_lookup_command (objects_pool, command);
- + if (command_entry != NULL)
- + {
- + token->command_has_bang = has_bang;
- + token->command_entry = command_entry;
- + token->kind = IDE_VIM_PARSER_TOKEN_COMMAND_NAME;
- +
- + context->command_found = token->command_entry;
- + info->command_name_found = g_strdup (ide_vim_parser_command_get_name (context->command_found));
- + }
- + else
- + {
- + token->kind = IDE_VIM_PARSER_TOKEN_STRING;
- + }
- +
- +out:
- +
- + return update_state (context, token, error_code, ptr);
- +}
- +
- +/* From a string, return a token type and it's size.
- + * On error, size contain the error position.
- + */
- +static gboolean
- +tokenize_after_command (IdeVimParserContext *context,
- + IdeVimParserToken *arg)
- +{
- + IdeVimParserToken *token;
- + IdeVimParserErrorCode error_code = IDE_VIM_PARSER_ERROR_NONE;
- + const gchar *ptr;
- + gchar c;
- +
- + /* Skip any preceding spaces */
- + c = skip_spaces (&context->position);
- + ptr = context->position;
- +
- + token = ide_vim_parser_token_new ();
- + token->kind = IDE_VIM_PARSER_TOKEN_UNKNOW;
- +
- + if (c == '\0')
- + {
- + /* End of string */
- + token->kind = IDE_VIM_PARSER_TOKEN_END_OF_STRING;
- + error_code = IDE_VIM_PARSER_ERROR_MISMATCH_KIND;
- + goto out;
- + }
- +
- + if (arg->kind == IDE_VIM_PARSER_TOKEN_NUMBER)
- + {
- + /* TODO: Negative number used in post command ? */
- + if (get_number (&ptr, &token->number, &error_code) ||
- + error_code != IDE_VIM_PARSER_ERROR_NONE)
- + {
- + token->kind = IDE_VIM_PARSER_TOKEN_NUMBER;
- + goto out;
- + }
- +
- + error_code = IDE_VIM_PARSER_ERROR_MISMATCH_KIND;
- + goto out;
- + }
- +
- + if (arg->kind == IDE_VIM_PARSER_TOKEN_STRING)
- + {
- + while ((c = get_next_char (&ptr)) && !g_ascii_isspace (c));
- +
- + token->kind = IDE_VIM_PARSER_TOKEN_STRING;
- + goto out;
- + }
- +
- + error_code = IDE_VIM_PARSER_ERROR_MISMATCH_KIND;
- +
- +out:
- +
- + return update_state (context, token, error_code, ptr);
- +}
- +
- +static gboolean
- +ide_vim_parser_validate_pre_command_args (IdeVimParserContext *context)
- +{
- + IdeVimParserCommand *command = context->command_found;
- + IdeVimParserToken *arg;
- + IdeVimParserToken *token;
- + const GPtrArray *args;
- + const GList *l_token;
- + gboolean is_matching;
- +
- + g_return_val_if_fail (command != NULL, FALSE);
- +
- + l_token = context->stack->tail;
- + args = ide_vim_parser_command_get_args (command);
- +
- + for (gint i = 0; i < args->len; i++)
- + {
- + context->command_arg_list_pos = i;
- + arg = g_ptr_array_index (args, i);
- + token = l_token->data;
- +
- + /* We also cover the case where we way for a number but
- + * we have a range due to separators
- + */
- + is_matching = arg->kind == token->kind ||
- + (arg->kind == IDE_VIM_PARSER_TOKEN_NUMBER && token->kind == IDE_VIM_PARSER_TOKEN_RANGE);
- +
- + if (!is_matching)
- + {
- + if (arg->flag == IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL)
- + continue;
- + else
- + break;
- + }
- +
- + g_printf ("match: kind:%i, flag:%i\n", arg->kind, arg->flag);
- +
- + if (arg->kind == IDE_VIM_PARSER_TOKEN_COMMAND_NAME)
- + return TRUE;
- +
- + l_token = l_token->prev;
- + if (l_token == NULL)
- + break;
- + }
- +
- + g_printf ("missmatch: kind:%i != %i, flag:%i\n", arg->kind, token->kind, arg->flag);
- + return FALSE;
- +}
- +
- +static gboolean
- +ide_vim_parser_validate_post_command_args (IdeVimParserContext *context)
- +{
- + IdeVimParserCommand *command = context->command_found;
- + IdeVimParserError *tmp_error = NULL;
- + const GPtrArray *args;
- + IdeVimParserToken *arg;
- + gboolean ret;
- +
- + g_return_val_if_fail (command != NULL, FALSE);
- +
- + /* We continue validate args after command name */
- + args = ide_vim_parser_command_get_args (command);
- + for (gint i = context->command_arg_list_pos + 1; i < args->len; i++)
- + {
- + arg = g_ptr_array_index (args, i);
- +
- + ret = tokenize_after_command (context, arg);
- + /* TODO: errors stuff to fix too, can be an incomplete token or
- + * no token at all */
- + if (!ret)
- + {
- + if (arg->flag != IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL)
- + {
- + g_printf ("post missmatch: kind:%i != %i, flag:%i\n", arg->kind, context->token->kind, arg->flag);
- + return FALSE;
- + }
- +
- + return FALSE;
- + }
- +
- + g_queue_push_head (context->stack, context->token);
- + }
- +
- + return TRUE;
- +}
- +
- +static void
- +ide_vim_parser_destroy_context (IdeVimParserContext *context)
- +{
- + g_free (context->cmdline);
- + g_queue_clear (context->stack);
- + g_free (context);
- +}
- +
- +/* Line values are in Vim coordinates, starting from 1 */
- +static IdeVimParserContext *
- +ide_vim_parser_create_context (IdeVimParser *self,
- + GtkTextBuffer *buffer,
- + const gchar *cmdline)
- +{
- + IdeVimParserPrivate *priv = ide_vim_parser_get_instance_private (self);
- + IdeVimParserContext *context;
- + GtkTextIter start;
- + GtkTextIter end;
- + GtkTextIter insert;
- + GtkTextIter select;
- + gboolean has_selection;
- +
- + g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
- + g_return_val_if_fail (!ide_str_empty0 (cmdline), NULL);
- +
- + context = g_new0 (IdeVimParserContext, 1);
- + context->buffer = buffer;
- +
- + gtk_text_buffer_get_bounds (buffer, &start, &end);
- + context->start_line = gtk_text_iter_get_line (&start) + BUFFER_TO_VIM_LINE_COORDS;
- + context->end_line = gtk_text_iter_get_line (&end) + BUFFER_TO_VIM_LINE_COORDS;
- +
- + has_selection = gtk_text_buffer_get_selection_bounds (buffer, &insert, &select);
- + context->insert_line = gtk_text_iter_get_line (&insert) + BUFFER_TO_VIM_LINE_COORDS;
- + /* TODO: set select_line to 0 if has_selection FALSE ? */
- + context->select_line = gtk_text_iter_get_line (&select) + BUFFER_TO_VIM_LINE_COORDS;
- +
- + context->range_start_line = VALUE_NOT_SET;
- + context->range_end_line = VALUE_NOT_SET;
- +
- + context->previous_token_is_separator = TRUE;
- +
- + context->parser = self;
- + context->cmdline = g_strdup (cmdline);
- + context->position = context->cmdline;
- + context->objects_pool = priv->objects_pool;
- + context->stack = priv->stack;
- + context->info = priv->info;
- +
- + return context;
- +}
- +
- +static void
- +set_token_error (IdeVimParserContext *context)
- +{
- + IdeVimParserInfo *info = context->info;
- +
- + g_assert (info->error_code != IDE_VIM_PARSER_ERROR_NONE);
- +
- + ide_vim_parser_error_cursor_set (&context->error,
- + info->error_code,
- + context->cmdline,
- + info->cmdline_error_offset);
- +}
- +
- +static void
- +set_token_unwanted_error (IdeVimParserContext *context)
- +{
- + IdeVimParserInfo *info = context->info;
- +
- + info->state = IDE_VIM_PARSER_STATE_ERROR;
- + info->error_code = IDE_VIM_PARSER_ERROR_UNWANTED_TOKEN;
- + info->cmdline_error_offset = (context->position - context->token_size - context->cmdline);
- +
- + ide_vim_parser_error_cursor_set (&context->error,
- + IDE_VIM_PARSER_ERROR_UNWANTED_TOKEN,
- + context->cmdline,
- + info->cmdline_error_offset);
- +}
- +
- +/* Commom enter and leave functions */
- +static void
- +state_enter (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + //printf ("%s state enter\n", ide_vim_state_machine_get_state_name (self));
- +}
- +
- +static void
- +state_leave (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + //g_printf ("%s state leave\n", ide_vim_state_machine_get_state_name (self));
- +}
- +
- +/* 'init' state functions */
- +static IdeVimStateId
- +state_init_transition (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- + IdeVimParserToken *token;
- + const gchar *state_name;
- + gboolean status;
- +
- + g_printf ("%s state transition\n", ide_vim_state_machine_get_state_name (self));
- +
- + status = tokenize (context);
- + if (status)
- + {
- + token = context->token;
- + g_printf ("%s\n", ide_vim_parser_debug_token_to_string (context->token));
- +
- + switch (token->kind)
- + {
- + case IDE_VIM_PARSER_TOKEN_PATTERN:
- + case IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER:
- + case IDE_VIM_PARSER_TOKEN_MARK:
- + case IDE_VIM_PARSER_TOKEN_NUMBER:
- + case IDE_VIM_PARSER_TOKEN_RANGE:
- + state_name = ide_vim_parser_push_to_stack (context, token) ? "range" : "error";
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_REGISTER:
- + state_name = ide_vim_parser_push_to_stack (context, token) ? "register" : "error";
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_COMMAND_NAME:
- + state_name = ide_vim_parser_push_to_stack (context, token) ? "command" : "error";
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_RANGE_SEPARATOR:
- + state_name = ide_vim_parser_push_to_stack (context, token) ? "separator" : "error";
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_UNKNOW:
- + case IDE_VIM_PARSER_TOKEN_STRING:
- + case IDE_VIM_PARSER_TOKEN_END_OF_STRING:
- + /* TODO: goto line command */
- + set_token_unwanted_error (context);
- + state_name = "error";
- + break;
- +
- + default:
- + g_assert_not_reached ();
- + break;
- + }
- +
- + return ide_vim_state_machine_get_id_from_name (self, state_name);
- + }
- +
- + set_token_error (context);
- + return ide_vim_state_machine_get_id_from_name (self, "error");
- +}
- +
- +static gboolean
- +state_init_action (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + //g_printf ("%s state action\n", ide_vim_state_machine_get_state_name (self));
- +
- + return TRUE;
- +}
- +
- +/* 'range' state functions */
- +static IdeVimStateId
- +state_range_transition (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- + IdeVimParserToken *token;
- + const gchar *state_name;
- + gboolean status;
- +
- + g_printf ("%s state transition\n", ide_vim_state_machine_get_state_name (self));
- +
- + status = tokenize (context);
- + if (status)
- + {
- + token = context->token;
- + g_printf ("%s\n", ide_vim_parser_debug_token_to_string (context->token));
- +
- + switch (token->kind)
- + {
- + case IDE_VIM_PARSER_TOKEN_COMMAND_NAME:
- + state_name = ide_vim_parser_push_to_stack (context, token) ? "command" : "error";
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_NUMBER:
- + case IDE_VIM_PARSER_TOKEN_PATTERN:
- + state_name = ide_vim_parser_push_to_stack (context, token) ? "range" : "error";
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_RANGE_SEPARATOR:
- + state_name = ide_vim_parser_push_to_stack (context, token) ? "separator" : "error";
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER:
- + case IDE_VIM_PARSER_TOKEN_MARK:
- + case IDE_VIM_PARSER_TOKEN_REGISTER:
- + case IDE_VIM_PARSER_TOKEN_UNKNOW:
- + case IDE_VIM_PARSER_TOKEN_STRING:
- + case IDE_VIM_PARSER_TOKEN_END_OF_STRING:
- + case IDE_VIM_PARSER_TOKEN_RANGE:
- + set_token_unwanted_error (context);
- + state_name = "error";
- + break;
- +
- + default:
- + g_assert_not_reached ();
- + break;
- + }
- +
- + return ide_vim_state_machine_get_id_from_name (self, state_name);
- + }
- +
- + set_token_error (context);
- + return ide_vim_state_machine_get_id_from_name (self, "error");
- +}
- +
- +static gboolean
- +state_range_action (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + //g_printf ("%s state action\n", ide_vim_state_machine_get_state_name (self));
- +
- + return TRUE;
- +}
- +
- +/* 'separator' state functions */
- +static IdeVimStateId
- +state_separator_transition (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- + IdeVimParserToken *token;
- + const gchar *state_name;
- + gboolean status;
- +
- + g_printf ("%s state transition\n", ide_vim_state_machine_get_state_name (self));
- +
- + status = tokenize (context);
- + if (status)
- + {
- + token = context->token;
- + g_printf ("%s\n", ide_vim_parser_debug_token_to_string (context->token));
- +
- + switch (token->kind)
- + {
- + case IDE_VIM_PARSER_TOKEN_COMMAND_NAME:
- + state_name = ide_vim_parser_push_to_stack (context, token) ? "command" : "error";
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_PATTERN:
- + case IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER:
- + case IDE_VIM_PARSER_TOKEN_MARK:
- + case IDE_VIM_PARSER_TOKEN_NUMBER:
- + state_name = ide_vim_parser_push_to_stack (context, token) ? "range" : "error";
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_RANGE_SEPARATOR:
- + case IDE_VIM_PARSER_TOKEN_REGISTER:
- + case IDE_VIM_PARSER_TOKEN_UNKNOW:
- + case IDE_VIM_PARSER_TOKEN_STRING:
- + case IDE_VIM_PARSER_TOKEN_END_OF_STRING:
- + case IDE_VIM_PARSER_TOKEN_RANGE:
- + set_token_unwanted_error (context);
- + state_name = "error";
- + break;
- +
- + default:
- + g_assert_not_reached ();
- + break;
- + }
- +
- + return ide_vim_state_machine_get_id_from_name (self, state_name);
- + }
- +
- + set_token_error (context);
- + return ide_vim_state_machine_get_id_from_name (self, "error");
- +}
- +
- +static gboolean
- +state_separator_action (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + //g_printf ("%s state action\n", ide_vim_state_machine_get_state_name (self));
- +
- + return TRUE;
- +}
- +
- +/* 'register' state functions */
- +static IdeVimStateId
- +state_register_transition (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- + IdeVimParserToken *token;
- + const gchar *state_name;
- + gboolean status;
- +
- + g_printf ("%s state transition\n", ide_vim_state_machine_get_state_name (self));
- +
- + status = tokenize (context);
- + if (status)
- + {
- + token = context->token;
- + g_printf ("%s\n", ide_vim_parser_debug_token_to_string (context->token));
- +
- + switch (token->kind)
- + {
- + case IDE_VIM_PARSER_TOKEN_COMMAND_NAME:
- + state_name = ide_vim_parser_push_to_stack (context, token) ? "command" : "error";
- + break;
- +
- + case IDE_VIM_PARSER_TOKEN_RANGE_SEPARATOR:
- + case IDE_VIM_PARSER_TOKEN_UNKNOW:
- + case IDE_VIM_PARSER_TOKEN_STRING:
- + case IDE_VIM_PARSER_TOKEN_END_OF_STRING:
- + case IDE_VIM_PARSER_TOKEN_RANGE:
- + case IDE_VIM_PARSER_TOKEN_PATTERN:
- + case IDE_VIM_PARSER_TOKEN_RANGE_SPECIFIER:
- + case IDE_VIM_PARSER_TOKEN_MARK:
- + case IDE_VIM_PARSER_TOKEN_NUMBER:
- + case IDE_VIM_PARSER_TOKEN_REGISTER:
- + set_token_unwanted_error (context);
- + state_name = "error";
- + break;
- +
- + default:
- + g_assert_not_reached ();
- + break;
- + }
- +
- + return ide_vim_state_machine_get_id_from_name (self, state_name);
- + }
- +
- + set_token_error (context);
- + return ide_vim_state_machine_get_id_from_name (self, "error");
- +}
- +
- +static gboolean
- +state_register_action (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + //g_printf ("%s state action\n", ide_vim_state_machine_get_state_name (self));
- +
- + return TRUE;
- +}
- +
- +/* 'command' state functions */
- +static IdeVimStateId
- +state_command_transition (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + g_printf ("%s state transition\n", ide_vim_state_machine_get_state_name (self));
- +
- + if (!ide_vim_parser_validate_pre_command_args (context))
- + return ide_vim_state_machine_get_id_from_name (self, "error");
- +
- + if (!ide_vim_parser_validate_post_command_args (context))
- + return ide_vim_state_machine_get_id_from_name (self, "error");
- +
- + return ide_vim_state_machine_get_id_from_name (self, "valid");
- +}
- +
- +static gboolean
- +state_command_action (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + //g_printf ("%s state action\n", ide_vim_state_machine_get_state_name (self));
- +
- + return TRUE;
- +}
- +
- +/* 'valid' state functions */
- +static gboolean
- +state_valid_action (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + g_printf ("%s state action\n", ide_vim_state_machine_get_state_name (self));
- +
- + return TRUE;
- +}
- +
- +/* 'incomplete' state functions */
- +static gboolean
- +state_incomplete_action (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + g_printf ("%s state action\n", ide_vim_state_machine_get_state_name (self));
- +
- + return TRUE;
- +}
- +
- +/* 'error' state functions */
- +
- +static gboolean
- +state_error_action (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimParserContext *context = (IdeVimParserContext *)data;
- +
- + g_printf ("%s state action\n", ide_vim_state_machine_get_state_name (self));
- + /* TODO: save the token and clear context->token */
- +
- +
- + return TRUE;
- +}
- +
- +#pragma GCC diagnostic push
- +
- +static void
- +_ide_vim_parser_fill_state_table (IdeVimParser *self)
- +{
- + IdeVimParserPrivate *priv = ide_vim_parser_get_instance_private (self);
- +
- + /* The init state is also use for range separators */
- + ide_vim_state_machine_add_state (priv->machine, "init",
- + state_enter, state_leave, state_init_transition, state_init_action);
- +
- + /* The range state is also use for counts */
- + ide_vim_state_machine_add_state (priv->machine, "range",
- + state_enter, state_leave, state_range_transition, state_range_action);
- +
- + ide_vim_state_machine_add_state (priv->machine, "separator",
- + state_enter, state_leave, state_separator_transition, state_separator_action);
- +
- + ide_vim_state_machine_add_state (priv->machine, "register",
- + state_enter, state_leave, state_register_transition, state_register_action);
- +
- + ide_vim_state_machine_add_state (priv->machine, "command",
- + state_enter, state_leave, state_command_transition, state_command_action);
- +
- + ide_vim_state_machine_add_state (priv->machine, "error",
- + state_enter, state_leave, NULL, state_error_action);
- +
- + ide_vim_state_machine_add_state (priv->machine, "valid",
- + state_enter, state_leave, NULL, state_valid_action);
- +
- + ide_vim_state_machine_add_state (priv->machine, "incomplete",
- + state_enter, state_leave, NULL, state_incomplete_action);
- +}
- +
- +static void
- +_ide_vim_parser_fill_command_table (IdeVimParser *self)
- +{
- +
- +/*
- + static IdeVimParserTokenCommandItem commands [] = {
- + {"buffer", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_BUFFER },
- + {"cd", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_CD },
- + {"clist", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_CLIST },
- + {"excecute", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_EXCECUTE },
- + {"history", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_HISTORY },
- + {"marks", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_MARKS },
- + {"fold", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_FOLD },
- + {"global", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_GLOBAL },
- + {"nohl", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_NOHL },
- + {"qall", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_QALL },
- + {"quit", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_QUIT },
- + {"quitall", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_QUITALL },
- + {"reg", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_REG },
- + {"retab", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_RETAB },
- + {"set", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_SET },
- + {"shell", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_SHELL },
- + {"sort", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_SORT },
- + {"split", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_SPLIT },
- + {"substitute", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_SUBSTITUTE },
- + {"syntax", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_SYNTAX },
- + {"tags", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_TAGS },
- + {"version", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_VERSION },
- + {"vsplit", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_VSPLIT },
- + {"wq", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_WQ },
- + {"write", IDE_VIM_PARSER_TOKEN_COMMAND_NAME_WRITE }
- + };
- +*/
- +
- +}
- +
- +static inline gboolean
- +set_substring_parse (const gchar *str,
- + gchar **var,
- + gchar **val,
- + IdeVimParserSetOp *op,
- + IdeVimParserError **error)
- +{
- + gchar *set_separator;
- + const gchar *str_end;
- + g_autofree gchar *val_tmp = NULL;
- + guint error_position = 0;
- + gint len;
- +
- + len = strlen (str);
- + str_end = str + len - 1;
- + set_separator = strchr (str, '=');
- + if (set_separator == NULL)
- + {
- + set_separator = strchr (str, ':');
- + }
- +
- + if (set_separator == NULL)
- + {
- + *val = NULL;
- + if (*str_end == '!')
- + {
- + *var = g_strndup (str, len - 1);
- + *op = IDE_VIM_PARSER_SET_OP_INVERT;
- + }
- + else if (*str_end == '?')
- + {
- + *var = g_strndup (str, len - 1);
- + *op = IDE_VIM_PARSER_SET_OP_SHOW;
- + }
- + else if (g_str_has_prefix (str, "no"))
- + {
- + *var = g_strdup (str + 2);
- + *op = IDE_VIM_PARSER_SET_OP_RESET;
- + }
- + else
- + {
- + *var = g_strdup (str);
- + *op = IDE_VIM_PARSER_SET_OP_NONE;
- + }
- +
- + /* TODO: validate *var as isalpha */
- + }
- + else
- + {
- + if (set_separator == str || set_separator == str_end)
- + {
- + error_position = set_separator -str;
- + goto error;
- + }
- +
- + /* TODO: validate *var as isalpha */
- + *var = g_strndup (str, set_separator - str);
- + val_tmp = g_strndup (set_separator + 1, str_end - set_separator);
- + *val = g_strcompress (val_tmp);
- + }
- +
- + return TRUE;
- +
- +error:
- + ide_vim_parser_error_cursor_set (error, IDE_VIM_PARSER_ERROR_SET_CANT_PARSE, str, error_position);
- + return FALSE;
- +}
- +
- +/**
- + * ide_vim_parser_parse_set:
- + * @self: (in): a #IdeVimParser instance.
- + * @string: (in): The cset string to parse.
- + * @error: (out): The #IdeVimParserError used for error reporting.
- + *
- + * Parse the a set string.
- + *
- + * Returns: (transfer full) (nullable): A #GArray of ?.
- + */
- +GArray *
- +ide_vim_parser_parse_settable (IdeVimParser *self,
- + const gchar *string,
- + IdeVimParserError **error)
- +{
- + g_autofree const gchar *str = NULL;
- + const gchar *cursor;
- + const gchar *base;
- + gchar *set_str, *set_var, *set_val;
- + IdeVimParserSetOp op = IDE_VIM_PARSER_SET_OP_NONE;
- + IdeVimParserError *tmp_error = NULL;
- + GArray *array = NULL;
- + gchar c;
- + IdeVimParserPrivate *priv;
- +
- + g_assert (IDE_IS_VIM_PARSER (self));
- +
- + priv = ide_vim_parser_get_instance_private (self);
- + if (ide_str_empty0 (string))
- + {
- + /* TODO: show changed */
- + return NULL;
- + }
- +
- + str = g_strchomp (g_strchug (g_strdup (string)));
- + base = cursor = str;
- + while (1)
- + {
- + c = skip_till_spaces (&cursor);
- + set_str = g_strndup (base, cursor - base);
- + if (set_substring_parse (set_str, &set_var, &set_val, &op, &tmp_error))
- + g_printf ("set var:'%s', val:'%s' op:%i\n", set_var, set_val, op);
- + else
- + {
- + g_printf ("can't parse:'%s'", set_str);
- + ide_vim_parser_error_propagate (error, tmp_error);
- + return NULL;
- + }
- +
- + if (c == '\0')\
- + break;
- +
- + skip_spaces (&cursor);
- + base = cursor;
- + g_free (set_str);
- + }
- +
- + return array;
- +}
- +
- +/**
- + * ide_vim_parser_parse:
- + * @self: (in): a #IdeVimParser instance.
- + * @buffer: (in): The #GtkTextBuffer used when parsing. We need it to calculate the range part.
- + * @cmdline: (in): The command line to parse.
- + * @error: (out): The #IdeVimParserError used for error reporting.
- + *
- + * Parse the cmdline string.
- + *
- + * Returns: (transfer full) (nullable): A #IdeVimParserCommand.
- + */
- +IdeVimParserCommand *
- +ide_vim_parser_parse (IdeVimParser *self,
- + GtkTextBuffer *buffer,
- + const gchar *cmdline,
- + IdeVimParserError **error)
- +{
- + IdeVimParserPrivate *priv = ide_vim_parser_get_instance_private (self);
- + IdeVimParserCommand *new_command = NULL;
- + GList *list = NULL;
- + IdeVimParserContext *context;
- + IdeVimParserError *tmp_error = NULL;
- + IdeVimParserInfo *info = priv->info;
- +
- + g_assert (IDE_IS_VIM_PARSER (self));
- + g_assert (GTK_IS_TEXT_BUFFER (buffer));
- +
- + if (ide_str_empty0 (cmdline))
- + {
- + info->state = IDE_VIM_PARSER_STATE_ERROR;
- + info->error_code = IDE_VIM_PARSER_ERROR_CMDLINE_EMPTY;
- + ide_vim_parser_error_set (error, IDE_VIM_PARSER_ERROR_CMDLINE_EMPTY, NULL);
- + return NULL;
- + }
- +
- + context = ide_vim_parser_create_context (self, buffer, cmdline);
- +
- + /* TODO: allocate str on the stack but no more than 256 bytes
- + * added or more \0 to keep ptr in. not sure it's needed now
- + */
- +
- + ide_vim_state_machine_set_state_by_name (priv->machine, "init");
- + while (ide_vim_state_machine_run_once (priv->machine, context))
- + ;
- +
- + if (context->error == NULL)
- + {
- + list = g_list_reverse (g_list_copy (context->stack->head));
- +
- + if (context->command_found)
- + {
- + new_command = ide_vim_parser_command_parsed_new (context->command_found, list, &tmp_error);
- + info->command_name_found = ide_vim_parser_command_get_name (new_command);
- +
- + /* TODO: to remove after debuging */
- + if (tmp_error != NULL)
- + {
- + /* FIXME: incomplete or error ? */
- + info->state = IDE_VIM_PARSER_STATE_INCOMPLETE;
- + info->error_code = ide_vim_parser_error_get_error_code (tmp_error);
- + ide_vim_parser_error_propagate (error, tmp_error);
- +
- + ide_vim_parser_debug_show_stack (list);
- + }
- + else
- + {
- + info->state = IDE_VIM_PARSER_STATE_COMPLETE;
- + }
- + }
- + else
- + {
- + info->state = IDE_VIM_PARSER_STATE_ERROR;
- + /* TODO: cursor error ? */
- + ide_vim_parser_error_set (error, IDE_VIM_PARSER_ERROR_COMMAND_NOT_FOUND, cmdline);
- + info->error_code = ide_vim_parser_error_get_error_code (*error);
- + }
- + }
- + else
- + {
- + ide_vim_parser_error_propagate (error, context->error);
- + }
- +
- + /* TODO: free the tokens list if there's no command */
- + g_list_free (list);
- + ide_vim_parser_destroy_context (context);
- +
- + ide_vim_parser_debug_show_info (ide_vim_parser_get_info (self));
- +
- + return new_command;
- +}
- +
- +const IdeVimParserInfo *
- +ide_vim_parser_get_info (IdeVimParser *self)
- +{
- + IdeVimParserPrivate *priv;
- +
- + g_assert (IDE_IS_VIM_PARSER (self));
- +
- + priv = ide_vim_parser_get_instance_private (self);
- +
- + return priv->info;
- +}
- +
- +IdeVimParser *
- +ide_vim_parser_new (void)
- +{
- + return g_object_new (IDE_TYPE_VIM_PARSER, NULL);
- +}
- +
- +static void
- +ide_vim_parser_finalize (GObject *object)
- +{
- + IdeVimParser *self = (IdeVimParser *)object;
- + IdeVimParserPrivate *priv = ide_vim_parser_get_instance_private (self);
- +
- + g_clear_object (&priv->machine);
- + g_clear_object (&priv->objects_pool);
- + g_clear_pointer (&priv->stack, g_queue_free);
- + if (priv->info)
- + {
- + g_free ((gpointer)priv->info->command_name_found);
- + g_clear_object (&priv->info);
- + }
- +
- + G_OBJECT_CLASS (ide_vim_parser_parent_class)->finalize (object);
- +}
- +
- +static void
- +ide_vim_parser_get_property (GObject *object,
- + guint prop_id,
- + GValue *value,
- + GParamSpec *pspec)
- +{
- + //IdeVimParser *self = IDE_VIM_PARSER (object);
- +
- + switch (prop_id)
- + {
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_parser_set_property (GObject *object,
- + guint prop_id,
- + const GValue *value,
- + GParamSpec *pspec)
- +{
- + //IdeVimParser *self = IDE_VIM_PARSER (object);
- +
- + switch (prop_id)
- + {
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_parser_init (IdeVimParser *self)
- +{
- + IdeVimParserPrivate *priv = ide_vim_parser_get_instance_private (self);
- +
- + priv->stack = g_queue_new ();
- + priv->machine = ide_vim_state_machine_new ();
- + priv->objects_pool = ide_vim_parser_objects_pool_new ();
- + priv->info = g_new0 (IdeVimParserInfo, 1);
- +
- + _ide_vim_parser_fill_command_table (self);
- + _ide_vim_parser_fill_state_table (self);
- +}
- +
- +static void
- +ide_vim_parser_class_init (IdeVimParserClass *klass)
- +{
- + GObjectClass *object_class = G_OBJECT_CLASS (klass);
- +
- + object_class->finalize = ide_vim_parser_finalize;
- + object_class->get_property = ide_vim_parser_get_property;
- + object_class->set_property = ide_vim_parser_set_property;
- +}
- +
- diff --git a/libide/vim/ide-vim-parser.h b/libide/vim/ide-vim-parser.h
- new file mode 100644
- index 0000000..14b9a89
- --- /dev/null
- +++ b/libide/vim/ide-vim-parser.h
- @@ -0,0 +1,125 @@
- +/* ide-vim-parser.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_PARSER_H
- +#define IDE_VIM_PARSER_H
- +
- +#include <gtk/gtk.h>
- +
- +#include "ide-vim-parser-command.h"
- +#include "ide-vim-parser-commands.h"
- +#include "ide-vim-parser-objects-pool.h"
- +#include "ide-vim-parser-token.h"
- +#include "ide-vim-complete-item.h"
- +
- +G_BEGIN_DECLS
- +
- +#define IDE_TYPE_VIM_PARSER (ide_vim_parser_get_type())
- +
- +G_DECLARE_FINAL_TYPE (IdeVimParser, ide_vim_parser, IDE, VIM_PARSER, GObject)
- +
- +struct _IdeVimParser
- +{
- + GObject parent;
- +};
- +
- +//typedef struct _IdeVimParserCommand IdeVimParserCommand;
- +
- +/********** PARSER **********/
- +
- +typedef enum
- +{
- + IDE_VIM_PARSER_KIND_RANGE,
- + IDE_VIM_PARSER_KIND_COMMAND,
- + IDE_VIM_PARSER_KIND_PATTERN,
- + IDE_VIM_PARSER_KIND_OPTION
- +} IdeVimParserKind;
- +
- +typedef enum
- +{
- + IDE_VIM_PARSER_SET_OP_NONE,
- + IDE_VIM_PARSER_SET_OP_RESET,
- + IDE_VIM_PARSER_SET_OP_SHOW,
- + IDE_VIM_PARSER_SET_OP_INVERT
- +} IdeVimParserSetOp;
- +
- +typedef enum
- +{
- + IDE_VIM_PARSER_STATE_NOT_PARSED,
- + IDE_VIM_PARSER_STATE_COMPLETE,
- + IDE_VIM_PARSER_STATE_INCOMPLETE,
- + IDE_VIM_PARSER_STATE_ERROR
- +} IdeVimParserState;
- +
- +typedef struct
- +{
- + IdeVimParserState state;
- + IdeVimParserErrorCode error_code;
- + IdeVimParserTokenKind last_token_kind;
- + IdeVimParserTokenKind last_good_token_kind;
- + gint cmdline_error_offset;
- + const gchar *last_token_content;
- + const gchar *command_name_found;
- +} IdeVimParserInfo;
- +
- +typedef struct
- +{
- + IdeVimParser *parser;
- + GtkTextBuffer *buffer;
- + IdeVimParserObjectsPool *objects_pool;
- + GQueue *stack;
- + IdeVimParserInfo *info;
- + gint start_line;
- + gint end_line;
- + gint insert_line;
- + gint select_line;
- + gint range_start_line;
- + gint range_end_line;
- + gchar *cmdline;
- + const gchar *position;
- + IdeVimParserToken *token;
- + gint token_size;
- + IdeVimParserCommand *command_found;
- + gint command_arg_list_pos;
- + IdeVimParserError *error;
- + gboolean previous_token_is_separator : 1;
- + gboolean status : 1;
- +} IdeVimParserContext;
- +
- +gint ide_vim_parser_add_command (IdeVimParser *self,
- + const gchar *name,
- + const gchar *shortname,
- + IdeVimParserCommandFunc func,
- + ...) G_GNUC_NULL_TERMINATED;
- +GPtrArray *ide_vim_parser_complete (IdeVimParser *self,
- + GtkTextBuffer *buffer,
- + const gchar *match_name);
- +IdeVimParser *ide_vim_parser_new (void);
- +IdeVimParserCommand *ide_vim_parser_parse (IdeVimParser *self,
- + GtkTextBuffer *buffer,
- + const gchar *cmdline,
- + IdeVimParserError **error);
- +GArray *ide_vim_parser_parse_settable (IdeVimParser *self,
- + const gchar *string,
- + IdeVimParserError **error);
- +const IdeVimParserInfo *ide_vim_parser_get_info (IdeVimParser *self);
- +
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_PARSER_H */
- diff --git a/libide/vim/ide-vim-state-machine.c b/libide/vim/ide-vim-state-machine.c
- new file mode 100644
- index 0000000..4e2341f
- --- /dev/null
- +++ b/libide/vim/ide-vim-state-machine.c
- @@ -0,0 +1,500 @@
- +/* ide-vim-state-machine.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <string.h>
- +#include <errno.h>
- +#include <glib/gi18n.h>
- +#include <glib/gprintf.h>
- +
- +#include "ide-debug.h"
- +#include "ide-macros.h"
- +
- +#include <glib/gi18n.h>
- +
- +#include "ide-vim-state-machine.h"
- +#include "ide-vim-state-result.h"
- +
- +typedef struct
- +{
- + IdeVimStateId state_id;
- + IdeVimStateId previous_id;
- + GHashTable *state_table;
- +} IdeVimStateMachinePrivate;
- +
- +G_DEFINE_TYPE_WITH_PRIVATE (IdeVimStateMachine, ide_vim_state_machine, G_TYPE_OBJECT)
- +
- +enum {
- + PROP_0,
- + PROP_STATE_NAME,
- + PROP_STATE_ID,
- + LAST_PROP
- +};
- +
- +static inline IdeVimStateId
- +try_state_id (const gchar *name)
- +{
- + g_autofree const gchar *fullname = NULL;
- +
- + g_return_val_if_fail (!ide_str_empty0 (name), 0);
- +
- + fullname = g_strconcat (STATE_NAME_PREFIX, name, NULL);
- +
- + return g_quark_try_string (fullname);
- +}
- +
- +static GParamSpec *gParamSpecs [LAST_PROP];
- +
- +/**
- + * ide_vim_state_machine_add_state:
- + * @self: (in): #IdeVimStateMachine instance.
- + * @name: (in): the name of the state
- + * @state_enter_func: a pointer to a StateEnterFunc for the enter phase.
- + * @state_leave_func: a pointer to a StateLeaveFunc for the leave phase.
- + * @state_transition_func: a pointer to a StateCondFunc for the transition phase.
- + * @state_action_func: a pointer to a StateActionFunc for the action phase.
- + *
- + * Return the state IdeVimStateId.
- + *
- + * Returns: the corresponding IdeVimStateId or 0 if
- + * the state already exist.
- + */
- +IdeVimStateId
- +ide_vim_state_machine_add_state (IdeVimStateMachine *self,
- + const gchar *name,
- + StateEnterFunc enter_func,
- + StateLeaveFunc leave_func,
- + StateTransitionFunc transition_func,
- + StateActionFunc action_func)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- + IdeVimStateId id;
- + IdeVimState *state;
- +
- + g_return_val_if_fail (IDE_IS_VIM_STATE_MACHINE (self), 0);
- + g_return_val_if_fail (!ide_str_empty0 (name), 0);
- +
- +
- + id = try_state_id (name);
- + if (id && (state = (IdeVimState *)g_hash_table_lookup (priv->state_table, GINT_TO_POINTER (id))) != NULL)
- + {
- + ide_vim_state_change_funcs (state, enter_func, leave_func, transition_func, action_func);
- + }
- + else
- + {
- + state = ide_vim_state_new (name, enter_func, leave_func, transition_func, action_func);
- + id = ide_vim_state_get_id (state);
- + g_hash_table_insert (priv->state_table, GINT_TO_POINTER (id), state);
- + }
- +
- + return id;
- +}
- +
- +/**
- + * ide_vim_state_machine_remove_state_by_name:
- + * @self: (in): #IdeVimStateMachine instance.
- + * @name: (in): the name of the state
- + *
- + * Return the succes status of the operation
- + *
- + * Returns: TRUE if removed, FALSE overwise.
- + */
- +gboolean
- +ide_vim_state_machine_remove_state_by_name (IdeVimStateMachine *self,
- + const gchar *name)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- + IdeVimStateId id;
- +
- + g_return_val_if_fail (IDE_IS_VIM_STATE_MACHINE (self), FALSE);
- + g_return_val_if_fail (!ide_str_empty0 (name), FALSE);
- +
- + id = try_state_id (name);
- + if (id)
- + {
- + if (g_hash_table_remove (priv->state_table, GINT_TO_POINTER (id)))
- + {
- + if (priv->state_id == id)
- + {
- + priv->state_id = 0;
- + priv->previous_id = 0;
- + }
- +
- + return TRUE;
- + }
- + }
- +
- + return FALSE;
- +}
- +
- +/**
- + * ide_vim_state_machine_set_state:
- + * @self: (in): #IdeVimStateMachine instance.
- + * @id: (in): An existing IdeVimStateId.
- + *
- + * Return the succes status
- + *
- + * Returns: TRUE if succes, FALSE overwise.
- + */
- +gboolean
- +ide_vim_state_machine_set_state (IdeVimStateMachine *self,
- + IdeVimStateId id)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_STATE_MACHINE (self), FALSE);
- + g_return_val_if_fail (id != 0, FALSE);
- +
- + if (g_hash_table_lookup (priv->state_table, GINT_TO_POINTER (id)))
- + {
- + priv->previous_id = priv->state_id;
- + priv->state_id = id;
- + return TRUE;
- + }
- +
- + g_warning (_("The state id:%i is not registered on this state machine\n"), id);
- + return FALSE;
- +}
- +
- +/**
- + * ide_vim_state_machine_set_state_by_name:
- + * @self: (in): #IdeVimStateMachine instance.
- + * @name: (in): An existing #IdeVimState name
- + *
- + * Return the corresponding IdeVimStateId.
- + *
- + * Returns: the IdeVimStateId or 0 if the state doesn't exist.
- + */
- +IdeVimStateId
- +ide_vim_state_machine_set_state_by_name (IdeVimStateMachine *self,
- + const gchar *name)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- + IdeVimStateId id;
- +
- + g_return_val_if_fail (IDE_IS_VIM_STATE_MACHINE (self), 0);
- + g_return_val_if_fail (!ide_str_empty0 (name), 0);
- +
- + id = try_state_id (name);
- + if (!id)
- + {
- + g_warning (_("'%s' state doesn't exist\n"), name);
- + return 0;
- + }
- +
- + if (g_hash_table_lookup (priv->state_table, GINT_TO_POINTER (id)) == NULL)
- + {
- + g_warning (_("'%s' state is not registered on this state machine\n"), name);
- + return 0;
- + }
- +
- + priv->previous_id = priv->state_id;
- + priv->state_id = id;
- + return id;
- +}
- +
- +/**
- + * ide_vim_state_machine_get_state_name:
- + * @self: (in): #IdeVimStateMachine instance.
- + *
- + * Return the current state's name.
- + *
- + * Returns: (tranfert none): the current state's name or an empty
- + * string if the state is not set.
- + */
- +const gchar *
- +ide_vim_state_machine_get_state_name (IdeVimStateMachine *self)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- + IdeVimStateId id;
- +
- + g_return_val_if_fail (IDE_IS_VIM_STATE_MACHINE (self), NULL);
- +
- + id = priv->state_id;
- +
- + return (id) ? g_quark_to_string (id) : NULL;
- +}
- +
- +/**
- + * ide_vim_state_machine_get_state_id:
- + * @self: (in): #IdeVimStateMachine instance.
- + *
- + * Return the current state IdeVimStateId.
- + *
- + * Returns: a #IdeVimStateId.
- + */
- +IdeVimStateId
- +ide_vim_state_machine_get_state_id (IdeVimStateMachine *self)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- +
- + g_return_val_if_fail (IDE_IS_VIM_STATE_MACHINE (self), 0);
- +
- + return priv->state_id;
- +}
- +
- +/**
- + * ide_vim_state_machine_get_state_from_id:
- + * @self: (in): #IdeVimStateMachine instance.
- + * @id: (in): a registered #IdeVimStateId for this #IdeVimStateMachine.
- + *
- + * Return the corresponding #IdeVimState.
- + *
- + * Returns: a #IdeVimState.
- + */
- +IdeVimState *
- +ide_vim_state_machine_get_state_from_id (IdeVimStateMachine *self,
- + IdeVimStateId id)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- + const gchar *name;
- + IdeVimState *state;
- +
- + g_return_val_if_fail (IDE_IS_VIM_STATE_MACHINE (self), NULL);
- + g_return_val_if_fail (id > 0, NULL);
- +
- + state = (IdeVimState *)g_hash_table_lookup (priv->state_table, GINT_TO_POINTER (id));
- + if (state == NULL)
- + {
- + name = g_quark_to_string ((GQuark)id);
- + if (name == NULL)
- + g_warning (_("State id:%i doesn't exist\n"), id);
- + else if (!g_str_has_prefix (name, STATE_NAME_PREFIX))
- + g_warning (_("'%s' state doesn't exist\n"), name);
- + else
- + g_warning (_("'%s' state is not registered on this state machine\n"), name);
- +
- + return NULL;
- + }
- +
- + return state;
- +}
- +
- +/**
- + * ide_vim_state_machine_get_state_from_name:
- + * @self: (in): #IdeVimStateMachine instance.
- + * @name: (in): a registered state name for this #IdeVimStateMachine.
- + *
- + * Return the corresponding #IdeVimState.
- + *
- + * Returns: a #IdeVimState.
- + */
- +IdeVimState *
- +ide_vim_state_machine_get_state_from_name (IdeVimStateMachine *self,
- + const gchar *name)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- + IdeVimStateId id;
- + IdeVimState *state = NULL;
- +
- + g_return_val_if_fail (IDE_IS_VIM_STATE_MACHINE (self), NULL);
- + g_return_val_if_fail (!ide_str_empty0 (name), NULL);
- +
- + id = try_state_id (name);
- + if (!id)
- + {
- + g_warning (_("'%s' state doesn't exist\n"), name);
- + return NULL;
- + }
- +
- + state = (IdeVimState *)g_hash_table_lookup (priv->state_table, GINT_TO_POINTER (id));
- + if (state == NULL)
- + g_warning (_("'%s' state is not registered on this state machine\n"), name);
- +
- + return state;
- +}
- +
- +/**
- + * ide_vim_state_machine_get_id_from_name:
- + * @self: (in): #IdeVimStateMachine instance.
- + * @name: (in): a registered state name for this #IdeVimStateMachine.
- + *
- + * Return the corresponding #IdeVimStateId.
- + *
- + * Returns: a #IdeVimStateId.
- + */
- +IdeVimStateId
- +ide_vim_state_machine_get_id_from_name (IdeVimStateMachine *self,
- + const gchar *name)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- + IdeVimStateId id = 0;
- +
- + g_return_val_if_fail (IDE_IS_VIM_STATE_MACHINE (self), 0);
- + g_return_val_if_fail (!ide_str_empty0 (name), 0);
- +
- + id = try_state_id (name);
- + if (!id)
- + {
- + g_warning (_("'%s' state doesn't exist\n"), name);
- + return 0;
- + }
- +
- + if (g_hash_table_lookup (priv->state_table, GINT_TO_POINTER (id)) == NULL)
- + {
- + g_warning (_("'%s' state is not registered on this state machine\n"), name);
- + return 0;
- + }
- +
- + return id;
- +}
- +
- +gboolean
- +ide_vim_state_machine_run_once (IdeVimStateMachine *self,
- + gpointer data)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- + IdeVimState *state;
- + IdeVimStateId current_id;
- + IdeVimStateId transition_id = 0;
- +
- + g_return_val_if_fail (IDE_IS_VIM_STATE_MACHINE (self), FALSE);
- +
- + current_id = priv->state_id;
- + if (!current_id)
- + {
- + g_warning (_("You need to start from an existing state"));
- + return FALSE;
- + }
- +
- + /* TODO: even when transitioning to the same state, do enter-leave */
- + state = ide_vim_state_machine_get_state_from_id (self, current_id);
- + if (priv->previous_id != current_id && state->enter_func)
- + state->enter_func (self, data);
- +
- + if (state->transition_func)
- + transition_id = state->transition_func (self, data);
- +
- + /* TODO: check transition_id validity */
- + /* TODO: need return gboolean ? */
- + if (state->action_func)
- + state->action_func (self, data);
- +
- + if (current_id != transition_id && state->leave_func)
- + state->leave_func (self, data);
- +
- + if (transition_id)
- + ide_vim_state_machine_set_state (self, transition_id);
- +
- + return (transition_id != 0);
- +}
- +
- +IdeVimStateMachine *
- +ide_vim_state_machine_new (void)
- +{
- + return g_object_new (IDE_TYPE_VIM_STATE_MACHINE, NULL);
- +}
- +
- +static void
- +ide_vim_state_machine_finalize (GObject *object)
- +{
- + IdeVimStateMachine *self = IDE_VIM_STATE_MACHINE (object);
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- +
- + g_clear_pointer (&priv->state_table, g_hash_table_unref);
- +
- + G_OBJECT_CLASS (ide_vim_state_machine_parent_class)->finalize (object);
- +}
- +
- +static void
- +ide_vim_state_machine_get_property (GObject *object,
- + guint prop_id,
- + GValue *value,
- + GParamSpec *pspec)
- +{
- + IdeVimStateMachine *self = IDE_VIM_STATE_MACHINE (object);
- +
- + switch (prop_id)
- + {
- + case PROP_STATE_NAME:
- + g_value_set_string (value, ide_vim_state_machine_get_state_name (self));
- + break;
- +
- + case PROP_STATE_ID:
- + g_value_set_uint (value, ide_vim_state_machine_get_state_id (self));
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_state_machine_set_property (GObject *object,
- + guint prop_id,
- + const GValue *value,
- + GParamSpec *pspec)
- +{
- + IdeVimStateMachine *self = IDE_VIM_STATE_MACHINE (object);
- +
- + switch (prop_id)
- + {
- + case PROP_STATE_NAME:
- + ide_vim_state_machine_set_state_by_name (self, g_value_get_string (value));
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +ide_vim_state_machine_init (IdeVimStateMachine *self)
- +{
- + IdeVimStateMachinePrivate *priv = ide_vim_state_machine_get_instance_private (self);
- +
- + priv->state_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
- + NULL, (GDestroyNotify)ide_vim_state_unref);
- +}
- +
- +static void
- +ide_vim_state_machine_class_init (IdeVimStateMachineClass *klass)
- +{
- + GObjectClass *object_class = G_OBJECT_CLASS (klass);
- +
- + object_class->finalize = ide_vim_state_machine_finalize;
- + object_class->get_property = ide_vim_state_machine_get_property;
- + object_class->set_property = ide_vim_state_machine_set_property;
- +
- + /**
- + * IdeVimStateMachine:state-name:
- + *
- + * A string holding the name of current state.
- + */
- + gParamSpecs[PROP_STATE_NAME] =
- + g_param_spec_string ("state-name",
- + _("current state name"),
- + _("The name of the current state."),
- + NULL,
- + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * IdeVimStateMachine:state-id:
- + *
- + * the IdeVimStateId of current state.
- + */
- + gParamSpecs[PROP_STATE_ID] =
- + g_param_spec_uint64 ("state-id",
- + _("current state id"),
- + _("The id of the current state."),
- + 0,
- + G_MAXUINT32,
- + 0,
- + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- +
- + g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
- +}
- diff --git a/libide/vim/ide-vim-state-machine.h b/libide/vim/ide-vim-state-machine.h
- new file mode 100644
- index 0000000..44b36b7
- --- /dev/null
- +++ b/libide/vim/ide-vim-state-machine.h
- @@ -0,0 +1,63 @@
- +/* ide-vim-state-machine.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_STATE_MACHINE_H
- +#define IDE_VIM_STATE_MACHINE_H
- +
- +#include <glib.h>
- +
- +#include "ide-vim-state.h"
- +
- +G_BEGIN_DECLS
- +
- +#define IDE_TYPE_VIM_STATE_MACHINE (ide_vim_state_machine_get_type())
- +
- +G_DECLARE_FINAL_TYPE (IdeVimStateMachine, ide_vim_state_machine, IDE, VIM_STATE_MACHINE, GObject)
- +
- +struct _IdeVimStateMachine
- +{
- + GObject parent;
- +};
- +
- +IdeVimStateId ide_vim_state_machine_add_state (IdeVimStateMachine *self,
- + const gchar *name,
- + StateEnterFunc enter_func,
- + StateLeaveFunc leave_func,
- + StateTransitionFunc transition_func,
- + StateActionFunc action_func);
- +IdeVimStateId ide_vim_state_machine_get_id_from_name (IdeVimStateMachine *self,
- + const gchar *name);
- +IdeVimState *ide_vim_state_machine_get_state_from_id (IdeVimStateMachine *self,
- + IdeVimStateId id);
- +IdeVimState *ide_vim_state_machine_get_state_from_name (IdeVimStateMachine *self,
- + const gchar *name);
- +const gchar *ide_vim_state_machine_get_state_name (IdeVimStateMachine *self);
- +IdeVimStateId ide_vim_state_machine_get_state_id (IdeVimStateMachine *self);
- +IdeVimStateMachine *ide_vim_state_machine_new (void);
- +gboolean ide_vim_state_machine_remove_state_by_name (IdeVimStateMachine *self,
- + const gchar *name);
- +gboolean ide_vim_state_machine_run_once (IdeVimStateMachine *self,
- + gpointer data);
- +gboolean ide_vim_state_machine_set_state (IdeVimStateMachine *self,
- + IdeVimStateId id);
- +IdeVimStateId ide_vim_state_machine_set_state_by_name (IdeVimStateMachine *self,
- + const gchar *name);
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_STATE_MACHINE_H */
- diff --git a/libide/vim/ide-vim-state-private.h b/libide/vim/ide-vim-state-private.h
- new file mode 100644
- index 0000000..8f2512d
- --- /dev/null
- +++ b/libide/vim/ide-vim-state-private.h
- @@ -0,0 +1,37 @@
- +/* ide-vim-state-private.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_STATE_PRIVATE_H
- +#define IDE_VIM_STATE_PRIVATE_H
- +
- +#include <glib-object.h>
- +
- +G_BEGIN_DECLS
- +
- +struct _IdeVimState
- +{
- + volatile gint ref_count;
- +
- + IdeVimStateId id;
- + StateEnterFunc enter_func;
- + StateLeaveFunc leave_func;
- + StateTransitionFunc transition_func;
- + StateActionFunc action_func;
- +};
- +
- +endif /* IDE_VIM_STATE_PRIVATE_H */
- diff --git a/libide/vim/ide-vim-state-result.c b/libide/vim/ide-vim-state-result.c
- new file mode 100644
- index 0000000..51ff639
- --- /dev/null
- +++ b/libide/vim/ide-vim-state-result.c
- @@ -0,0 +1,73 @@
- +/* ide-vim-state-result.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +#include <string.h>
- +#include <errno.h>
- +#include <glib/gi18n.h>
- +#include <glib/gprintf.h>
- +
- +#include "ide-debug.h"
- +#include "ide-macros.h"
- +
- +#include <glib/gi18n.h>
- +
- +#include "ide-vim-state-result.h"
- +
- +G_DEFINE_BOXED_TYPE (IdeVimStateResult, ide_vim_state_result, ide_vim_state_result_ref, ide_vim_state_result_unref)
- +
- +struct _IdeVimStateResult
- +{
- + volatile gint ref_count;
- +};
- +
- +static void
- +ide_vim_state_result_finalize (IdeVimStateResult *self)
- +{
- + g_free (self);
- +}
- +
- +IdeVimStateResult *
- +ide_vim_state_result_ref (IdeVimStateResult *self)
- +{
- + g_return_val_if_fail (self, NULL);
- + g_return_val_if_fail (self->ref_count > 0, NULL);
- +
- + g_atomic_int_inc (&self->ref_count);
- +
- + return self;
- +}
- +
- +void
- +ide_vim_state_result_unref (IdeVimStateResult *self)
- +{
- + g_return_if_fail (self);
- + g_return_if_fail (self->ref_count > 0);
- +
- + if (g_atomic_int_dec_and_test (&self->ref_count))
- + ide_vim_state_result_finalize (self);
- +}
- +
- +IdeVimStateResult *
- +ide_vim_state_result_new (void)
- +{
- + IdeVimStateResult *self;
- +
- + self = g_new0 (IdeVimStateResult, 1);
- + self->ref_count = 1;
- +
- + return self;
- +}
- diff --git a/libide/vim/ide-vim-state-result.h b/libide/vim/ide-vim-state-result.h
- new file mode 100644
- index 0000000..3fbbb93
- --- /dev/null
- +++ b/libide/vim/ide-vim-state-result.h
- @@ -0,0 +1,39 @@
- +/* ide-vim-state-result.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_STATE_RESULT_H
- +#define IDE_VIM_STATE_RESULT_H
- +
- +#include <glib-object.h>
- +
- +#include "ide-vim-state.h"
- +
- +G_BEGIN_DECLS
- +
- +#define IDE_TYPE_VIM_STATE_RESULT (ide_vim_state_result_get_type())
- +
- +typedef struct _IdeVimStateResult IdeVimStateResult;
- +
- +IdeVimStateResult *ide_vim_state_result_new (void);
- +
- +IdeVimStateResult *ide_vim_state_result_ref (IdeVimStateResult *self);
- +void ide_vim_state_result_unref (IdeVimStateResult *self);
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_STATE_RESULT_H */
- diff --git a/libide/vim/ide-vim-state.c b/libide/vim/ide-vim-state.c
- new file mode 100644
- index 0000000..caa3b5f
- --- /dev/null
- +++ b/libide/vim/ide-vim-state.c
- @@ -0,0 +1,162 @@
- +/* ide-vim-state.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +#include <string.h>
- +#include <errno.h>
- +#include <glib/gi18n.h>
- +#include <glib/gprintf.h>
- +
- +#include "ide-debug.h"
- +#include "ide-macros.h"
- +
- +#include "ide-vim-state.h"
- +
- +G_DEFINE_BOXED_TYPE (IdeVimState, ide_vim_state, ide_vim_state_ref, ide_vim_state_unref)
- +
- +/**
- + * ide_vim_state_change_funcs:
- + * @self: (in): #IdeVimState instance.
- + * @state_enter_func: a pointer to a StateEnterFunc for the enter phase.
- + * @state_leave_func: a pointer to a StateLeaveFunc for the leave phase.
- + * @state_transition_func: a pointer to a StateTransitionFunc for the transition phase.
- + * @state_action_func: a pointer to a StateActionFunc for the action phase.
- + *
- + */
- +void
- +ide_vim_state_change_funcs (IdeVimState *self,
- + StateEnterFunc enter_func,
- + StateLeaveFunc leave_func,
- + StateTransitionFunc transition_func,
- + StateActionFunc action_func)
- +{
- + g_return_if_fail (self);
- +
- + self->enter_func = enter_func;
- + self->leave_func = leave_func;
- + self->transition_func = transition_func;
- + self->action_func = action_func;
- +}
- +
- +/**
- + * ide_vim_state_get_name:
- + * @self: (in): #IdeVimState instance.
- + *
- + * Return the state's name.
- + *
- + * Returns: (tranfert none): the state's name.
- + */
- +const gchar *
- +ide_vim_state_get_name (IdeVimState *self)
- +{
- + g_return_val_if_fail (self, NULL);
- +
- + return self->name;
- +}
- +
- +/**
- + * ide_vim_state_get_id:
- + * @self: (in): #IdeVimState instance.
- + *
- + * Return the #IdeVimStateId of the state.
- + *
- + * Returns: the #IdeVimStateId of the state.
- + */
- +IdeVimStateId
- +ide_vim_state_get_id (IdeVimState *self)
- +{
- + g_return_val_if_fail (self, 0);
- +
- + return self->id;
- +}
- +
- +static void
- +ide_vim_state_finalize (IdeVimState *self)
- +{
- + g_clear_pointer (&self->name, g_free);
- + g_free (self);
- +}
- +
- +/**
- + * ide_vim_state_ref:
- + * @self: (in): #IdeVimState instance.
- + *
- + * Increment #IdeVimState ref count.
- + *
- + * Returns: the #IdeVimState itself.
- + */
- +IdeVimState *
- +ide_vim_state_ref (IdeVimState *self)
- +{
- + g_return_val_if_fail (self, NULL);
- + g_return_val_if_fail (self->ref_count > 0, NULL);
- +
- + g_atomic_int_inc (&self->ref_count);
- +
- + return self;
- +}
- +
- +/**
- + * ide_vim_state_unref:
- + * @self: (in): #IdeVimState instance.
- + *
- + * Decrement #IdeVimState ref count.
- + */
- +void
- +ide_vim_state_unref (IdeVimState *self)
- +{
- + g_return_if_fail (self);
- + g_return_if_fail (self->ref_count > 0);
- +
- + if (g_atomic_int_dec_and_test (&self->ref_count))
- + ide_vim_state_finalize (self);
- +}
- +
- +/**
- + * ide_vim_state_new:
- + * @name: (in): the name of the state
- + * @state_enter_func: a pointer to a StateEnterFunc for the enter phase.
- + * @state_leave_func: a pointer to a StateLeaveFunc for the leave phase.
- + * @state_transition_func: a pointer to a StateTransitionFunc for the transition phase.
- + * @state_action_func: a pointer to a StateActionFunc for the action phase.
- + *
- + * Return an #IdeVimState instance.
- + *
- + * Returns: A new #IdeVimState or NULL if the state already exist.
- + */
- +IdeVimState *
- +ide_vim_state_new (const gchar *name,
- + StateEnterFunc enter_func,
- + StateLeaveFunc leave_func,
- + StateTransitionFunc transition_func,
- + StateActionFunc action_func)
- +{
- + IdeVimState *self;
- + g_autofree gchar *fullname;
- +
- + g_return_val_if_fail (!ide_str_empty0 (name), NULL);
- +
- + fullname = g_strconcat (STATE_NAME_PREFIX, name, NULL);
- +
- + self = g_new0 (IdeVimState, 1);
- + self->ref_count = 1;
- + self->id = g_quark_from_string (fullname);
- + self->name = g_strdup (name);
- +
- + ide_vim_state_change_funcs (self, enter_func, leave_func, transition_func, action_func);
- +
- + return self;
- +}
- diff --git a/libide/vim/ide-vim-state.h b/libide/vim/ide-vim-state.h
- new file mode 100644
- index 0000000..83451d2
- --- /dev/null
- +++ b/libide/vim/ide-vim-state.h
- @@ -0,0 +1,71 @@
- +/* ide-vim-state.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef IDE_VIM_STATE_H
- +#define IDE_VIM_STATE_H
- +
- +#include <glib-object.h>
- +
- +G_BEGIN_DECLS
- +
- +#define IDE_TYPE_VIM_STATE (ide_vim_state_get_type())
- +
- +/* Name prefix used to avoid confict with already existing quark string */
- +#define STATE_NAME_PREFIX "ide-vim-state-"
- +
- +typedef struct _IdeVimStateMachine IdeVimStateMachine;
- +typedef GQuark IdeVimStateId;
- +
- +typedef void (*StateEnterFunc) (IdeVimStateMachine *state_machine, gpointer data);
- +typedef void (*StateLeaveFunc) (IdeVimStateMachine *state_machine, gpointer data);
- +typedef IdeVimStateId (*StateTransitionFunc) (IdeVimStateMachine *state_machine, gpointer data);
- +typedef gboolean (*StateActionFunc) (IdeVimStateMachine *state_machine, gpointer data);
- +
- +struct _IdeVimState
- +{
- + volatile gint ref_count;
- +
- + IdeVimStateId id;
- + const gchar *name;
- + StateEnterFunc enter_func;
- + StateLeaveFunc leave_func;
- + StateTransitionFunc transition_func;
- + StateActionFunc action_func;
- +};
- +
- +/* TODO: ide_vim_state_overwrite used ? */
- +typedef struct _IdeVimState IdeVimState;
- +
- +IdeVimState *ide_vim_state_new (const gchar *name,
- + StateEnterFunc enter_func,
- + StateLeaveFunc leave_func,
- + StateTransitionFunc transition_func,
- + StateActionFunc action_func);
- +void ide_vim_state_change_funcs (IdeVimState *self,
- + StateEnterFunc enter_func,
- + StateLeaveFunc leave_func,
- + StateTransitionFunc transition_func,
- + StateActionFunc action_func);
- +const gchar *ide_vim_state_get_name (IdeVimState *self);
- +IdeVimStateId ide_vim_state_get_id (IdeVimState *self);
- +IdeVimState *ide_vim_state_ref (IdeVimState *self);
- +void ide_vim_state_unref (IdeVimState *self);
- +
- +G_END_DECLS
- +
- +#endif /* IDE_VIM_STATE_H */
- diff --git a/plugins/command-bar/Makefile.am b/plugins/command-bar/Makefile.am
- index 4833eb1..1992509 100644
- --- a/plugins/command-bar/Makefile.am
- +++ b/plugins/command-bar/Makefile.am
- @@ -12,6 +12,10 @@ libcommand_bar_la_SOURCES = \
- gb-command-bar-resources.h \
- gb-command-bar.c \
- gb-command-bar.h \
- + gb-command-bar-item.c \
- + gb-command-bar-item.h \
- + gb-command-complete-item.c \
- + gb-command-complete-item.h \
- gb-command-gaction-provider.c \
- gb-command-gaction-provider.h \
- gb-command-gaction.c \
- diff --git a/plugins/command-bar/gb-command-bar-item.c b/plugins/command-bar/gb-command-bar-item.c
- new file mode 100644
- index 0000000..8700f0b
- --- /dev/null
- +++ b/plugins/command-bar/gb-command-bar-item.c
- @@ -0,0 +1,257 @@
- +/* gb-command-bar-item.c
- + *
- + * Copyright (C) 2014 Christian Hergert <christian@hergert.me>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <glib/gi18n.h>
- +
- +#include "gb-command-bar-item.h"
- +#include "gb-widget.h"
- +
- +struct _GbCommandBarItem
- +{
- + GtkBin parent_instance;
- + GbCommandResult *result;
- +
- + GtkWidget *command_text;
- + GtkWidget *result_text;
- + GtkWidget *equal_label;
- + GtkWidget *status_image;
- + GtkWidget *status_box;
- +};
- +
- +G_DEFINE_TYPE (GbCommandBarItem, gb_command_bar_item, GTK_TYPE_BIN)
- +
- +enum {
- + PROP_0,
- + PROP_RESULT,
- + LAST_PROP
- +};
- +
- +static GParamSpec *gParamSpecs [LAST_PROP];
- +
- +GtkWidget *
- +gb_command_bar_item_new (GbCommandResult *result)
- +{
- + return g_object_new (GB_TYPE_COMMAND_BAR_ITEM,
- + "result", result,
- + NULL);
- +}
- +
- +/**
- + * gb_command_bar_item_get_result:
- + * @item: A #GbCommandBarItem.
- + *
- + * Retrieves the result text widget so it can be used in the command bar
- + * sizing group.
- + *
- + * Returns: (transfer none): The result text widget.
- + */
- +GtkWidget *
- +gb_command_bar_item_get_result (GbCommandBarItem *item)
- +{
- + g_return_val_if_fail (GB_IS_COMMAND_BAR_ITEM (item), NULL);
- +
- + return item->result_text;
- +}
- +
- +static gboolean
- +error_status_to_icon_name (GBinding *binding,
- + const GValue *from_value,
- + GValue *to_value,
- + gpointer user_data)
- +{
- + GbCommandBarItem *item = GB_COMMAND_BAR_ITEM (user_data);
- + gboolean error_status = g_value_get_boolean (from_value);
- +
- + if (error_status)
- + g_value_set_string (to_value, "dialog-warning-symbolic");
- + else if (!gb_command_result_get_is_running (item->result))
- + g_value_set_string (to_value, "");
- +
- + return TRUE;
- +}
- +
- +static gboolean
- +running_status_to_icon_name (GBinding *binding,
- + const GValue *from_value,
- + GValue *to_value,
- + gpointer user_data)
- +{
- + GbCommandBarItem *item = GB_COMMAND_BAR_ITEM (user_data);
- + gboolean running_status = g_value_get_boolean (from_value);
- +
- + if (running_status && !gb_command_result_get_is_error (item->result))
- + g_value_set_string (to_value, "system-run-symbolic");
- + else if (gb_command_result_get_is_error (item->result))
- + g_value_set_string (to_value, "dialog-warning-symbolic");
- + else
- + g_value_set_string (to_value, "");
- +
- + return TRUE;
- +}
- +
- +static gboolean
- +string_to_boolean (GBinding *binding,
- + const GValue *from_value,
- + GValue *to_value,
- + gpointer user_data)
- +{
- + g_value_set_boolean (to_value, !!g_value_get_string (from_value));
- + return TRUE;
- +}
- +
- +static void
- +gb_command_bar_item_set_result (GbCommandBarItem *item,
- + GbCommandResult *result)
- +{
- + g_return_if_fail (GB_IS_COMMAND_BAR_ITEM (item));
- + g_return_if_fail (GB_IS_COMMAND_RESULT (result));
- +
- + if (item->result != result)
- + {
- + g_clear_object (&item->result);
- +
- + if (result)
- + {
- + item->result = g_object_ref (result);
- + g_object_bind_property (result, "command-text",
- + item->command_text, "label",
- + G_BINDING_SYNC_CREATE);
- + g_object_bind_property (result, "result-text",
- + item->result_text, "label",
- + G_BINDING_SYNC_CREATE);
- + g_object_bind_property_full (result, "result-text",
- + item->equal_label, "visible",
- + G_BINDING_SYNC_CREATE,
- + string_to_boolean,
- + NULL,
- + item,
- + NULL);
- + g_object_bind_property_full (result, "result-text",
- + item->result_text, "visible",
- + G_BINDING_SYNC_CREATE,
- + string_to_boolean,
- + NULL,
- + item,
- + NULL);
- + g_object_bind_property_full (result, "is-error",
- + item->status_image, "icon-name",
- + G_BINDING_SYNC_CREATE,
- + error_status_to_icon_name,
- + NULL, NULL, NULL);
- + g_object_bind_property_full (result, "is-running",
- + item->status_image, "icon-name",
- + G_BINDING_SYNC_CREATE,
- + running_status_to_icon_name,
- + NULL,
- + item,
- + NULL);
- + }
- +
- + g_object_notify_by_pspec (G_OBJECT (item), gParamSpecs [PROP_RESULT]);
- + }
- +}
- +
- +static void
- +gb_command_bar_item_finalize (GObject *object)
- +{
- + GbCommandBarItem *self = GB_COMMAND_BAR_ITEM (object);
- +
- + g_clear_object (&self->result);
- +
- + G_OBJECT_CLASS (gb_command_bar_item_parent_class)->finalize (object);
- +}
- +
- +static void
- +gb_command_bar_item_get_property (GObject *object,
- + guint prop_id,
- + GValue *value,
- + GParamSpec *pspec)
- +{
- + GbCommandBarItem *self = GB_COMMAND_BAR_ITEM (object);
- +
- + switch (prop_id)
- + {
- + case PROP_RESULT:
- + g_value_set_object (value, gb_command_bar_item_get_result (self));
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +gb_command_bar_item_set_property (GObject *object,
- + guint prop_id,
- + const GValue *value,
- + GParamSpec *pspec)
- +{
- + GbCommandBarItem *self = GB_COMMAND_BAR_ITEM (object);
- +
- + switch (prop_id)
- + {
- + case PROP_RESULT:
- + gb_command_bar_item_set_result (self, g_value_get_object (value));
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +gb_command_bar_item_class_init (GbCommandBarItemClass *klass)
- +{
- + GObjectClass *object_class = G_OBJECT_CLASS (klass);
- + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- +
- + object_class->finalize = gb_command_bar_item_finalize;
- + object_class->get_property = gb_command_bar_item_get_property;
- + object_class->set_property = gb_command_bar_item_set_property;
- +
- + gtk_widget_class_set_template_from_resource (widget_class,
- + "/org/gnome/builder/plugins/command-bar/gb-command-bar-item.ui");
- +
- + GB_WIDGET_CLASS_BIND (widget_class, GbCommandBarItem, command_text);
- + GB_WIDGET_CLASS_BIND (widget_class, GbCommandBarItem, result_text);
- + GB_WIDGET_CLASS_BIND (widget_class, GbCommandBarItem, equal_label);
- + GB_WIDGET_CLASS_BIND (widget_class, GbCommandBarItem, status_image);
- + GB_WIDGET_CLASS_BIND (widget_class, GbCommandBarItem, status_box);
- +
- + gParamSpecs [PROP_RESULT] =
- + g_param_spec_object ("result",
- + _("Result"),
- + _("The result to be visualized in the item."),
- + GB_TYPE_COMMAND_RESULT,
- + (G_PARAM_READWRITE |
- + G_PARAM_CONSTRUCT_ONLY |
- + G_PARAM_STATIC_STRINGS));
- +
- + g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
- +}
- +
- +static void
- +gb_command_bar_item_init (GbCommandBarItem *self)
- +{
- + gint width, height;
- +
- + gtk_widget_init_template (GTK_WIDGET (self));
- +
- + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height);
- + gtk_widget_set_size_request (self->status_box, width, height);
- +}
- diff --git a/plugins/command-bar/gb-command-bar-item.h b/plugins/command-bar/gb-command-bar-item.h
- new file mode 100644
- index 0000000..4db55da
- --- /dev/null
- +++ b/plugins/command-bar/gb-command-bar-item.h
- @@ -0,0 +1,39 @@
- +/* gb-command-bar-item.h
- + *
- + * Copyright (C) 2014 Christian Hergert <christian@hergert.me>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef GB_COMMAND_BAR_ITEM_H
- +#define GB_COMMAND_BAR_ITEM_H
- +
- +#include <gtk/gtk.h>
- +
- +#include "gb-command-result.h"
- +
- +G_BEGIN_DECLS
- +
- +#define GB_TYPE_COMMAND_BAR_ITEM (gb_command_bar_item_get_type())
- +
- +G_DECLARE_FINAL_TYPE (GbCommandBarItem, gb_command_bar_item,
- + GB, COMMAND_BAR_ITEM, GtkBin)
- +
- +GtkWidget *gb_command_bar_item_new (GbCommandResult *result);
- +void gb_command_bar_item_connect_close (GbCommandBarItem *item);
- +GtkWidget *gb_command_bar_item_get_result (GbCommandBarItem *item);
- +
- +G_END_DECLS
- +
- +#endif /* GB_COMMAND_BAR_ITEM_H */
- diff --git a/plugins/command-bar/gb-command-bar-item.ui b/plugins/command-bar/gb-command-bar-item.ui
- new file mode 100644
- index 0000000..d5cb27b
- --- /dev/null
- +++ b/plugins/command-bar/gb-command-bar-item.ui
- @@ -0,0 +1,83 @@
- +<?xml version="1.0" encoding="UTF-8"?>
- +<interface>
- + <!-- interface-requires gtk+ 3.8 -->
- + <template class="GbCommandBarItem" parent="GtkBin">
- + <property name="visible">True</property>
- + <child>
- + <object class="GtkBox" id="hbox1">
- + <property name="visible">True</property>
- + <property name="orientation">horizontal</property>
- + <property name="margin">3</property>
- + <style>
- + <class name="gb-command-bar-item"/>
- + </style>
- + <child>
- + <object class="GtkBox" id="status_box">
- + <property name="visible">True</property>
- + <property name="margin-left">6</property>
- + <child>
- + <object class="GtkImage" id="status_image">
- + <property name="visible">True</property>
- + <property name="halign">center</property>
- + <property name="valign">center</property>
- + </object>
- + </child>
- + </object>
- + </child>
- + <child>
- + <object class="GtkBox" id="vbox1">
- + <property name="visible">True</property>
- + <property name="margin-left">12</property>
- + <property name="margin-right">3</property>
- + <property name="margin-top">3</property>
- + <property name="margin-bottom">3</property>
- + <property name="orientation">vertical</property>
- + <child>
- + <object class="GtkBox" id="hbox2">
- + <property name="visible">True</property>
- + <property name="vexpand">False</property>
- + <property name="spacing">6</property>
- + <child>
- + <object class="GtkLabel" id="command_text">
- + <property name="visible">True</property>
- + <property name="halign">start</property>
- + </object>
- + <packing>
- + <property name="fill">True</property>
- + </packing>
- + </child>
- + <child>
- + <object class="GtkLabel" id="equal_label">
- + <property name="visible">True</property>
- + <property name="label">:</property>
- + </object>
- + <packing>
- + <property name="fill">True</property>
- + </packing>
- + </child>
- + </object>
- + <packing>
- + <property name="expand">True</property>
- + <property name="fill">True</property>
- + </packing>
- + </child>
- + <child>
- + <object class="GtkLabel" id="result_text">
- + <property name="visible">True</property>
- + <property name="halign">start</property>
- + <property name="vexpand">False</property>
- + </object>
- + <packing>
- + <property name="fill">True</property>
- + </packing>
- + </child>
- + </object>
- + <packing>
- + <property name="expand">True</property>
- + <property name="fill">True</property>
- + </packing>
- + </child>
- + </object>
- + </child>
- + </template>
- +</interface>
- diff --git a/plugins/command-bar/gb-command-bar.c b/plugins/command-bar/gb-command-bar.c
- index 03e82b9..8416cb3 100644
- --- a/plugins/command-bar/gb-command-bar.c
- +++ b/plugins/command-bar/gb-command-bar.c
- @@ -23,9 +23,13 @@
- #include "gb-command.h"
- #include "gb-command-bar-resources.h"
- #include "gb-command-bar.h"
- +#include "gb-command-bar-item.h"
- +#include "gb-command-complete-item.h"
- #include "gb-command-gaction-provider.h"
- #include "gb-command-manager.h"
- +#include "gb-command-vim.h"
- #include "gb-command-vim-provider.h"
- +#include "gb-command-result.h"
- #include "gb-glib.h"
- #include "gb-slider.h"
- #include "gb-string.h"
- @@ -34,6 +38,8 @@
- #include "gb-workbench.h"
- #include "gb-workbench-addin.h"
- +#include <glib/gprintf.h>
- +
- struct _GbCommandBar
- {
- GtkBin parent_instance;
- @@ -43,9 +49,15 @@ struct _GbCommandBar
- GSimpleAction *show_action;
- + gulong set_focus_handler;
- +
- GtkSizeGroup *result_size_group;
- GtkEntry *entry;
- + GtkMenuButton *results_button;
- + GtkPopover *popover;
- + GtkWidget *command_box;
- GtkListBox *list_box;
- + gint result_y_pos;
- GtkScrolledWindow *scroller;
- GtkScrolledWindow *completion_scroller;
- GtkFlowBox *flow_box;
- @@ -58,6 +70,7 @@ struct _GbCommandBar
- gchar *saved_text;
- int saved_position;
- gboolean saved_position_valid;
- + gboolean is_in_results_popup;
- };
- static void workbench_addin_init (GbWorkbenchAddinInterface *iface);
- @@ -166,6 +179,58 @@ find_alternate_focus (GtkWidget *focus)
- return focus;
- }
- +static void
- +gb_command_bar_results_toggled_cb (GbCommandBar *self,
- + GtkToggleButton *button)
- +{
- + g_return_if_fail (GB_IS_COMMAND_BAR (self));
- + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
- +
- + if (gtk_toggle_button_get_active (button))
- + {
- + gtk_widget_grab_focus (GTK_WIDGET (self->list_box));
- + gtk_widget_hide (GTK_WIDGET (self->completion_scroller));
- + }
- + else
- + {
- + gtk_widget_hide (GTK_WIDGET (self->popover));
- + }
- +}
- +
- +static gint
- +gb_command_bar_results_length (GbCommandBar *self)
- +{
- + GList *children;
- + gint len;
- +
- + g_return_val_if_fail (GB_IS_COMMAND_BAR (self), 0);
- +
- + children = gtk_container_get_children (GTK_CONTAINER (self->list_box));
- + len = g_list_length (children);
- +
- + g_list_free (children);
- + return len;
- +}
- +
- +static void
- +gb_command_bar_results_show (GbCommandBar *self)
- +{
- + g_return_if_fail (GB_IS_COMMAND_BAR (self));
- + if (gb_command_bar_results_length (self) != 0)
- + {
- + gb_command_bar_show (self);
- + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->results_button), TRUE);
- + }
- +}
- +
- +static void
- +gb_command_bar_results_hide (GbCommandBar *self)
- +{
- + g_return_if_fail (GB_IS_COMMAND_BAR (self));
- +
- + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->results_button), FALSE);
- +}
- +
- /**
- * gb_command_bar_hide:
- * @bar: A #GbCommandBar
- @@ -185,6 +250,7 @@ gb_command_bar_hide (GbCommandBar *self)
- return;
- gb_slider_set_position (slider, GB_SLIDER_NONE);
- + gb_command_bar_results_hide (self);
- if (self->last_focus)
- focus = find_alternate_focus (self->last_focus);
- @@ -242,9 +308,148 @@ static void
- gb_command_bar_push_result (GbCommandBar *self,
- GbCommandResult *result)
- {
- - /*
- - * TODO: if we decide to keep results visible, add them to list here.
- - */
- + GtkAdjustment *vadj;
- + GdkFrameClock *frame_clock;
- + GtkWidget *item;
- + GtkWidget *result_widget;
- + gdouble upper;
- +
- + g_return_if_fail (GB_IS_COMMAND_BAR (self));
- + g_return_if_fail (GB_IS_COMMAND_RESULT (result));
- +
- + item = g_object_new (GB_TYPE_COMMAND_BAR_ITEM,
- + "result", result,
- + "visible", TRUE,
- + NULL);
- + gtk_container_add (GTK_CONTAINER (self->list_box), item);
- +
- + result_widget = gb_command_bar_item_get_result (GB_COMMAND_BAR_ITEM (item));
- + gtk_size_group_add_widget (self->result_size_group, result_widget);
- +
- + vadj = gtk_list_box_get_adjustment (self->list_box);
- + upper = gtk_adjustment_get_upper (vadj);
- + frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (self->list_box));
- +
- + gb_command_bar_results_show (self);
- + ide_object_animate (vadj,
- + IDE_ANIMATION_EASE_IN_CUBIC,
- + 250,
- + frame_clock,
- + "value", upper,
- + NULL);
- +}
- +
- +static void
- +gb_command_bar_results_clear_all (GbCommandBar *self,
- + GtkWidget *menuitem)
- +{
- + GList *children;
- + GList *l;
- +
- + children = gtk_container_get_children (GTK_CONTAINER (self->list_box));
- + for (l = children; l != NULL; l = l->next)
- + gtk_widget_destroy (GTK_WIDGET (l->data));
- + g_list_free (children);
- +}
- +
- +static void
- +gb_command_bar_results_clear (GbCommandBar *self,
- + GtkWidget *menuitem)
- +{
- + GtkListBoxRow *row;
- +
- + if (self->result_y_pos == -1)
- + row = gtk_list_box_get_selected_row (self->list_box);
- + else
- + row = gtk_list_box_get_row_at_y (self->list_box, self->result_y_pos);
- +
- + if (row != NULL)
- + gtk_widget_destroy (GTK_WIDGET (row));
- +}
- +
- +static void
- +gb_command_bar_results_popup_desactivate_cb (GbCommandBar *self,
- + GtkMenu *menu)
- +{
- + self->is_in_results_popup = FALSE;
- + /* FIX: menu destroyed ? */
- +}
- +
- +static void
- +gb_command_bar_results_do_menu (GbCommandBar *self,
- + GtkWidget *widget,
- + GdkEventButton *event)
- +{
- + gint button;
- + gint event_time;
- + GtkWidget *menuitem;
- + GtkWidget *menu;
- +
- + self->is_in_results_popup = TRUE;
- + if (gb_command_bar_results_length (self) == 0)
- + return;
- +
- + menu = gtk_menu_new ();
- +
- + menuitem = gtk_menu_item_new_with_label (_("Clear"));
- + g_signal_connect_swapped (menuitem, "activate",
- + G_CALLBACK (gb_command_bar_results_clear),
- + self);
- + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
- +
- + menuitem = gtk_menu_item_new_with_label (_("Clear all"));
- + g_signal_connect_swapped (menuitem, "activate",
- + G_CALLBACK (gb_command_bar_results_clear_all),
- + self);
- + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
- +
- + g_signal_connect_swapped (menu, "deactivate",
- + G_CALLBACK (gb_command_bar_results_popup_desactivate_cb),
- + self);
- +
- + self->result_y_pos = -1;
- + if (event)
- + {
- + button = event->button;
- + event_time = event->time;
- + self->result_y_pos = ((GdkEventButton*)event)->y;
- + }
- + else
- + {
- + button = 0;
- + event_time = gtk_get_current_event_time ();
- + }
- +
- + gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (widget), NULL);
- + gtk_widget_show_all (menu);
- + gtk_menu_popup_for_device (GTK_MENU (menu),
- + gdk_event_get_device ((GdkEvent *)event),
- + NULL, NULL,
- + NULL, NULL, NULL,
- + button,
- + event_time);
- +}
- +
- +static gboolean
- +gb_command_bar_results_button_pressed_cb (GbCommandBar *self,
- + GdkEventButton *event,
- + GtkListBox *list_box)
- +{
- + if (gdk_event_triggers_context_menu ((GdkEvent *)event) && event->type == GDK_BUTTON_PRESS)
- + {
- + gb_command_bar_results_do_menu (self, GTK_WIDGET (list_box), event);
- + return TRUE;
- + }
- +
- + return FALSE;
- +}
- +
- +static gboolean
- +gb_command_bar_results_on_popup_menu_cb (GbCommandBar *self,
- + GtkWidget *widget)
- +{
- + gb_command_bar_results_do_menu (self, widget, NULL);
- + return TRUE;
- }
- static void
- @@ -259,19 +464,26 @@ gb_command_bar_on_entry_activate (GbCommandBar *self,
- text = gtk_entry_get_text (entry);
- gtk_widget_hide (GTK_WIDGET (self->completion_scroller));
- -
- + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->results_button), FALSE);
- +
- if (!gb_str_empty0 (text))
- {
- GbCommandResult *result = NULL;
- GbCommand *command = NULL;
- - g_queue_push_head (self->history, g_strdup (text));
- - g_free (g_queue_pop_nth (self->history, HISTORY_LENGTH));
- -
- - command = gb_command_manager_lookup (self->command_manager, text);
- + command = gb_command_manager_lookup (self->command_manager, text, &result);
- + if (result)
- + {
- + gb_command_bar_push_result (self, result);
- + }
- if (command)
- {
- + //printf ("command text=%s\n", gb_command_vim_get_command_text (GB_COMMAND_VIM (command)));
- +
- + g_queue_push_head (self->history, g_strdup (text));
- + g_free (g_queue_pop_nth (self->history, HISTORY_LENGTH));
- +
- result = gb_command_execute (command);
- /* if we got a result item, keep the bar open for observing it.
- @@ -293,7 +505,6 @@ gb_command_bar_on_entry_activate (GbCommandBar *self,
- "command-text", errmsg,
- NULL);
- gb_command_bar_push_result (self, result);
- - g_object_unref (result);
- g_free (errmsg);
- }
- @@ -307,20 +518,6 @@ gb_command_bar_on_entry_activate (GbCommandBar *self,
- gtk_entry_set_text (self->entry, "");
- }
- -static gboolean
- -gb_command_bar_on_entry_focus_out_event (GbCommandBar *self,
- - GdkEventKey *event,
- - GtkEntry *entry)
- -{
- - g_assert (GB_IS_COMMAND_BAR (self));
- - g_assert (event != NULL);
- - g_assert (GTK_IS_ENTRY (entry));
- -
- - gb_command_bar_hide (self);
- -
- - return GDK_EVENT_PROPAGATE;
- -}
- -
- static void
- gb_command_bar_grab_focus (GtkWidget *widget)
- {
- @@ -332,15 +529,19 @@ gb_command_bar_grab_focus (GtkWidget *widget)
- }
- static gchar *
- -find_longest_common_prefix (gchar **strv)
- +find_longest_common_prefix (GPtrArray *completions)
- {
- - gchar *lcp = NULL;
- - gchar *lcp_end = NULL;
- + const gchar *lcp = NULL;
- + const gchar *lcp_end = NULL;
- int i;
- + const gchar *str;
- + GbCommandCompleteItem *entry;
- + guint len = completions->len;
- - for (i = 0; strv[i] != NULL; i++)
- + for (i = 0; i < len; i++)
- {
- - gchar *str = strv[i];
- + entry = g_ptr_array_index (completions, i);
- + str = gb_command_complete_item_get_name (entry);
- if (lcp == NULL)
- {
- lcp = str;
- @@ -348,7 +549,7 @@ find_longest_common_prefix (gchar **strv)
- }
- else
- {
- - gchar *tmp = lcp;
- + const gchar *tmp = lcp;
- while (tmp < lcp_end && *str != 0 && *tmp == *str)
- {
- @@ -369,12 +570,52 @@ find_longest_common_prefix (gchar **strv)
- #define MIN_COMPLETION_COLUMS 3
- #define N_UNSCROLLED_COMPLETION_ROWS 4
- +static gchar *
- +gb_command_bar_format_complete_string (GbCommandCompleteItem *item,
- + gchar *prefix)
- +{
- + gchar *str;
- + g_autofree gchar *decorated_remainder = NULL;
- + g_autofree gchar *decorated_shortname = NULL;
- + GbCommandCompleteItemKind kind;
- + const gchar *name;
- + const gchar *shortname;
- + const gchar *remainder;
- + gint prefix_len;
- + gint shortname_len;
- + gint len_s, len_n;
- +
- + kind = gb_command_complete_item_get_kind (item);
- + name = gb_command_complete_item_get_name (item);
- + shortname = gb_command_complete_item_get_shortname (item);
- + prefix_len = strlen (prefix);
- +
- + if (kind == GB_COMMAND_COMPLETE_ITEM_KIND_COMMAND && !ide_str_empty0 (shortname))
- + {
- + shortname_len = strlen (shortname);
- + len_s = MIN (shortname_len, prefix_len);
- + len_n = MAX (0, prefix_len - shortname_len);
- + remainder = name + shortname_len;
- + decorated_shortname = g_strdup_printf ("<b>%.*s</b>%s", len_s, shortname, shortname + len_s);
- + decorated_remainder = g_strdup_printf ("<b>%.*s</b>%s", len_n, remainder, remainder + len_n);
- + str = g_strconcat ("[", decorated_shortname, "]", decorated_remainder, NULL);
- + }
- + else
- + {
- + str = g_strdup_printf ("<b>%s</b>%s", prefix, name + prefix_len);
- + }
- +
- + return str;
- +}
- +
- static void
- gb_command_bar_complete (GbCommandBar *self)
- {
- + GPtrArray *completions;
- + guint len;
- GtkEditable *editable = GTK_EDITABLE (self->entry);
- GtkWidget *viewport = gtk_bin_get_child (GTK_BIN (self->completion_scroller));
- - gchar **completions;
- +
- int pos, i;
- gchar *current_prefix, *expanded_prefix;
- @@ -402,62 +643,72 @@ gb_command_bar_complete (GbCommandBar *self)
- g_clear_pointer (&self->last_completion, g_free);
- completions = gb_command_manager_complete (self->command_manager, current_prefix);
- -
- - expanded_prefix = find_longest_common_prefix (completions);
- -
- - if (strlen (expanded_prefix) > strlen (current_prefix))
- - {
- - gtk_widget_hide (GTK_WIDGET (self->completion_scroller));
- - gtk_editable_insert_text (editable, expanded_prefix + strlen (current_prefix), -1, &pos);
- - gtk_editable_set_position (editable, pos);
- - }
- - else if (g_strv_length (completions) > 1)
- + if (completions != NULL)
- {
- - gint wrapped_height = 0;
- - self->last_completion = g_strdup (current_prefix);
- -
- - gtk_widget_show (GTK_WIDGET (self->completion_scroller));
- - gtk_container_foreach (GTK_CONTAINER (self->flow_box),
- - (GtkCallback)gtk_widget_destroy, NULL);
- + expanded_prefix = find_longest_common_prefix (completions);
- - gtk_flow_box_set_min_children_per_line (self->flow_box, MIN_COMPLETION_COLUMS);
- -
- - for (i = 0; completions[i] != NULL; i++)
- + if (strlen (expanded_prefix) > strlen (current_prefix))
- {
- - GtkWidget *label;
- - char *s;
- -
- - label = gtk_label_new ("");
- - s = g_strdup_printf ("<b>%s</b>%s", current_prefix, completions[i] + strlen (current_prefix));
- - gtk_label_set_markup (GTK_LABEL (label), s);
- - gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
- - g_free (s);
- -
- - gtk_container_add (GTK_CONTAINER (self->flow_box), label);
- - gtk_widget_show (label);
- -
- - if (i == MIN_COMPLETION_COLUMS * N_UNSCROLLED_COMPLETION_ROWS - 1)
- - gtk_widget_get_preferred_height (GTK_WIDGET (self->flow_box), &wrapped_height, NULL);
- - }
- -
- - if (i < MIN_COMPLETION_COLUMS * N_UNSCROLLED_COMPLETION_ROWS)
- - {
- - gtk_widget_set_size_request (GTK_WIDGET (self->completion_scroller), -1, -1);
- - gtk_scrolled_window_set_policy (self->completion_scroller,
- - GTK_POLICY_NEVER, GTK_POLICY_NEVER);
- + gtk_widget_hide (GTK_WIDGET (self->completion_scroller));
- + gtk_editable_insert_text (editable, expanded_prefix + strlen (current_prefix), -1, &pos);
- + gtk_editable_set_position (editable, pos);
- }
- else
- {
- - gtk_widget_set_size_request (GTK_WIDGET (self->completion_scroller), -1, wrapped_height);
- - gtk_scrolled_window_set_policy (self->completion_scroller,
- - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
- + len = completions->len;
- + gint wrapped_height = 0;
- + self->last_completion = g_strdup (current_prefix);
- +
- + gtk_widget_show (GTK_WIDGET (self->completion_scroller));
- + gb_command_bar_results_hide (self);
- +
- + gtk_container_foreach (GTK_CONTAINER (self->flow_box),
- + (GtkCallback)gtk_widget_destroy, NULL);
- +
- + gtk_flow_box_set_min_children_per_line (self->flow_box, MIN_COMPLETION_COLUMS);
- +
- + for (i = 0; i < len; i++)
- + {
- + GbCommandCompleteItem *entry = g_ptr_array_index (completions, i);
- + GtkWidget *label;
- + char *s;
- +
- + label = gtk_label_new ("");
- + s = gb_command_bar_format_complete_string (entry, current_prefix);
- + gtk_label_set_markup (GTK_LABEL (label), s);
- + gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
- + g_free (s);
- +
- + gtk_container_add (GTK_CONTAINER (self->flow_box), label);
- + gtk_widget_show (label);
- +
- + if (i == MIN_COMPLETION_COLUMS * N_UNSCROLLED_COMPLETION_ROWS - 1)
- + gtk_widget_get_preferred_height (GTK_WIDGET (self->flow_box), &wrapped_height, NULL);
- + }
- +
- + g_ptr_array_free (completions, TRUE);
- +
- + if (i < MIN_COMPLETION_COLUMS * N_UNSCROLLED_COMPLETION_ROWS)
- + {
- + gtk_widget_set_size_request (GTK_WIDGET (self->completion_scroller), -1, -1);
- + gtk_scrolled_window_set_policy (self->completion_scroller,
- + GTK_POLICY_NEVER, GTK_POLICY_NEVER);
- + }
- + else
- + {
- + gtk_widget_set_size_request (GTK_WIDGET (self->completion_scroller), -1, wrapped_height);
- + gtk_scrolled_window_set_policy (self->completion_scroller,
- + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
- + }
- }
- +
- + g_free (expanded_prefix);
- }
- else
- - gtk_widget_hide (GTK_WIDGET (self->completion_scroller));
- -
- - g_free (expanded_prefix);
- - g_strfreev (completions);
- + {
- + gtk_widget_hide (GTK_WIDGET (self->completion_scroller));
- + gb_command_bar_results_hide (self);
- + }
- }
- g_free (current_prefix);
- @@ -565,6 +816,63 @@ gb_command_bar_on_entry_key_press_event (GbCommandBar *bar,
- }
- static void
- +gb_command_bar_set_focus (GbCommandBar *self,
- + GtkWidget *focus,
- + GbWorkbench *workbench)
- +{
- + g_return_if_fail (GB_IS_COMMAND_BAR (self));
- + g_return_if_fail (!focus || GTK_IS_WIDGET (focus));
- + g_return_if_fail (GB_IS_WORKBENCH (workbench));
- +
- + if (!focus ||
- + (!gtk_widget_is_ancestor (focus, GTK_WIDGET (self)) &&
- + !gtk_widget_is_ancestor (focus, GTK_WIDGET (self->popover))))
- + {
- + gb_command_bar_hide (self);
- + }
- +}
- +
- +static void
- +gb_command_bar_map (GtkWidget *widget)
- +{
- + GbCommandBar *self = (GbCommandBar *)widget;
- + GtkWidget *toplevel;
- +
- + g_return_if_fail (GB_IS_COMMAND_BAR (self));
- +
- + GTK_WIDGET_CLASS (gb_command_bar_parent_class)->map (widget);
- +
- + toplevel = gtk_widget_get_toplevel (widget);
- +
- + if (GB_IS_WORKBENCH (toplevel))
- + {
- + gb_set_weak_pointer (toplevel, &self->workbench);
- + self->set_focus_handler =
- + g_signal_connect_object (toplevel,
- + "set-focus",
- + G_CALLBACK (gb_command_bar_set_focus),
- + self,
- + G_CONNECT_SWAPPED | G_CONNECT_AFTER);
- + }
- +}
- +
- +static void
- +gb_command_bar_unmap (GtkWidget *widget)
- +{
- + GbCommandBar *self = (GbCommandBar *)widget;
- +
- + g_return_if_fail (GB_IS_COMMAND_BAR (self));
- +
- + if (self->workbench)
- + {
- + ide_clear_signal_handler (self->workbench, &self->set_focus_handler);
- + ide_clear_weak_pointer (&self->workbench);
- + }
- +
- + GTK_WIDGET_CLASS (gb_command_bar_parent_class)->unmap (widget);
- +}
- +
- +static void
- update_header_func (GtkListBoxRow *row,
- GtkListBoxRow *before,
- gpointer user_data)
- @@ -604,12 +912,6 @@ gb_command_bar_constructed (GObject *object)
- G_CONNECT_SWAPPED);
- g_signal_connect_object (self->entry,
- - "focus-out-event",
- - G_CALLBACK (gb_command_bar_on_entry_focus_out_event),
- - self,
- - G_CONNECT_SWAPPED);
- -
- - g_signal_connect_object (self->entry,
- "key-press-event",
- G_CALLBACK (gb_command_bar_on_entry_key_press_event),
- self,
- @@ -621,8 +923,28 @@ gb_command_bar_constructed (GObject *object)
- self,
- G_CONNECT_SWAPPED);
- + g_signal_connect_object (self->list_box,
- + "button-press-event",
- + G_CALLBACK (gb_command_bar_results_button_pressed_cb),
- + self,
- + G_CONNECT_SWAPPED);
- +
- + g_signal_connect_object (self->list_box,
- + "popup-menu",
- + G_CALLBACK (gb_command_bar_results_on_popup_menu_cb),
- + self,
- + G_CONNECT_SWAPPED);
- +
- + g_signal_connect_object (self->results_button,
- + "toggled",
- + G_CALLBACK (gb_command_bar_results_toggled_cb),
- + self,
- + G_CONNECT_SWAPPED);
- +
- gtk_list_box_set_header_func (self->list_box, update_header_func,
- NULL, NULL);
- +
- + gtk_popover_set_relative_to (self->popover, GTK_WIDGET (self->command_box));
- }
- static void
- @@ -670,6 +992,8 @@ gb_command_bar_class_init (GbCommandBarClass *klass)
- object_class->finalize = gb_command_bar_finalize;
- object_class->set_property = gb_command_bar_set_property;
- + widget_class->map = gb_command_bar_map;
- + widget_class->unmap = gb_command_bar_unmap;
- widget_class->grab_focus = gb_command_bar_grab_focus;
- gParamSpecs [PROP_WORKBENCH] =
- @@ -729,6 +1053,9 @@ gb_command_bar_class_init (GbCommandBarClass *klass)
- gtk_widget_class_bind_template_child (widget_class, GbCommandBar, entry);
- gtk_widget_class_bind_template_child (widget_class, GbCommandBar, list_box);
- + gtk_widget_class_bind_template_child (widget_class, GbCommandBar, results_button);
- + gtk_widget_class_bind_template_child (widget_class, GbCommandBar, command_box);
- + gtk_widget_class_bind_template_child (widget_class, GbCommandBar, popover);
- gtk_widget_class_bind_template_child (widget_class, GbCommandBar, scroller);
- gtk_widget_class_bind_template_child (widget_class, GbCommandBar, result_size_group);
- gtk_widget_class_bind_template_child (widget_class, GbCommandBar, completion_scroller);
- diff --git a/plugins/command-bar/gb-command-bar.gresource.xml b/plugins/command-bar/gb-command-bar.gresource.xml
- index 6197d47..61b8564 100644
- --- a/plugins/command-bar/gb-command-bar.gresource.xml
- +++ b/plugins/command-bar/gb-command-bar.gresource.xml
- @@ -2,5 +2,6 @@
- <gresources>
- <gresource prefix="/org/gnome/builder/plugins/command-bar">
- <file>gb-command-bar.ui</file>
- + <file>gb-command-bar-item.ui</file>
- </gresource>
- </gresources>
- diff --git a/plugins/command-bar/gb-command-bar.ui b/plugins/command-bar/gb-command-bar.ui
- index f5c997e..33624b5 100644
- --- a/plugins/command-bar/gb-command-bar.ui
- +++ b/plugins/command-bar/gb-command-bar.ui
- @@ -3,28 +3,10 @@
- <!-- interface-requires gtk+ 3.8 -->
- <template class="GbCommandBar" parent="GtkBin">
- <child>
- - <object class="GtkBox" id="vbox1">
- + <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <child>
- - <object class="GtkScrolledWindow" id="scroller">
- - <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
- - <property name="visible">False</property>
- - <property name="expand">True</property>
- - <property name="height_request">300</property>
- - <child>
- - <object class="GtkListBox" id="list_box">
- - <property name="visible">True</property>
- - <property name="expand">True</property>
- - <property name="selection_mode">GTK_SELECTION_NONE</property>
- - <style>
- - <class name="view"/>
- - </style>
- - </object>
- - </child>
- - </object>
- - </child>
- - <child>
- <object class="GtkScrolledWindow" id="completion_scroller">
- <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
- <property name="visible">False</property>
- @@ -43,12 +25,13 @@
- </object>
- </child>
- <child>
- - <object class="GtkBox">
- + <object class="GtkBox" id="command_box">
- <property name="visible">True</property>
- <property name="orientation">horizontal</property>
- <property name="spacing">3</property>
- <style>
- <class name="gb-command-bar-box"/>
- + <class name="linked"/>
- </style>
- <child>
- <object class="GtkLabel">
- @@ -68,6 +51,25 @@
- </style>
- </object>
- </child>
- + <child>
- + <object class="GtkMenuButton" id="results_button">
- + <property name="visible">true</property>
- + <property name="can-focus">True</property>
- + <property name="popover">popover</property>
- + <style>
- + <class name="button"/>
- + <class name="flat"/>
- + </style>
- + <child>
- + <object class="GtkImage">
- + <!-- we use margin-top here because .image-button doesn't work with 10pt font -->
- + <property name="margin-top">3</property>
- + <property name="visible">True</property>
- + <property name="icon_name">go-up-symbolic</property>
- + </object>
- + </child>
- + </object>
- + </child>
- </object>
- </child>
- </object>
- @@ -76,4 +78,29 @@
- <object class="GtkSizeGroup" id="result_size_group">
- <property name="mode">GTK_SIZE_GROUP_HORIZONTAL</property>
- </object>
- + <object class="GtkPopover" id="popover">
- + <property name="visible">true</property>
- + <property name="hexpand">True</property>
- + <property name="modal">false</property>
- + <style>
- + <class name="gb-command-bar-results"/>
- + </style>
- + <child>
- + <object class="GbScrolledWindow" id="scroller">
- + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
- + <property name="max-content-height">300</property>
- + <property name="min-content-height">150</property>
- + <property name="min-content-width">775</property>
- + <property name="visible">True</property>
- + <property name="expand">True</property>
- + <child>
- + <object class="GtkListBox" id="list_box">
- + <property name="visible">True</property>
- + <property name="expand">True</property>
- + <property name="selection_mode">GTK_SELECTION_SINGLE</property>
- + </object>
- + </child>
- + </object>
- + </child>
- + </object>
- </interface>
- diff --git a/plugins/command-bar/gb-command-complete-item.c b/plugins/command-bar/gb-command-complete-item.c
- new file mode 100644
- index 0000000..7a127ae
- --- /dev/null
- +++ b/plugins/command-bar/gb-command-complete-item.c
- @@ -0,0 +1,113 @@
- +/* gb-command-complete-item.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <string.h>
- +
- +#include <glib/gi18n.h>
- +#include <glib/gprintf.h>
- +#include <ide.h>
- +
- +#include "gb-command-complete-item.h"
- +
- +G_DEFINE_BOXED_TYPE (GbCommandCompleteItem, gb_command_complete_item, gb_command_complete_item_ref, gb_command_complete_item_unref)
- +
- +struct _GbCommandCompleteItem
- +{
- + volatile gint ref_count;
- +
- + GbCommandCompleteItemKind kind;
- + gchar *name;
- + gchar *shortname;
- +};
- +
- +
- +const gchar *
- +gb_command_complete_item_get_name (GbCommandCompleteItem *self)
- +{
- + g_return_val_if_fail (self, NULL);
- +
- + return self->name;
- +}
- +
- +const gchar *
- +gb_command_complete_item_get_shortname (GbCommandCompleteItem *self)
- +{
- + g_return_val_if_fail (self, NULL);
- +
- + return self->shortname;
- +}
- +
- +GbCommandCompleteItemKind
- +gb_command_complete_item_get_kind (GbCommandCompleteItem *self)
- +{
- + g_return_val_if_fail (self, GB_COMMAND_COMPLETE_ITEM_KIND_NONE);
- +
- + return self->kind;
- +}
- +
- +static void
- +gb_command_complete_item_finalize (GbCommandCompleteItem *self)
- +{
- + g_clear_pointer (&self->name, g_free);
- + g_clear_pointer (&self->shortname, g_free);
- +
- + g_free (self);
- +}
- +
- +GbCommandCompleteItem *
- +gb_command_complete_item_ref (GbCommandCompleteItem *self)
- +{
- + g_return_val_if_fail (self, NULL);
- + g_return_val_if_fail (self->ref_count > 0, NULL);
- +
- + g_atomic_int_inc (&self->ref_count);
- +
- + return self;
- +}
- +
- +void
- +gb_command_complete_item_unref (GbCommandCompleteItem *self)
- +{
- + g_return_if_fail (self);
- + g_return_if_fail (self->ref_count > 0);
- +
- + if (g_atomic_int_dec_and_test (&self->ref_count))
- + gb_command_complete_item_finalize (self);
- +}
- +
- +GbCommandCompleteItem *
- +gb_command_complete_item_new (GbCommandCompleteItemKind kind,
- + const gchar *name,
- + const gchar *shortname)
- +{
- +
- + GbCommandCompleteItem *self;
- +
- + g_return_val_if_fail (!ide_str_empty0 (name), NULL);
- + g_return_val_if_fail (kind < GB_COMMAND_COMPLETE_ITEM_KIND_LAST, NULL);
- +
- + self = g_new0 (GbCommandCompleteItem, 1);
- + self->ref_count = 1;
- +
- + self->kind = kind;
- + self->name = g_strdup (name);
- + if (!ide_str_empty0 (shortname))
- + self->shortname = g_strdup (shortname);
- +
- + return self;
- +}
- diff --git a/plugins/command-bar/gb-command-complete-item.h b/plugins/command-bar/gb-command-complete-item.h
- new file mode 100644
- index 0000000..8a7eaeb
- --- /dev/null
- +++ b/plugins/command-bar/gb-command-complete-item.h
- @@ -0,0 +1,53 @@
- +/* gb-command-complete-item.h
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#ifndef GB_COMMAND_COMPLETE_ITEM_H
- +#define GB_COMMAND_COMPLETE_ITEM_H
- +
- +#include <glib-object.h>
- +
- +G_BEGIN_DECLS
- +
- +#define GB_TYPE_COMMAND_COMPLETE_ITEM (gb_command_complete_item_get_type())
- +
- +typedef struct _GbCommandCompleteItem GbCommandCompleteItem;
- +
- +typedef enum
- +{
- + GB_COMMAND_COMPLETE_ITEM_KIND_NONE,
- + GB_COMMAND_COMPLETE_ITEM_KIND_SET,
- + GB_COMMAND_COMPLETE_ITEM_KIND_COLORSCHEME,
- + GB_COMMAND_COMPLETE_ITEM_KIND_COMMAND,
- + GB_COMMAND_COMPLETE_ITEM_KIND_PATH,
- + GB_COMMAND_COMPLETE_ITEM_KIND_ACTION,
- +
- + GB_COMMAND_COMPLETE_ITEM_KIND_LAST
- +} GbCommandCompleteItemKind;
- +
- +GbCommandCompleteItem *gb_command_complete_item_new (GbCommandCompleteItemKind kind,
- + const gchar *name,
- + const gchar *shortname);
- +GbCommandCompleteItem *gb_command_complete_item_ref (GbCommandCompleteItem *self);
- +void gb_command_complete_item_unref (GbCommandCompleteItem *self);
- +GbCommandCompleteItemKind gb_command_complete_item_get_kind (GbCommandCompleteItem *self);
- +const gchar *gb_command_complete_item_get_name (GbCommandCompleteItem *self);
- +const gchar *gb_command_complete_item_get_shortname (GbCommandCompleteItem *self);
- +
- +G_END_DECLS
- +
- +#endif /* GB_COMMAND_COMPLETE_ITEM_H */
- diff --git a/plugins/command-bar/gb-command-gaction-provider.c b/plugins/command-bar/gb-command-gaction-provider.c
- index b9c26cb..7d139d6 100644
- --- a/plugins/command-bar/gb-command-gaction-provider.c
- +++ b/plugins/command-bar/gb-command-gaction-provider.c
- @@ -26,6 +26,7 @@
- #include "gb-command-gaction-provider.h"
- #include "gb-command-gaction.h"
- +#include "gb-command-complete-item.h"
- #include "gb-view.h"
- struct _GbCommandGactionProvider
- @@ -334,8 +335,10 @@ search_action_in_maps (const gchar *command_name,
- }
- static GbCommand *
- -gb_command_gaction_provider_lookup (GbCommandProvider *provider,
- - const gchar *command_text)
- +gb_command_gaction_provider_lookup (GbCommandProvider *provider,
- + const gchar *command_text,
- + GbCommandResult **result)
- +
- {
- GbCommandGactionProvider *self = (GbCommandGactionProvider *)provider;
- GbCommand *command = NULL;
- @@ -348,7 +351,7 @@ gb_command_gaction_provider_lookup (GbCommandProvider *provider,
- const gchar *new_command_name = NULL;
- const gchar *action_name = NULL;
- const gchar *prefix = NULL;
- - gboolean result = FALSE;
- + gboolean ret = FALSE;
- IDE_ENTRY;
- @@ -370,13 +373,13 @@ gb_command_gaction_provider_lookup (GbCommandProvider *provider,
- if (g_str_equal (prefix, gb_group->prefix) && g_action_group_has_action (group, action_name))
- {
- - result = TRUE;
- + ret = TRUE;
- break;
- }
- }
- }
- - if (!result)
- + if (!ret)
- {
- for (iter = gb_groups; iter; iter = iter->next)
- {
- @@ -389,20 +392,22 @@ gb_command_gaction_provider_lookup (GbCommandProvider *provider,
- prefix = gb_group->prefix;
- if (search_command_in_maps (command_name, prefix, &new_command_name))
- {
- - result = FALSE;
- + ret = FALSE;
- break;
- }
- action_name = command_name;
- - result = TRUE;
- + ret = TRUE;
- break;
- }
- }
- }
- - if (result)
- + if (ret)
- {
- command = g_object_new (GB_TYPE_COMMAND_GACTION,
- + "name", action_name,
- + "shortname", NULL,
- "action-group", group,
- "action-name", action_name,
- "parameters", params,
- @@ -416,6 +421,16 @@ gb_command_gaction_provider_lookup (GbCommandProvider *provider,
- IDE_RETURN (command);
- }
- +static inline GbCommandCompleteItem *
- +create_completion_item (const gchar *name)
- +{
- + GbCommandCompleteItem *item;
- +
- + item = gb_command_complete_item_new (GB_COMMAND_COMPLETE_ITEM_KIND_ACTION, name, NULL);
- +
- + return item;
- +}
- +
- static void
- gb_command_gaction_provider_complete (GbCommandProvider *provider,
- GPtrArray *completions,
- @@ -450,13 +465,13 @@ gb_command_gaction_provider_complete (GbCommandProvider *provider,
- if (search_command_in_maps (names [i], prefix, &command_name))
- {
- if (command_name != NULL && g_str_has_prefix (command_name, initial_command_text))
- - g_ptr_array_add (completions, g_strdup (command_name));
- + g_ptr_array_add (completions, create_completion_item (command_name));
- continue;
- }
- if (g_str_has_prefix (names [i], initial_command_text))
- - g_ptr_array_add (completions, g_strdup (names [i]));
- + g_ptr_array_add (completions, create_completion_item (names [i]));
- }
- g_free (names);
- diff --git a/plugins/command-bar/gb-command-gaction-provider.h b/plugins/command-bar/gb-command-gaction-provider.h
- index aeb4e50..0d8db25 100644
- --- a/plugins/command-bar/gb-command-gaction-provider.h
- +++ b/plugins/command-bar/gb-command-gaction-provider.h
- @@ -20,6 +20,7 @@
- #define GB_COMMAND_GACTION_PROVIDER_H
- #include "gb-command-provider.h"
- +#include "gb-command-result.h"
- G_BEGIN_DECLS
- diff --git a/plugins/command-bar/gb-command-manager.c b/plugins/command-bar/gb-command-manager.c
- index 896ae7a..4f81822 100644
- --- a/plugins/command-bar/gb-command-manager.c
- +++ b/plugins/command-bar/gb-command-manager.c
- @@ -20,6 +20,7 @@
- #include <string.h>
- +#include "gb-command-complete-item.h"
- #include "gb-command-manager.h"
- #include "gb-workbench.h"
- @@ -91,21 +92,23 @@ gb_command_manager_add_provider (GbCommandManager *manager,
- }
- GbCommand *
- -gb_command_manager_lookup (GbCommandManager *manager,
- - const gchar *command_text)
- +gb_command_manager_lookup (GbCommandManager *manager,
- + const gchar *command_text,
- + GbCommandResult **result)
- {
- GbCommand *ret = NULL;
- guint i;
- g_return_val_if_fail (GB_IS_COMMAND_MANAGER (manager), NULL);
- g_return_val_if_fail (command_text, NULL);
- + g_return_val_if_fail (result, NULL);
- for (i = 0; i < manager->providers->len; i++)
- {
- GbCommandProvider *provider;
- provider = g_ptr_array_index (manager->providers, i);
- - ret = gb_command_provider_lookup (provider, command_text);
- + ret = gb_command_provider_lookup (provider, command_text, result);
- if (ret)
- return ret;
- @@ -114,14 +117,45 @@ gb_command_manager_lookup (GbCommandManager *manager,
- return NULL;
- }
- +gboolean
- +gb_command_manager_validate (GbCommandManager *manager,
- + const gchar *initial_command_text,
- + GbCommandResult **result)
- +{
- + gboolean ret = FALSE;
- + guint i;
- +
- + g_return_val_if_fail (GB_IS_COMMAND_MANAGER (manager), FALSE);
- + g_return_val_if_fail (initial_command_text, FALSE);
- + g_return_val_if_fail (result, FALSE);
- +
- + for (i = 0; i < manager->providers->len; i++)
- + {
- + GbCommandProvider *provider;
- +
- + provider = g_ptr_array_index (manager->providers, i);
- + ret = gb_command_provider_validate (provider, initial_command_text, result);
- + if (ret)
- + break;
- + }
- +
- + return ret;
- +}
- +
- static gint
- -sort_strings (const gchar * const * a,
- - const gchar * const * b)
- +sort_command_names (GbCommandCompleteItem **i1,
- + GbCommandCompleteItem **i2)
- {
- - return strcmp (*a, *b);
- + const gchar *name_i1;
- + const gchar *name_i2;
- +
- + name_i1 = gb_command_complete_item_get_name (*i1);
- + name_i2 = gb_command_complete_item_get_name (*i2);
- +
- + return strcmp (name_i1, name_i2);
- }
- -gchar **
- +GPtrArray *
- gb_command_manager_complete (GbCommandManager *manager,
- const gchar *initial_command_text)
- {
- @@ -131,7 +165,7 @@ gb_command_manager_complete (GbCommandManager *manager,
- g_return_val_if_fail (GB_IS_COMMAND_MANAGER (manager), NULL);
- g_return_val_if_fail (initial_command_text, NULL);
- - completions = g_ptr_array_new ();
- + completions = g_ptr_array_new_full (32, (GDestroyNotify)gb_command_complete_item_unref);
- for (i = 0; i < manager->providers->len; i++)
- {
- @@ -141,11 +175,14 @@ gb_command_manager_complete (GbCommandManager *manager,
- gb_command_provider_complete (provider, completions, initial_command_text);
- }
- - g_ptr_array_sort (completions, (GCompareFunc)sort_strings);
- -
- - g_ptr_array_add (completions, NULL);
- + if (completions->len == 0)
- + {
- + g_ptr_array_free (completions, TRUE);
- + return NULL;
- + }
- - return (gchar **)g_ptr_array_free (completions, FALSE);
- + g_ptr_array_sort (completions, (GCompareFunc)sort_command_names);
- + return completions;
- }
- diff --git a/plugins/command-bar/gb-command-manager.h b/plugins/command-bar/gb-command-manager.h
- index 2edb9d2..b1b551e 100644
- --- a/plugins/command-bar/gb-command-manager.h
- +++ b/plugins/command-bar/gb-command-manager.h
- @@ -23,6 +23,7 @@
- #include "gb-command.h"
- #include "gb-command-provider.h"
- +#include "gb-command-result.h"
- G_BEGIN_DECLS
- @@ -31,12 +32,16 @@ G_BEGIN_DECLS
- G_DECLARE_FINAL_TYPE (GbCommandManager, gb_command_manager, GB, COMMAND_MANAGER, GObject)
- GbCommandManager *gb_command_manager_new (void);
- -GbCommand *gb_command_manager_lookup (GbCommandManager *manager,
- - const gchar *command_text);
- -gchar **gb_command_manager_complete (GbCommandManager *manager,
- - const gchar *initial_command_text);
- -void gb_command_manager_add_provider (GbCommandManager *manager,
- - GbCommandProvider *provider);
- +GbCommand *gb_command_manager_lookup (GbCommandManager *manager,
- + const gchar *command_text,
- + GbCommandResult **result);
- +gboolean gb_command_manager_validate (GbCommandManager *manager,
- + const gchar *initial_command_text,
- + GbCommandResult **result);
- +GPtrArray *gb_command_manager_complete (GbCommandManager *manager,
- + const gchar *initial_command_text);
- +void gb_command_manager_add_provider (GbCommandManager *manager,
- + GbCommandProvider *provider);
- G_END_DECLS
- diff --git a/plugins/command-bar/gb-command-provider.c b/plugins/command-bar/gb-command-provider.c
- index 15b4d92..1bb3427 100644
- --- a/plugins/command-bar/gb-command-provider.c
- +++ b/plugins/command-bar/gb-command-provider.c
- @@ -41,6 +41,7 @@ enum {
- enum {
- LOOKUP,
- COMPLETE,
- + VALIDATE,
- LAST_SIGNAL
- };
- @@ -218,20 +219,47 @@ gb_command_provider_set_priority (GbCommandProvider *provider,
- * gb_command_provider_lookup:
- * @provider: (in): The #GbCommandProvider
- * @command_text: (in): Command text to be parsed
- - *
- + * @result: (out): #GbResult giving the result of the lookup.
- *
- * Returns: (transfer full): A #GbCommand if successful; otherwise %NULL.
- */
- GbCommand *
- -gb_command_provider_lookup (GbCommandProvider *provider,
- - const gchar *command_text)
- +gb_command_provider_lookup (GbCommandProvider *provider,
- + const gchar *command_text,
- + GbCommandResult **result)
- {
- GbCommand *ret = NULL;
- g_return_val_if_fail (GB_IS_COMMAND_PROVIDER (provider), NULL);
- g_return_val_if_fail (command_text, NULL);
- + g_return_val_if_fail (result, NULL);
- - g_signal_emit (provider, gSignals [LOOKUP], 0, command_text, &ret);
- + g_signal_emit (provider, gSignals [LOOKUP], 0, command_text, result, &ret);
- +
- + return ret;
- +}
- +
- +/**
- + * gb_command_provider_validate:
- + * @provider: (in): The #GbCommandProvider
- + * @initial_command_text: (in): Command text to be validated. Can be part of or
- + * the whole command text.
- + * @result: (out): #GbResult giving the result of the validation.
- + *
- + * Returns: TRUE if successful, FALSE overwise.
- + */
- +gboolean
- +gb_command_provider_validate (GbCommandProvider *provider,
- + const gchar *initial_command_text,
- + GbCommandResult **result)
- +{
- + gboolean ret;
- +
- + g_return_val_if_fail (GB_IS_COMMAND_PROVIDER (provider), FALSE);
- + g_return_val_if_fail (initial_command_text, FALSE);
- + g_return_val_if_fail (result, FALSE);
- +
- + g_signal_emit (provider, gSignals [VALIDATE], 0, initial_command_text, result, &ret);
- return ret;
- }
- @@ -363,14 +391,12 @@ gb_command_provider_class_init (GbCommandProviderClass *klass)
- /**
- * GbCommandProvider::lookup:
- * @command_text: (in): the command line text to be processed.
- - * @parameter: (out): a location to store any parsed parameters.
- + * @result: (out): adress of a #GbResult pointer, giving the result of the lookup.
- *
- * This signal is emitted when a request to parse the command text is
- * received. Only the first handler will respond to the action. The
- - * callee should return a GAction if successful, otherwise %NULL.
- + * callee should return a #GbCommand if successful, otherwise %NULL.
- *
- - * If successful, the callee can set @parameter, to specify the
- - * parameters that should be passed to the resulting action.
- */
- gSignals [LOOKUP] =
- g_signal_new ("lookup",
- @@ -381,13 +407,39 @@ gb_command_provider_class_init (GbCommandProviderClass *klass)
- NULL,
- NULL,
- GB_TYPE_COMMAND,
- - 1,
- - G_TYPE_STRING);
- + 2,
- + G_TYPE_STRING,
- + G_TYPE_POINTER);
- +
- + /**
- + * GbCommandProvider::validate:
- + * @initial_command_text: (in): the command line text to be processed.
- + * @result: (out): adress of a #GbResult pointer, giving the result of the validation.
- + *
- + * This signal is emitted when a request to validate the command text is
- + * received. Only the first handler will respond to the action.
- + *
- + * If the callee can parsed the initial text, TRUE is returned, FALSE otherwise.
- + */
- + gSignals [VALIDATE] =
- + g_signal_new ("validate",
- + GB_TYPE_COMMAND_PROVIDER,
- + G_SIGNAL_RUN_LAST,
- + G_STRUCT_OFFSET (GbCommandProviderClass, validate),
- + g_signal_accumulator_first_wins,
- + NULL,
- + NULL,
- + G_TYPE_BOOLEAN,
- + 2,
- + G_TYPE_STRING,
- + G_TYPE_POINTER);
- /**
- * GbCommandProvider::complete:
- * @completions: (in): A #GPtrArray where completed strings can be added
- * @initial_command_text: (in): the command line text to be processed.
- + * @with_short_name: (in): indicate if you want the short name of the command and
- + * the remainder separated with a '/'
- *
- * This signal is emitted when a request to complete a command text is
- * received. All providers should all all possible completions, matching
- @@ -402,9 +454,10 @@ gb_command_provider_class_init (GbCommandProviderClass *klass)
- NULL,
- NULL,
- G_TYPE_NONE,
- - 2,
- + 3,
- G_TYPE_PTR_ARRAY,
- - G_TYPE_STRING);
- + G_TYPE_STRING,
- + G_TYPE_BOOLEAN);
- }
- static void
- diff --git a/plugins/command-bar/gb-command-provider.h b/plugins/command-bar/gb-command-provider.h
- index f1ee95b..80ff805 100644
- --- a/plugins/command-bar/gb-command-provider.h
- +++ b/plugins/command-bar/gb-command-provider.h
- @@ -24,6 +24,7 @@
- #include "gb-command.h"
- #include "gb-view.h"
- #include "gb-workbench-types.h"
- +#include "gb-command-result.h"
- G_BEGIN_DECLS
- @@ -35,24 +36,32 @@ struct _GbCommandProviderClass
- {
- GObjectClass parent;
- - GbCommand *(*lookup) (GbCommandProvider *provider,
- - const gchar *command_text);
- - void (*complete) (GbCommandProvider *provider,
- - GPtrArray *completions,
- - const gchar *command_text);
- + GbCommand *(*lookup) (GbCommandProvider *provider,
- + const gchar *command_text,
- + GbCommandResult **result);
- + gboolean (*validate) (GbCommandProvider *provider,
- + const gchar *command_text,
- + GbCommandResult **result);
- + void (*complete) (GbCommandProvider *provider,
- + GPtrArray *completions,
- + const gchar *command_text);
- };
- -GbCommandProvider *gb_command_provider_new (GbWorkbench *workbench);
- -GbWorkbench *gb_command_provider_get_workbench (GbCommandProvider *provider);
- -GbView *gb_command_provider_get_active_view (GbCommandProvider *provider);
- -gint gb_command_provider_get_priority (GbCommandProvider *provider);
- -void gb_command_provider_set_priority (GbCommandProvider *provider,
- - gint priority);
- -GbCommand *gb_command_provider_lookup (GbCommandProvider *provider,
- - const gchar *command_text);
- -void gb_command_provider_complete (GbCommandProvider *provider,
- - GPtrArray *completions,
- - const gchar *initial_command_text);
- +GbCommandProvider *gb_command_provider_new (GbWorkbench *workbench);
- +GbWorkbench *gb_command_provider_get_workbench (GbCommandProvider *provider);
- +GbView *gb_command_provider_get_active_view (GbCommandProvider *provider);
- +gint gb_command_provider_get_priority (GbCommandProvider *provider);
- +void gb_command_provider_set_priority (GbCommandProvider *provider,
- + gint priority);
- +GbCommand *gb_command_provider_lookup (GbCommandProvider *provider,
- + const gchar *command_text,
- + GbCommandResult **result);
- +gboolean gb_command_provider_validate (GbCommandProvider *provider,
- + const gchar *initial_command_text,
- + GbCommandResult **result);
- +void gb_command_provider_complete (GbCommandProvider *provider,
- + GPtrArray *completions,
- + const gchar *initial_command_text);
- G_END_DECLS
- diff --git a/plugins/command-bar/gb-command-vim-provider.c b/plugins/command-bar/gb-command-vim-provider.c
- index e12484a..b45b159 100644
- --- a/plugins/command-bar/gb-command-vim-provider.c
- +++ b/plugins/command-bar/gb-command-vim-provider.c
- @@ -31,12 +31,13 @@
- struct _GbCommandVimProvider
- {
- - GbCommandProvider parent_instance;
- + GbCommandProvider parent_instance;
- + IdeVimParser *parser;
- };
- G_DEFINE_TYPE (GbCommandVimProvider, gb_command_vim_provider, GB_TYPE_COMMAND_PROVIDER)
- -GtkWidget *
- +static GtkWidget *
- get_source_view (GbCommandProvider *provider)
- {
- GbWorkbench *workbench;
- @@ -64,20 +65,61 @@ get_source_view (GbCommandProvider *provider)
- }
- static GbCommand *
- -gb_command_vim_provider_lookup (GbCommandProvider *provider,
- - const gchar *command_text)
- +gb_command_vim_provider_lookup (GbCommandProvider *provider,
- + const gchar *command_text,
- + GbCommandResult **result)
- {
- GtkWidget *source_view;
- + IdeVimParser *parser;
- + IdeVimParserCommand *command;
- + IdeVimParserError *error = NULL;
- + g_autofree gchar *detail = NULL;
- + const gchar *message;
- g_return_val_if_fail (GB_IS_COMMAND_VIM_PROVIDER (provider), NULL);
- g_return_val_if_fail (command_text, NULL);
- source_view = get_source_view (provider);
- + parser = GB_COMMAND_VIM_PROVIDER (provider)->parser;
- - return g_object_new (GB_TYPE_COMMAND_VIM,
- - "command-text", command_text,
- - "source-view", source_view,
- - NULL);
- + command = gb_vim_lookup (GTK_SOURCE_VIEW (source_view), parser, command_text, &error);
- + if (command != NULL)
- + {
- + return g_object_new (GB_TYPE_COMMAND_VIM,
- + "command-text", command_text,
- + "source-view", source_view,
- + "vim-parser", parser,
- + "command", command,
- + NULL);
- + }
- +
- + if (error != NULL)
- + {
- + message = ide_vim_parser_error_get_message (ide_vim_parser_error_get_error_code (error));
- + detail = ide_vim_parser_error_get_detail (error);
- + *result = g_object_new (GB_TYPE_COMMAND_RESULT,
- + "is-error", TRUE,
- + "command-text", message,
- + "result-text", detail,
- + NULL);
- + }
- +
- + return NULL;
- +}
- +
- +static gboolean
- +gb_command_vim_provider_validate (GbCommandProvider *provider,
- + const gchar *command_text,
- + GbCommandResult **result)
- +{
- + GtkWidget *source_view;
- +
- + g_return_val_if_fail (GB_IS_COMMAND_VIM_PROVIDER (provider), FALSE);
- + g_return_val_if_fail (command_text, FALSE);
- +
- + source_view = get_source_view (provider);
- +
- + return TRUE;
- }
- static void
- @@ -85,32 +127,157 @@ gb_command_vim_provider_complete (GbCommandProvider *provider,
- GPtrArray *completions,
- const gchar *initial_command_text)
- {
- + GbCommandVimProvider *self = GB_COMMAND_VIM_PROVIDER (provider);
- GtkWidget *source_view;
- - gchar **results;
- + GPtrArray *results;
- gsize i;
- - g_return_if_fail (GB_IS_COMMAND_VIM_PROVIDER (provider));
- g_return_if_fail (completions);
- g_return_if_fail (initial_command_text);
- source_view = get_source_view (provider);
- - results = gb_vim_complete (GTK_SOURCE_VIEW (source_view), initial_command_text);
- - for (i = 0; results [i]; i++)
- - g_ptr_array_add (completions, results [i]);
- - g_free (results);
- + results = gb_vim_complete (self->parser, GTK_SOURCE_VIEW (source_view), initial_command_text);
- + if (results != NULL)
- + {
- + for (i = 0; i < results->len; i++)
- + g_ptr_array_add (completions, g_ptr_array_index (results, i));
- +
- + /* We need to keep the elememts */
- + g_ptr_array_set_free_func (results, NULL);
- + g_ptr_array_free (results, TRUE);
- + }
- +}
- +
- +static void
- +gb_command_vim_provider_fill_command_table (IdeVimParser *parser)
- +{
- + ide_vim_parser_add_command (parser, "bnext", "bn", gb_vim_command_bnext,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "bprevious", "bp", gb_vim_command_bprevious,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "cnext", "cn", gb_vim_command_cnext,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "cprevious", "cp", gb_vim_command_cprevious,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "buffers", NULL, gb_vim_command_buffers,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "ls", NULL, gb_vim_command_buffers,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "nohl", NULL, gb_vim_command_nohl,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "quit", NULL, gb_vim_command_quit,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "write", "w", gb_vim_command_write,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_STRING, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "wq", NULL, gb_vim_command_wq,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_STRING, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "split", "sp", gb_vim_command_split,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_STRING, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "vsplit", "vs", gb_vim_command_vsplit,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_STRING, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "colorscheme", NULL, gb_vim_command_colorscheme,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_STRING, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "make", NULL, gb_vim_command_make,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "syntax", "sy", gb_vim_command_syntax,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_STRING, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "help", NULL, gb_vim_command_help,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_STRING, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "tabedit", "tabe", gb_vim_command_tabedit,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_STRING, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "edit", "e", gb_vim_command_edit,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_STRING, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "sort", "sor", gb_vim_command_sort,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL);
- +
- + ide_vim_parser_add_command (parser, "set", "se", gb_vim_command_set,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_STRING, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL);
- +}
- +
- +static void
- +gb_command_vim_provider_finalize (GObject *object)
- +{
- + GbCommandVimProvider *self = GB_COMMAND_VIM_PROVIDER (object);
- +
- + g_clear_pointer (&self->parser, g_object_unref);
- +
- + G_OBJECT_CLASS (gb_command_vim_provider_parent_class)->finalize (object);
- }
- static void
- gb_command_vim_provider_class_init (GbCommandVimProviderClass *klass)
- {
- + GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GbCommandProviderClass *provider_class = GB_COMMAND_PROVIDER_CLASS (klass);
- + object_class->finalize = gb_command_vim_provider_finalize;
- +
- provider_class->lookup = gb_command_vim_provider_lookup;
- provider_class->complete = gb_command_vim_provider_complete;
- + provider_class->validate = gb_command_vim_provider_validate;
- }
- static void
- gb_command_vim_provider_init (GbCommandVimProvider *self)
- {
- + self->parser = ide_vim_parser_new ();
- +
- + gb_command_vim_provider_fill_command_table (self->parser);
- }
- diff --git a/plugins/command-bar/gb-command-vim-provider.h b/plugins/command-bar/gb-command-vim-provider.h
- index 5e4dffe..d9c6889 100644
- --- a/plugins/command-bar/gb-command-vim-provider.h
- +++ b/plugins/command-bar/gb-command-vim-provider.h
- @@ -20,6 +20,7 @@
- #define GB_COMMAND_VIM_PROVIDER_H
- #include "gb-command-provider.h"
- +#include "gb-command-result.h"
- G_BEGIN_DECLS
- diff --git a/plugins/command-bar/gb-command-vim.c b/plugins/command-bar/gb-command-vim.c
- index bb0981a..74bdb5a 100644
- --- a/plugins/command-bar/gb-command-vim.c
- +++ b/plugins/command-bar/gb-command-vim.c
- @@ -19,25 +19,30 @@
- #define G_LOG_DOMAIN "gb-command-vim"
- #include <glib/gi18n.h>
- -#include <ide.h>
- +#include <glib/gprintf.h>
- +#include "gb-command-result.h"
- #include "gb-command-vim.h"
- #include "gb-vim.h"
- struct _GbCommandVim
- {
- - GbCommand parent_instance;
- + GbCommand parent_instance;
- - IdeSourceView *source_view;
- - gchar *command_text;
- + IdeSourceView *source_view;
- + IdeVimParser *vim_parser;
- + IdeVimParserCommand *command;
- + gchar *command_text;
- };
- G_DEFINE_TYPE (GbCommandVim, gb_command_vim, GB_TYPE_COMMAND)
- enum {
- PROP_0,
- + PROP_COMMAND,
- PROP_COMMAND_TEXT,
- PROP_SOURCE_VIEW,
- + PROP_VIM_PARSER,
- LAST_PROP
- };
- @@ -62,6 +67,44 @@ gb_command_vim_set_source_view (GbCommandVim *vim,
- g_object_notify_by_pspec (G_OBJECT (vim), gParamSpecs [PROP_SOURCE_VIEW]);
- }
- +IdeVimParserCommand *
- +gb_command_vim_get_command (GbCommandVim *vim)
- +{
- + g_return_val_if_fail (GB_IS_COMMAND_VIM (vim), NULL);
- +
- + return vim->command;
- +}
- +
- +static void
- +gb_command_vim_set_command (GbCommandVim *vim,
- + IdeVimParserCommand *command)
- +{
- + g_return_if_fail (GB_IS_COMMAND_VIM (vim));
- + g_return_if_fail (IDE_IS_VIM_PARSER_COMMAND (command));
- +
- + if (ide_set_weak_pointer (&vim->command, command))
- + g_object_notify_by_pspec (G_OBJECT (vim), gParamSpecs [PROP_COMMAND]);
- +}
- +
- +IdeVimParser *
- +gb_command_vim_get_vim_parser (GbCommandVim *vim)
- +{
- + g_return_val_if_fail (GB_IS_COMMAND_VIM (vim), NULL);
- +
- + return vim->vim_parser;
- +}
- +
- +static void
- +gb_command_vim_set_vim_parser (GbCommandVim *vim,
- + IdeVimParser *vim_parser)
- +{
- + g_return_if_fail (GB_IS_COMMAND_VIM (vim));
- + g_return_if_fail (IDE_IS_VIM_PARSER (vim_parser));
- +
- + if (ide_set_weak_pointer (&vim->vim_parser, vim_parser))
- + g_object_notify_by_pspec (G_OBJECT (vim), gParamSpecs [PROP_VIM_PARSER]);
- +}
- +
- const gchar *
- gb_command_vim_get_command_text (GbCommandVim *vim)
- {
- @@ -70,16 +113,16 @@ gb_command_vim_get_command_text (GbCommandVim *vim)
- return vim->command_text;
- }
- -void
- +static void
- gb_command_vim_set_command_text (GbCommandVim *vim,
- const gchar *command_text)
- {
- g_return_if_fail (GB_IS_COMMAND_VIM (vim));
- - g_return_if_fail (command_text);
- + g_return_if_fail (command_text != NULL);
- if (command_text != vim->command_text)
- {
- - g_free (vim->command_text);
- + g_clear_pointer (&vim->command_text, g_free);
- vim->command_text = g_strdup (command_text);
- g_object_notify_by_pspec (G_OBJECT (vim), gParamSpecs [PROP_COMMAND_TEXT]);
- }
- @@ -89,24 +132,32 @@ static GbCommandResult *
- gb_command_vim_execute (GbCommand *command)
- {
- GbCommandVim *self = (GbCommandVim *)command;
- + IdeVimParserError *error = NULL;
- + GbCommandResult *result = NULL;
- + g_autofree gchar * detail = NULL;
- g_return_val_if_fail (GB_IS_COMMAND_VIM (self), NULL);
- - if (self->source_view)
- + if (self->source_view != NULL && self->command != NULL)
- {
- GtkSourceView *source_view = (GtkSourceView *)self->source_view;
- - GError *error = NULL;
- + IdeVimParser *vim_parser = IDE_VIM_PARSER (self->vim_parser);
- IDE_TRACE_MSG ("Executing Vim command: %s", self->command_text);
- - if (!gb_vim_execute (source_view, self->command_text, &error))
- + if (!gb_vim_execute (source_view, vim_parser, self->command, &error))
- {
- - g_warning ("%s", error->message);
- - g_clear_error (&error);
- + detail = ide_vim_parser_error_get_detail (error);
- + g_printf ("execute, detail:%s\n", detail);
- + result = g_object_new (GB_TYPE_COMMAND_RESULT,
- + "is-error", TRUE,
- + "command-text", error->code_text,
- + "result-text", detail,
- + NULL);
- }
- }
- - return NULL;
- + return result;
- }
- static void
- @@ -115,6 +166,8 @@ gb_command_vim_finalize (GObject *object)
- GbCommandVim *self = GB_COMMAND_VIM (object);
- ide_clear_weak_pointer (&self->source_view);
- + ide_clear_weak_pointer (&self->vim_parser);
- + ide_clear_weak_pointer (&self->command);
- g_clear_pointer (&self->command_text, g_free);
- G_OBJECT_CLASS (gb_command_vim_parent_class)->finalize (object);
- @@ -130,6 +183,10 @@ gb_command_vim_get_property (GObject *object,
- switch (prop_id)
- {
- + case PROP_COMMAND:
- + g_value_set_object (value, gb_command_vim_get_command (self));
- + break;
- +
- case PROP_COMMAND_TEXT:
- g_value_set_string (value, gb_command_vim_get_command_text (self));
- break;
- @@ -138,6 +195,10 @@ gb_command_vim_get_property (GObject *object,
- g_value_set_object (value, gb_command_vim_get_source_view (self));
- break;
- + case PROP_VIM_PARSER:
- + g_value_set_object (value, gb_command_vim_get_vim_parser (self));
- + break;
- +
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
- @@ -153,6 +214,10 @@ gb_command_vim_set_property (GObject *object,
- switch (prop_id)
- {
- + case PROP_COMMAND:
- + gb_command_vim_set_command (self, g_value_get_object (value));
- + break;
- +
- case PROP_COMMAND_TEXT:
- gb_command_vim_set_command_text (self, g_value_get_string (value));
- break;
- @@ -161,6 +226,10 @@ gb_command_vim_set_property (GObject *object,
- gb_command_vim_set_source_view (self, g_value_get_object (value));
- break;
- + case PROP_VIM_PARSER:
- + gb_command_vim_set_vim_parser (self, g_value_get_object (value));
- + break;
- +
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
- @@ -178,6 +247,14 @@ gb_command_vim_class_init (GbCommandVimClass *klass)
- command_class->execute = gb_command_vim_execute;
- + gParamSpecs [PROP_COMMAND] =
- + g_param_spec_object ("command",
- + _("IdeVimParserCommand command"),
- + _("The IdeVimParserCommand parsed from the command text."),
- + IDE_TYPE_VIM_PARSER_COMMAND,
- + (G_PARAM_READWRITE |
- + G_PARAM_STATIC_STRINGS));
- +
- gParamSpecs [PROP_COMMAND_TEXT] =
- g_param_spec_string ("command-text",
- _("Command Text"),
- @@ -194,6 +271,14 @@ gb_command_vim_class_init (GbCommandVimClass *klass)
- (G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
- + gParamSpecs [PROP_VIM_PARSER] =
- + g_param_spec_object ("vim-parser",
- + _("Vim Parser"),
- + _("The parser used with this command."),
- + IDE_TYPE_VIM_PARSER,
- + (G_PARAM_READWRITE |
- + G_PARAM_STATIC_STRINGS));
- +
- g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
- }
- diff --git a/plugins/command-bar/gb-command-vim.h b/plugins/command-bar/gb-command-vim.h
- index 03a919c..8a232d7 100644
- --- a/plugins/command-bar/gb-command-vim.h
- +++ b/plugins/command-bar/gb-command-vim.h
- @@ -19,6 +19,8 @@
- #ifndef GB_COMMAND_VIM_H
- #define GB_COMMAND_VIM_H
- +#include <ide.h>
- +
- #include "gb-command.h"
- G_BEGIN_DECLS
- @@ -27,6 +29,10 @@ G_BEGIN_DECLS
- G_DECLARE_FINAL_TYPE (GbCommandVim, gb_command_vim, GB, COMMAND_VIM, GbCommand)
- +IdeVimParserCommand *gb_command_vim_get_command (GbCommandVim *vim);
- +const gchar *gb_command_vim_get_command_text (GbCommandVim *command_vim);
- +IdeSourceView *gb_command_vim_get_source_view (GbCommandVim *vim);
- +IdeVimParser *gb_command_vim_get_vim_parser (GbCommandVim *vim);
- G_END_DECLS
- diff --git a/plugins/command-bar/gb-command.c b/plugins/command-bar/gb-command.c
- index 191bc65..3db56bd 100644
- --- a/plugins/command-bar/gb-command.c
- +++ b/plugins/command-bar/gb-command.c
- @@ -16,9 +16,24 @@
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- +#include <string.h>
- +
- +#include <glib/gi18n.h>
- +#include <glib/gprintf.h>
- +
- +#include <ide.h>
- +
- #include "gb-command.h"
- -G_DEFINE_TYPE (GbCommand, gb_command, G_TYPE_OBJECT)
- +typedef struct
- +{
- + gchar *name;
- + gchar *shortname;
- + gchar *syntax;
- + gint id;
- +} GbCommandPrivate;
- +
- +G_DEFINE_TYPE_WITH_PRIVATE (GbCommand, gb_command, G_TYPE_OBJECT)
- enum {
- EXECUTE,
- @@ -27,6 +42,116 @@ enum {
- static guint gSignals [LAST_SIGNAL];
- +enum {
- + PROP_0,
- + PROP_NAME,
- + PROP_SHORTNAME,
- + PROP_SYNTAX,
- + LAST_PROP
- +};
- +
- +static GParamSpec *gParamSpecs [LAST_PROP];
- +
- +const gchar *
- +gb_command_get_name (GbCommand *self)
- +{
- + GbCommandPrivate *priv = gb_command_get_instance_private (self);
- +
- + return priv->name;
- +}
- +
- +const gchar *
- +gb_command_get_shortname (GbCommand *self)
- +{
- + GbCommandPrivate *priv = gb_command_get_instance_private (self);
- +
- + return priv->shortname;
- +}
- +
- +const gchar *
- +gb_command_get_syntax (GbCommand *self)
- +{
- + const gchar *str = NULL;
- +
- + /* TODO: not yet implemented */
- +
- + return str;
- +}
- +
- +static void
- +gb_command_set_shortname (GbCommand *self,
- + const gchar *shortname)
- +{
- + GbCommandPrivate *priv = gb_command_get_instance_private (self);
- + guint shortname_len;
- +
- + if (!ide_str_empty0 (shortname))
- + {
- + shortname_len = strlen (shortname);
- + if (shortname_len > 0 && shortname_len < strlen (priv->name) && g_str_has_prefix (priv->name, shortname))
- + priv->shortname = g_strdup (shortname);
- + else
- + g_warning ("The shortname must be a prefix of the name and its length between 1 and name length - 1");
- + }
- +}
- +
- +static void
- +gb_command_get_property (GObject *object,
- + guint prop_id,
- + GValue *value,
- + GParamSpec *pspec)
- +{
- + GbCommand *self = GB_COMMAND (object);
- + GbCommandPrivate *priv = gb_command_get_instance_private (self);
- +
- + switch (prop_id)
- + {
- + case PROP_NAME:
- + g_value_set_string (value, priv->name);
- + break;
- +
- + case PROP_SHORTNAME:
- + g_value_set_string (value, priv->shortname);
- + break;
- +
- + case PROP_SYNTAX:
- + g_value_set_string (value, priv->syntax);
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- +static void
- +gb_command_set_property (GObject *object,
- + guint prop_id,
- + const GValue *value,
- + GParamSpec *pspec)
- +{
- + GbCommand *self = GB_COMMAND (object);
- + GbCommandPrivate *priv = gb_command_get_instance_private (self);
- +
- +
- + switch (prop_id)
- + {
- + case PROP_NAME:
- + priv->name = g_value_dup_string (value);
- + break;
- +
- + case PROP_SHORTNAME:
- + gb_command_set_shortname (self, g_value_get_string (value));
- + break;
- +
- + case PROP_SYNTAX:
- + priv->syntax = g_value_dup_string (value);
- + break;
- +
- + default:
- + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- + }
- +}
- +
- GbCommand *
- gb_command_new (void)
- {
- @@ -51,6 +176,11 @@ gb_command_execute (GbCommand *command)
- static void
- gb_command_class_init (GbCommandClass *klass)
- {
- + GObjectClass *object_class = G_OBJECT_CLASS (klass);
- +
- + object_class->get_property = gb_command_get_property;
- + object_class->set_property = gb_command_set_property;
- +
- klass->execute = gb_command_real_execute;
- gSignals [EXECUTE] =
- @@ -62,6 +192,45 @@ gb_command_class_init (GbCommandClass *klass)
- NULL, NULL,
- GB_TYPE_COMMAND_RESULT,
- 0);
- +
- + /**
- + * GbCommand:name:
- + *
- + * A string holding the name of the command.
- + */
- + gParamSpecs[PROP_NAME] =
- + g_param_spec_string ("name",
- + _("Command name"),
- + _("The name of the command."),
- + NULL,
- + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * GbCommand:shortname:
- + *
- + * A string holding the shortname of the command.
- + */
- + gParamSpecs[PROP_SHORTNAME] =
- + g_param_spec_string ("shortname",
- + _("Command shortname"),
- + _("The shortname of the command."),
- + NULL,
- + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- +
- + /**
- + * GbCommand:syntax:
- + *
- + * A string holding the syntax of the command,
- + * mostly used for helping purpose.
- + */
- + gParamSpecs[PROP_SYNTAX] =
- + g_param_spec_string ("syntax",
- + _("Command syntax"),
- + _("The syntax of the command."),
- + NULL,
- + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |G_PARAM_STATIC_STRINGS);
- +
- + g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
- }
- static void
- diff --git a/plugins/command-bar/gb-command.h b/plugins/command-bar/gb-command.h
- index 1d666ed..bb98d66 100644
- --- a/plugins/command-bar/gb-command.h
- +++ b/plugins/command-bar/gb-command.h
- @@ -33,11 +33,14 @@ struct _GbCommandClass
- {
- GObjectClass parent;
- - GbCommandResult *(*execute) (GbCommand *command);
- + GbCommandResult *(*execute) (GbCommand *command);
- };
- -GbCommand *gb_command_new (void);
- -GbCommandResult *gb_command_execute (GbCommand *command);
- +GbCommand *gb_command_new (void);
- +GbCommandResult *gb_command_execute (GbCommand *command);
- +const gchar *gb_command_get_name (GbCommand *command);
- +const gchar *gb_command_get_shortname (GbCommand *command);
- +const gchar *gb_command_get_syntax (GbCommand *command);
- G_END_DECLS
- diff --git a/plugins/command-bar/gb-vim.c b/plugins/command-bar/gb-vim.c
- index 5003fef..b0f3fff 100644
- --- a/plugins/command-bar/gb-vim.c
- +++ b/plugins/command-bar/gb-vim.c
- @@ -20,12 +20,14 @@
- #include <errno.h>
- #include <glib/gi18n.h>
- +#include <glib/gprintf.h>
- #include <ide.h>
- #include "gb-string.h"
- #include "gb-vim.h"
- #include "gb-widget.h"
- #include "gb-workbench.h"
- +#include "gb-command-complete-item.h"
- G_DEFINE_QUARK (gb-vim-error-quark, gb_vim_error)
- @@ -299,19 +301,21 @@ lookup_set (const gchar *key)
- return NULL;
- }
- -static gboolean
- -gb_vim_command_set (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_set (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- gboolean ret = FALSE;
- gchar **parts;
- gsize i;
- + gchar *options = NULL;
- +
- g_assert (GTK_SOURCE_IS_VIEW (source_view));
- - g_assert (command);
- - g_assert (options);
- + g_assert (IDE_IS_VIM_PARSER (parser));
- + g_assert (IDE_IS_VIM_PARSER_COMMAND (command));
- parts = g_strsplit (options, " ", 0);
- @@ -342,17 +346,20 @@ gb_vim_command_set (GtkSourceView *source_view,
- if (set == NULL)
- {
- + /*
- g_set_error (error,
- GB_VIM_ERROR,
- GB_VIM_ERROR_UNKNOWN_OPTION,
- _("Unknown option: %s"),
- key);
- + */
- goto cleanup;
- }
- -
- +/*
- if (!set->func (source_view, key, value, error))
- goto cleanup;
- - }
- +*/
- + }
- ret = TRUE;
- @@ -362,72 +369,93 @@ cleanup:
- return ret;
- }
- -static gboolean
- -gb_vim_command_colorscheme (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_colorscheme (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- GtkSourceStyleSchemeManager *manager;
- GtkSourceStyleScheme *style_scheme;
- GtkTextBuffer *buffer;
- - g_autofree gchar *trimmed = NULL;
- + const gchar *colorscheme = NULL;
- - trimmed = g_strstrip (g_strdup (options));
- + if (ide_vim_parser_command_get_string_arg (command, 1, &colorscheme))
- + {
- + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
- + manager = gtk_source_style_scheme_manager_get_default ();
- + style_scheme = gtk_source_style_scheme_manager_get_scheme (manager, colorscheme);
- - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
- - manager = gtk_source_style_scheme_manager_get_default ();
- - style_scheme = gtk_source_style_scheme_manager_get_scheme (manager, trimmed);
- + if (style_scheme == NULL)
- + {
- + ide_vim_parser_error_literal_set (error, IDE_VIM_PARSER_ERROR_UNKNOWN_OPTION,
- + _("Cannot find colorscheme '%s'"), colorscheme);
- + return FALSE;
- + }
- - if (style_scheme == NULL)
- - {
- - g_set_error (error,
- - GB_VIM_ERROR,
- - GB_VIM_ERROR_UNKNOWN_OPTION,
- - _("Cannot find colorscheme '%s'"),
- - options);
- - return FALSE;
- - }
- + g_object_set (buffer, "style-scheme", style_scheme, NULL);
- - g_object_set (buffer, "style-scheme", style_scheme, NULL);
- + return TRUE;
- + }
- + /* TODO: error handle: here, missuse of ide_vim_parser_command_get_string_arg
- + * so a g_critical */
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_edit (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +static GFile *
- +get_working_dir (GbWorkbench *workbench,
- + IdeVimParserError **error)
- {
- - GbWorkbench *workbench;
- IdeContext *context;
- IdeVcs *vcs;
- + GFile *workdir = NULL;
- +
- + if (!(context = gb_workbench_get_context (workbench)) ||
- + !(vcs = ide_context_get_vcs (context)) ||
- + !(workdir = ide_vcs_get_working_directory (vcs)))
- + ide_vim_parser_error_set (error, IDE_VIM_PARSER_ERROR_NO_WORKING_DIR, NULL);
- +
- + return workdir;
- +}
- +
- +gboolean
- +gb_vim_command_edit (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- +{
- + GbWorkbench *workbench;
- GFile *workdir;
- GFile *file = NULL;
- + const gchar *file_name = NULL;
- + IdeVimParserError *tmp_error = NULL;
- - if (gb_str_empty0 (options))
- + if (!ide_vim_parser_command_get_string_arg (command, 1, &file_name))
- {
- + g_printf ("edit open");
- gb_widget_activate_action (GTK_WIDGET (source_view), "workbench", "open", NULL);
- return TRUE;
- }
- - if (!(workbench = gb_widget_get_workbench (GTK_WIDGET (source_view))) ||
- - !(context = gb_workbench_get_context (workbench)) ||
- - !(vcs = ide_context_get_vcs (context)) ||
- - !(workdir = ide_vcs_get_working_directory (vcs)))
- + workbench = gb_widget_get_workbench (GTK_WIDGET (source_view));
- + g_assert (workbench != NULL);
- +
- + if (g_path_is_absolute (file_name))
- {
- - g_set_error (error,
- - GB_VIM_ERROR,
- - GB_VIM_ERROR_NOT_SOURCE_VIEW,
- - _("Failed to locate working directory"));
- - return FALSE;
- + file = g_file_new_for_path (file_name);
- }
- -
- - if (g_path_is_absolute (options))
- - file = g_file_new_for_path (options);
- else
- - file = g_file_get_child (workdir, options);
- + {
- + workdir = get_working_dir (workbench, &tmp_error);
- + if (workdir == NULL)
- + {
- + ide_vim_parser_error_propagate (error, tmp_error);
- + return FALSE;
- + }
- +
- + file = g_file_get_child (workdir, file_name);
- + }
- gb_workbench_open (workbench, file);
- @@ -436,76 +464,91 @@ gb_vim_command_edit (GtkSourceView *source_view,
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_tabe (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_tabedit (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- - if (!gb_str_empty0 (options))
- - return gb_vim_command_edit (source_view, command, options, error);
- + const gchar *file_name = NULL;
- +
- + if (ide_vim_parser_command_get_string_arg (command, 1, &file_name))
- + return gb_vim_command_edit (source_view, parser, command, error);
- gb_widget_activate_action (GTK_WIDGET (source_view), "workbench", "new-document", NULL);
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_quit (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_quit (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- + gboolean has_bang;
- +
- + /* TODO: handle bang */
- + has_bang = ide_vim_parser_command_has_bang (command);
- + if (has_bang)
- + g_printf ("has bang\n");
- +
- gb_widget_activate_action (GTK_WIDGET (source_view), "view", "save", NULL);
- gb_widget_activate_action (GTK_WIDGET (source_view), "view", "close", NULL);
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_split (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_split (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- + /* TODO: handle file argument */
- +
- gb_widget_activate_action (GTK_WIDGET (source_view), "view-stack", "split-down", NULL);
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_vsplit (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_vsplit (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- + /* TODO: handle file argument */
- +
- gb_widget_activate_action (GTK_WIDGET (source_view), "view-stack", "split-left", NULL);
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_write (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_write (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- + /* TODO: handle file argument */
- gb_widget_activate_action (GTK_WIDGET (source_view), "view", "save", NULL);
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_wq (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_wq (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- - return (gb_vim_command_write (source_view, command, options, error) &&
- - gb_vim_command_quit (source_view, command, options, error));
- + /* TODO: check separate error return */
- + return (gb_vim_command_write (source_view, parser, command, error) &&
- + gb_vim_command_quit (source_view, parser, command, error));
- }
- -static gboolean
- -gb_vim_command_nohl (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_nohl (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- if (IDE_IS_SOURCE_VIEW (source_view))
- {
- @@ -519,44 +562,49 @@ gb_vim_command_nohl (GtkSourceView *source_view,
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_make (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_make (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- gb_widget_activate_action (GTK_WIDGET (source_view), "workbench", "build", NULL);
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_syntax (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_syntax (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- - if (g_str_equal (options, "enable") || g_str_equal (options, "on"))
- - g_object_set (source_view, "highlight-syntax", TRUE, NULL);
- - else if (g_str_equal (options, "off"))
- - g_object_set (source_view, "highlight-syntax", FALSE, NULL);
- - else
- + GtkSourceBuffer *buffer;
- + const gchar *option = NULL;
- +
- + if (ide_vim_parser_command_get_string_arg (command, 1, &option))
- {
- - g_set_error (error,
- - GB_VIM_ERROR,
- - GB_VIM_ERROR_UNKNOWN_OPTION,
- - _("Invalid :syntax subcommand: %s"),
- - options);
- - return FALSE;
- + buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view)));
- +
- + if (g_str_equal (option, "enable") || g_str_equal (option, "on"))
- + g_object_set (buffer, "highlight-syntax", TRUE, NULL);
- + else if (g_str_equal (option, "disable") || g_str_equal (option, "off"))
- + g_object_set (buffer, "highlight-syntax", FALSE, NULL);
- + else
- + {
- + ide_vim_parser_error_literal_set (error, IDE_VIM_PARSER_ERROR_UNKNOWN_OPTION,
- + _("Invalid :syntax subcommand: '%s'"), option);
- + return FALSE;
- + }
- }
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_sort (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_sort (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- if (IDE_IS_SOURCE_VIEW (source_view))
- {
- @@ -569,53 +617,77 @@ gb_vim_command_sort (GtkSourceView *source_view,
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_bnext (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_bnext (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- - gb_widget_activate_action (GTK_WIDGET (source_view), "view-stack", "next-view", NULL);
- + gint count;
- +
- + if (!ide_vim_parser_command_get_number_arg (command, 2, &count) &&
- + !ide_vim_parser_command_get_number_arg (command, 0, &count))
- + count = 1;
- +
- + gb_widget_activate_action (GTK_WIDGET (source_view), "view-stack", "next-view", g_variant_new_int64 (count));
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_bprevious (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_bprevious (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- - gb_widget_activate_action (GTK_WIDGET (source_view), "view-stack", "previous-view", NULL);
- + gint count;
- +
- + if (!ide_vim_parser_command_get_number_arg (command, 2, &count) &&
- + !ide_vim_parser_command_get_number_arg (command, 0, &count))
- + count = 1;
- +
- + gb_widget_activate_action (GTK_WIDGET (source_view), "view-stack", "previous-view", g_variant_new_int64 (count));
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_cnext (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_cnext (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- + gint count;
- +
- + if (!ide_vim_parser_command_get_number_arg (command, 2, &count) &&
- + !ide_vim_parser_command_get_number_arg (command, 0, &count))
- + count = 1;
- +
- if (IDE_IS_SOURCE_VIEW (source_view))
- - g_signal_emit_by_name (source_view, "move-error", GTK_DIR_DOWN);
- + g_signal_emit_by_name (source_view, "move-error", GTK_DIR_DOWN, count);
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_cprevious (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_cprevious (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- + gint count;
- +
- + if (!ide_vim_parser_command_get_number_arg (command, 2, &count) &&
- + !ide_vim_parser_command_get_number_arg (command, 0, &count))
- + count = 1;
- +
- if (IDE_IS_SOURCE_VIEW (source_view))
- - g_signal_emit_by_name (source_view, "move-error", GTK_DIR_UP);
- + g_signal_emit_by_name (source_view, "move-error", GTK_DIR_UP, count);
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_buffers (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_buffers (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- gb_widget_activate_action (GTK_WIDGET (source_view), "view-stack", "show-list", NULL);
- return TRUE;
- @@ -651,16 +723,21 @@ gb_vim_jump_to_line (GtkSourceView *source_view,
- return TRUE;
- }
- -static gboolean
- -gb_vim_command_help (GtkSourceView *source_view,
- - const gchar *command,
- - const gchar *options,
- - GError **error)
- +gboolean
- +gb_vim_command_help (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- {
- + const gchar *option = NULL;
- GVariant *param;
- - param = g_variant_new_string (options);
- - gb_widget_activate_action (GTK_WIDGET (source_view), "workbench", "search-docs", param);
- + if (ide_vim_parser_command_get_string_arg (command, 1, &option))
- + {
- + param = g_variant_new_string (option);
- + gb_widget_activate_action (GTK_WIDGET (source_view), "workbench", "search-docs", param);
- + }
- +
- return TRUE;
- }
- @@ -706,6 +783,8 @@ gb_vim_do_search_and_replace (GtkTextBuffer *buffer,
- g_assert (replace_text);
- g_assert ((!begin && !end) || (begin && end));
- + printf ("substitute: form:%s, to:%s, global:%i\n", search_text, replace_text, is_global);
- +
- search_settings = gtk_source_search_settings_new ();
- search_context = gtk_source_search_context_new (GTK_SOURCE_BUFFER (buffer), search_settings);
- @@ -772,11 +851,16 @@ gb_vim_command_search (GtkSourceView *source_view,
- gchar *search_text = NULL;
- gchar *replace_text = NULL;
- gunichar separator;
- + gboolean range_is_file = FALSE;
- g_assert (g_str_has_prefix (command, "%s") || g_str_has_prefix (command, "s"));
- if (*command == '%')
- - command++;
- + {
- + range_is_file = TRUE;
- + command++;
- + }
- +
- command++;
- separator = g_utf8_get_char (command);
- @@ -876,27 +960,27 @@ invalid_request:
- }
- static const GbVimCommand vim_commands[] = {
- - { "bnext", gb_vim_command_bnext , NULL},
- - { "bprevious", gb_vim_command_bprevious, NULL },
- - { "buffers", gb_vim_command_buffers, NULL },
- - { "ls", gb_vim_command_buffers, NULL },
- - { "cnext", gb_vim_command_cnext, NULL },
- - { "colorscheme", gb_vim_command_colorscheme, NULL },
- - { "cprevious", gb_vim_command_cprevious, NULL },
- - { "edit", gb_vim_command_edit, NULL },
- - { "help", gb_vim_command_help, NULL },
- - { "nohl", gb_vim_command_nohl, NULL },
- - { "make", gb_vim_command_make, NULL },
- - { "quit", gb_vim_command_quit, NULL },
- - { "set", gb_vim_command_set, NULL },
- - { "sort", gb_vim_command_sort, NULL },
- - { "split", gb_vim_command_split, NULL },
- - { "syntax", gb_vim_command_syntax, NULL },
- - { "tabe", gb_vim_command_tabe, NULL },
- - { "vsplit", gb_vim_command_vsplit, NULL },
- - { "w", gb_vim_command_write, NULL },
- - { "wq", gb_vim_command_wq, NULL },
- - { "write", gb_vim_command_write, NULL },
- + //{ "bnext", gb_vim_command_bnext , NULL},
- + //{ "bprevious", gb_vim_command_bprevious, NULL },
- + //{ "buffers", gb_vim_command_buffers, NULL },
- + //{ "ls", gb_vim_command_buffers, NULL },
- + //{ "cnext", gb_vim_command_cnext, NULL },
- + //{ "colorscheme", gb_vim_command_colorscheme, NULL },
- + //{ "cprevious", gb_vim_command_cprevious, NULL },
- + //{ "edit", gb_vim_command_edit, NULL },
- + //{ "help", gb_vim_command_help, NULL },
- + //{ "nohl", gb_vim_command_nohl, NULL },
- + //{ "make", gb_vim_command_make, NULL },
- + //{ "quit", gb_vim_command_quit, NULL },
- + //{ "set", gb_vim_command_set, NULL },
- + //{ "sort", gb_vim_command_sort, NULL },
- + //{ "split", gb_vim_command_split, NULL },
- + //{ "syntax", gb_vim_command_syntax, NULL },
- + //{ "tabe", gb_vim_command_tabe, NULL },
- + //{ "vsplit", gb_vim_command_vsplit, NULL },
- + //{ "w", gb_vim_command_write, NULL },
- + //{ "wq", gb_vim_command_wq, NULL },
- + //{ "write", gb_vim_command_write, NULL },
- { NULL }
- };
- @@ -934,73 +1018,70 @@ lookup_command (const gchar *name)
- return NULL;
- }
- -gboolean
- -gb_vim_execute (GtkSourceView *source_view,
- - const gchar *line,
- - GError **error)
- +IdeVimParserCommand *
- +gb_vim_lookup (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + const gchar *command_text,
- + IdeVimParserError **error)
- {
- + IdeVimParserCommand *command = NULL;
- + IdeVimParserError *tmp_error = NULL;
- GtkTextBuffer *buffer;
- - g_autofree gchar *name_slice = NULL;
- - const GbVimCommand *command;
- - const gchar *command_name = line;
- - const gchar *options;
- - g_autofree gchar *all_options = NULL;
- - gboolean result;
- - g_return_val_if_fail (GTK_SOURCE_IS_VIEW (source_view), FALSE);
- - g_return_val_if_fail (line, FALSE);
- + g_return_val_if_fail (GTK_SOURCE_IS_VIEW (source_view), NULL);
- + g_return_val_if_fail (IDE_IS_VIM_PARSER (parser), NULL);
- + g_return_val_if_fail (!gb_str_empty0 (command_text), NULL);
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
- -
- if (!GTK_SOURCE_IS_BUFFER (buffer))
- {
- - g_set_error (error,
- - GB_VIM_ERROR,
- - GB_VIM_ERROR_NOT_SOURCE_VIEW,
- - _("vim mode requires GtkSourceView"));
- - return FALSE;
- + ide_vim_parser_error_set (error, IDE_VIM_PARSER_ERROR_NO_BUFFER, NULL);
- + return NULL;
- }
- - for (options = line; *options; options = g_utf8_next_char (options))
- + /* TODO: check for go-to-line command */
- + command = ide_vim_parser_parse (parser, buffer, command_text, &tmp_error);
- + if (tmp_error != NULL)
- {
- - gunichar ch;
- -
- - ch = g_utf8_get_char (options);
- -
- - if (g_unichar_isspace (ch))
- - break;
- + ide_vim_parser_error_propagate (error, tmp_error);
- + return NULL;
- }
- - if (g_unichar_isspace (g_utf8_get_char (options)))
- - {
- - command_name = name_slice = g_strndup (line, options - line);
- - options = g_utf8_next_char (options);
- - }
- + ide_vim_parser_debug_show_parsed (command);
- + return command;
- +}
- - command = lookup_command (command_name);
- +gboolean
- +gb_vim_execute (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- +{
- + GtkTextBuffer *buffer;
- + IdeVimParserCommandFunc func;
- + gboolean result;
- + IdeVimParserError *tmp_error = NULL;
- - if (command == NULL)
- - {
- - if (looks_like_search_and_replace (line))
- - return gb_vim_command_search (source_view, line, "", error);
- + g_return_val_if_fail (GTK_SOURCE_IS_VIEW (source_view), FALSE);
- + g_return_val_if_fail (IDE_IS_VIM_PARSER (parser), FALSE);
- + g_return_val_if_fail (IDE_IS_VIM_PARSER_COMMAND (command), FALSE);
- - g_set_error (error,
- - GB_VIM_ERROR,
- - GB_VIM_ERROR_NOT_FOUND,
- - _("Not an editor command: %s"),
- - command_name);
- + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
- + if (!GTK_SOURCE_IS_BUFFER (buffer))
- + {
- + ide_vim_parser_error_set (error, IDE_VIM_PARSER_ERROR_NOT_SOURCE_VIEW, NULL);
- return FALSE;
- }
- - if (command->options_sup)
- - all_options = g_strconcat (options, " ", command->options_sup, NULL);
- - else
- - all_options = g_strdup (options);
- -
- - result = command->func (source_view, command_name, all_options, error);
- - g_free (command->options_sup);
- + func = ide_vim_parser_command_get_func (command);
- + result = func (source_view, parser, command, &tmp_error);
- + ide_vim_parser_error_propagate (error, tmp_error);
- return result;
- +/*
- + if (looks_like_search_and_replace (line))
- + return gb_vim_command_search (source_view, line, "", error);
- +*/
- }
- static gchar *
- @@ -1054,16 +1135,46 @@ gb_vim_complete_set (const gchar *line,
- g_strfreev (parts);
- }
- +static inline GbCommandCompleteItem *
- +convert_to_gb_command (IdeVimCompleteItem *ide_complete_item)
- +{
- + GbCommandCompleteItem *complete_item;
- +
- + complete_item = gb_command_complete_item_new (GB_COMMAND_COMPLETE_ITEM_KIND_COMMAND,
- + g_strdup (ide_vim_complete_item_get_name (ide_complete_item)),
- + g_strdup (ide_vim_complete_item_get_shortname (ide_complete_item)));
- +
- + return complete_item;
- +}
- +
- static void
- -gb_vim_complete_command (const gchar *line,
- - GPtrArray *ar)
- +gb_vim_complete_command (IdeVimParser *parser,
- + GtkTextBuffer *buffer,
- + const gchar *line,
- + GPtrArray *ar_dst)
- {
- gsize i;
- + GPtrArray *ar_src;
- + GbCommandCompleteItem *complete_item;
- +
- +/* Here we get a g_ptr_array of IdeVimCompleteItem and
- + * convert it to a g_prt_array of GbCommandCompleteItem.
- + * We need to decouple things this way because the whole
- + * IdeVimCmdlineParser has a vocation to land into GtkSourceView
- + * which know nothing about GbCommandCompleteItem.
- + */
- - for (i = 0; vim_commands [i].name; i++)
- + ar_src = ide_vim_parser_complete (parser, buffer, line);
- + if (ar_src != NULL)
- {
- - if (g_str_has_prefix (vim_commands [i].name, line))
- - g_ptr_array_add (ar, g_strdup (vim_commands [i].name));
- + guint len = ar_src->len;
- + for (i = 0; i < len; i++)
- + {
- + complete_item = convert_to_gb_command (g_ptr_array_index (ar_src, i));
- + g_ptr_array_add (ar_dst, complete_item);
- + }
- +
- + g_ptr_array_free (ar_src, TRUE);
- }
- }
- @@ -1253,13 +1364,22 @@ gb_vim_complete_colorscheme (const gchar *line,
- }
- }
- -gchar **
- -gb_vim_complete (GtkSourceView *source_view,
- - const gchar *line)
- +GPtrArray *
- +gb_vim_complete (IdeVimParser *parser,
- + GtkSourceView *source_view,
- + const gchar *line)
- {
- + GtkTextBuffer *buffer;
- GPtrArray *ar;
- - ar = g_ptr_array_new ();
- + ar = g_ptr_array_new_full (32, g_object_unref);
- +
- + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
- + if (!GTK_SOURCE_IS_BUFFER (buffer))
- + {
- + //ide_vim_parser_error_set (error, IDE_VIM_PARSER_ERROR_NO_BUFFER, NULL);
- + return NULL;
- + }
- if (line != NULL)
- {
- @@ -1272,10 +1392,17 @@ gb_vim_complete (GtkSourceView *source_view,
- else if (g_str_has_prefix (line, "colorscheme "))
- gb_vim_complete_colorscheme (line, ar);
- else
- - gb_vim_complete_command (line, ar);
- + gb_vim_complete_command (parser, buffer, line, ar);
- }
- - g_ptr_array_add (ar, NULL);
- -
- - return (gchar **)g_ptr_array_free (ar, FALSE);
- + g_printf ("line:%s, ar len:%i\n", line, ar->len);
- + if (ar->len > 0)
- + {
- + return ar;
- + }
- + else
- + {
- + g_ptr_array_free (ar, TRUE);
- + return NULL;
- + }
- }
- diff --git a/plugins/command-bar/gb-vim.h b/plugins/command-bar/gb-vim.h
- index e28499d..8fc8134 100644
- --- a/plugins/command-bar/gb-vim.h
- +++ b/plugins/command-bar/gb-vim.h
- @@ -21,6 +21,8 @@
- #include <gtksourceview/gtksource.h>
- +#include <ide.h>
- +
- G_BEGIN_DECLS
- #define GB_VIM_ERROR (gb_vim_error_quark())
- @@ -36,12 +38,96 @@ typedef enum
- GB_VIM_ERROR_NOT_SOURCE_VIEW,
- } IdeVimError;
- -GQuark gb_vim_error_quark (void);
- -gboolean gb_vim_execute (GtkSourceView *source_view,
- - const gchar *line,
- - GError **error);
- -gchar **gb_vim_complete (GtkSourceView *source_view,
- - const gchar *line);
- +GQuark gb_vim_error_quark (void);
- +gboolean gb_vim_execute (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +GPtrArray *gb_vim_complete (IdeVimParser *parser,
- + GtkSourceView *source_view,
- + const gchar *line);
- +IdeVimParserCommand *gb_vim_lookup (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + const gchar *command_text,
- + IdeVimParserError **error);
- +
- +/* Gb specific Vim Commands */
- +gboolean gb_vim_command_bnext (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_bprevious (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_cnext (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_cprevious (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_buffers (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_nohl (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_quit (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_write (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_wq (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_split (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_vsplit (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_colorscheme (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_make (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_syntax (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_help (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_tabedit (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_edit (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_sort (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- +gboolean gb_vim_command_set (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error);
- G_END_DECLS
- diff --git a/src/editor/gb-editor-frame.c b/src/editor/gb-editor-frame.c
- index d32cf53..09e3684 100644
- --- a/src/editor/gb-editor-frame.c
- +++ b/src/editor/gb-editor-frame.c
- @@ -547,8 +547,10 @@ gb_editor_frame_set_show_map (GbEditorFrame *self,
- G_CALLBACK (gb_editor_frame_hide_map),
- self,
- G_CONNECT_SWAPPED);
- +
- gtk_container_add (GTK_CONTAINER (self->source_map_container),
- GTK_WIDGET (self->source_map));
- +
- g_signal_emit_by_name (self->source_map, "show-map");
- }
- diff --git a/src/resources/gnome-builder.gresource.xml b/src/resources/gnome-builder.gresource.xml
- index c2805df..6a41a99 100644
- --- a/src/resources/gnome-builder.gresource.xml
- +++ b/src/resources/gnome-builder.gresource.xml
- @@ -16,7 +16,6 @@
- <file alias="theme/Adwaita-dark.css">../../data/theme/Adwaita-dark.css</file>
- <file alias="theme/Adwaita-shared.css">../../data/theme/Adwaita-shared.css</file>
- <file alias="theme/shared.css">../../data/theme/shared.css</file>
- -
- <file alias="ui/gb-editor-frame.ui">../../data/ui/gb-editor-frame.ui</file>
- <file alias="ui/gb-editor-settings-widget.ui">../../data/ui/gb-editor-settings-widget.ui</file>
- <file alias="ui/gb-editor-tweak-widget.ui">../../data/ui/gb-editor-tweak-widget.ui</file>
- diff --git a/src/views/gb-view-stack-actions.c b/src/views/gb-view-stack-actions.c
- index c2d5781..431cfc7 100644
- --- a/src/views/gb-view-stack-actions.c
- +++ b/src/views/gb-view-stack-actions.c
- @@ -26,6 +26,8 @@
- #include "gb-view-stack-actions.h"
- #include "gb-view-stack-private.h"
- +#include <glib/gprintf.h>
- +
- static void
- gb_view_stack_actions_close_cb (GObject *object,
- GAsyncResult *result,
- @@ -40,7 +42,6 @@ gb_view_stack_actions_close_cb (GObject *object,
- gb_view_stack_remove (self, view);
- }
- -
- static void
- gb_view_stack_actions_close (GSimpleAction *action,
- GVariant *param,
- @@ -169,13 +170,17 @@ gb_view_stack_actions_split_right (GSimpleAction *action,
- }
- static void
- -gb_view_stack_actions_next_view (GSimpleAction *action,
- - GVariant *param,
- - gpointer user_data)
- +move_in__history (GbViewStack *self,
- + gint count,
- + gboolean up)
- {
- - GbViewStack *self = user_data;
- GtkWidget *active_view;
- GtkWidget *new_view;
- + GList *children;
- + GtkListBoxRow *row;
- + gint selected_index;
- + gint new_index;
- + gint len;
- IDE_ENTRY;
- @@ -185,49 +190,59 @@ gb_view_stack_actions_next_view (GSimpleAction *action,
- if (active_view == NULL || !GB_IS_VIEW (active_view))
- return;
- - if (g_list_length (self->focus_history) <= 1)
- + children = gtk_container_get_children (GTK_CONTAINER (self->views_listbox));
- + len = g_list_length (children);
- + if (len <= 1)
- return;
- - new_view = g_list_last (self->focus_history)->data;
- + selected_index = gtk_list_box_row_get_index (gtk_list_box_get_selected_row (self->views_listbox));
- + if (up)
- + {
- + if (count > selected_index)
- + new_index = 0;
- + else
- + new_index = selected_index - count;
- + }
- + else
- + {
- + if (selected_index + count > len - 1)
- + new_index = len - 1;
- + else
- + new_index = selected_index + count;
- + }
- +
- + row = gtk_list_box_get_row_at_index (self->views_listbox, new_index);
- + new_view = GTK_WIDGET (g_object_get_data (G_OBJECT (row), "GB_VIEW"));
- g_assert (GB_IS_VIEW (new_view));
- gb_view_stack_set_active_view (self, new_view);
- -
- - IDE_EXIT;
- + g_list_free (children);
- }
- static void
- -gb_view_stack_actions_previous_view (GSimpleAction *action,
- - GVariant *param,
- - gpointer user_data)
- +gb_view_stack_actions_next_view (GSimpleAction *action,
- + GVariant *param,
- + gpointer user_data)
- {
- GbViewStack *self = user_data;
- - GtkWidget *active_view;
- - GtkWidget *new_view;
- IDE_ENTRY;
- - g_assert (GB_IS_VIEW_STACK (self));
- + move_in__history (self, g_variant_get_int64 (param), TRUE);
- - active_view = gb_view_stack_get_active_view (self);
- - if (active_view == NULL || !GB_IS_VIEW (active_view))
- - return;
- -
- - if (g_list_length (self->focus_history) <= 1)
- - return;
- -
- - g_assert (active_view);
- - g_assert (self->focus_history);
- - g_assert (self->focus_history->next);
- - g_assert (active_view == self->focus_history->data);
- + IDE_EXIT;
- +}
- - new_view = self->focus_history->next->data;
- - g_assert (GB_IS_VIEW (new_view));
- +static void
- +gb_view_stack_actions_previous_view (GSimpleAction *action,
- + GVariant *param,
- + gpointer user_data)
- +{
- +GbViewStack *self = user_data;
- - self->focus_history = g_list_remove_link (self->focus_history, self->focus_history);
- - self->focus_history = g_list_append (self->focus_history, active_view);
- + IDE_ENTRY;
- - gb_view_stack_set_active_view (self, new_view);
- + move_in__history (self, g_variant_get_int64 (param), FALSE);
- IDE_EXIT;
- }
- @@ -276,8 +291,8 @@ static const GActionEntry gGbViewStackActions[] = {
- { "go-backward", gb_view_stack_actions_go_backward },
- { "move-left", gb_view_stack_actions_move_left },
- { "move-right", gb_view_stack_actions_move_right },
- - { "next-view", gb_view_stack_actions_next_view },
- - { "previous-view", gb_view_stack_actions_previous_view },
- + { "next-view", gb_view_stack_actions_next_view, "x" },
- + { "previous-view", gb_view_stack_actions_previous_view, "x" },
- { "show-list", gb_view_stack_actions_show_list },
- { "split-down", NULL, NULL, "false", gb_view_stack_actions_split_down },
- { "split-left", gb_view_stack_actions_split_left },
- diff --git a/src/views/gb-view-stack-private.h b/src/views/gb-view-stack-private.h
- index 349642a..8fe84dc 100644
- --- a/src/views/gb-view-stack-private.h
- +++ b/src/views/gb-view-stack-private.h
- @@ -28,7 +28,6 @@ struct _GbViewStack
- {
- GtkBin parent_instance;
- - GList *focus_history;
- IdeBackForwardList *back_forward_list;
- /* Weak references */
- diff --git a/src/views/gb-view-stack.c b/src/views/gb-view-stack.c
- index 3452c3f..5830469 100644
- --- a/src/views/gb-view-stack.c
- +++ b/src/views/gb-view-stack.c
- @@ -17,6 +17,7 @@
- */
- #include <glib/gi18n.h>
- +#include <glib/gprintf.h>
- #include <ide.h>
- #include "gb-document.h"
- @@ -86,8 +87,8 @@ gb_view_stack_add_list_row (GbViewStack *self,
- NULL);
- g_object_bind_property (child, "modified", label, "visible", G_BINDING_SYNC_CREATE);
- gtk_container_add (GTK_CONTAINER (box), label);
- -
- - gtk_container_add (GTK_CONTAINER (self->views_listbox), row);
- + gtk_list_box_prepend (self->views_listbox, row);
- + gtk_list_box_select_row (self->views_listbox, GTK_LIST_BOX_ROW (row));
- }
- static void
- @@ -117,37 +118,6 @@ gb_view_stack_remove_list_row (GbViewStack *self,
- }
- static void
- -gb_view_stack_move_top_list_row (GbViewStack *self,
- - GbView *view)
- -{
- - GList *children;
- - GList *iter;
- -
- - g_assert (GB_IS_VIEW_STACK (self));
- - g_assert (GB_IS_VIEW (view));
- -
- - children = gtk_container_get_children (GTK_CONTAINER (self->views_listbox));
- -
- - for (iter = children; iter; iter = iter->next)
- - {
- - GtkWidget *row = iter->data;
- - GbView *item = g_object_get_data (G_OBJECT (row), "GB_VIEW");
- -
- - if (item == view)
- - {
- - g_object_ref (row);
- - gtk_container_remove (GTK_CONTAINER (self->views_listbox), row);
- - gtk_list_box_prepend (self->views_listbox, row);
- - gtk_list_box_select_row (self->views_listbox, GTK_LIST_BOX_ROW (row));
- - g_object_unref (row);
- - break;
- - }
- - }
- -
- - g_list_free (children);
- -}
- -
- -static void
- gb_view_stack_add (GtkContainer *container,
- GtkWidget *child)
- {
- @@ -163,7 +133,6 @@ gb_view_stack_add (GtkContainer *container,
- gtk_widget_set_sensitive (GTK_WIDGET (self->document_button), TRUE);
- gtk_widget_set_visible (GTK_WIDGET (self->views_button), TRUE);
- - self->focus_history = g_list_prepend (self->focus_history, child);
- controls = gb_view_get_controls (GB_VIEW (child));
- if (controls)
- gtk_container_add (GTK_CONTAINER (self->controls_stack), controls);
- @@ -182,19 +151,35 @@ void
- gb_view_stack_remove (GbViewStack *self,
- GbView *view)
- {
- + GbView *selected_view;
- GtkWidget *controls;
- GtkWidget *focus_after_close = NULL;
- + GtkListBoxRow *selected_row;
- + GtkListBoxRow *row;
- + gint selected_index;
- g_assert (GB_IS_VIEW_STACK (self));
- g_assert (GB_IS_VIEW (view));
- - focus_after_close = g_list_nth_data (self->focus_history, 1);
- - if (focus_after_close != NULL)
- - g_object_ref (focus_after_close);
- + selected_row = gtk_list_box_get_selected_row (self->views_listbox);
- + selected_view = GB_VIEW (g_object_get_data (G_OBJECT (selected_row), "GB_VIEW"));
- + if (selected_view == view)
- + {
- + selected_index = gtk_list_box_row_get_index (selected_row);
- + if (selected_index - 1 < 0)
- + row = gtk_list_box_get_row_at_index (self->views_listbox, selected_index + 1);
- + else
- + row = gtk_list_box_get_row_at_index (self->views_listbox, selected_index - 1);
- +
- + if (row != NULL)
- + {
- + focus_after_close = GTK_WIDGET (g_object_get_data (G_OBJECT (row), "GB_VIEW"));
- + g_object_ref (focus_after_close);
- + }
- + }
- gb_view_stack_remove_list_row (self, view);
- - self->focus_history = g_list_remove (self->focus_history, view);
- controls = gb_view_get_controls (view);
- if (controls)
- gtk_container_remove (GTK_CONTAINER (self->controls_stack), controls);
- @@ -204,6 +189,7 @@ gb_view_stack_remove (GbViewStack *self,
- {
- gtk_stack_set_visible_child (self->stack, focus_after_close);
- gtk_widget_grab_focus (GTK_WIDGET (focus_after_close));
- + gtk_list_box_select_row (self->views_listbox, GTK_LIST_BOX_ROW (row));
- g_clear_object (&focus_after_close);
- }
- else
- @@ -255,9 +241,16 @@ gb_view_stack_grab_focus (GtkWidget *widget)
- static gboolean
- gb_view_stack_is_empty (GbViewStack *self)
- {
- + GList *children;
- + gint len;
- +
- g_return_val_if_fail (GB_IS_VIEW_STACK (self), FALSE);
- - return (self->focus_history == NULL);
- + children = gtk_container_get_children (GTK_CONTAINER (self->views_listbox));
- + len = g_list_length (children);
- + g_list_free (children);
- +
- + return (len == 0);
- }
- static void
- @@ -392,8 +385,10 @@ gb_view_stack__views_listbox_row_activated_cb (GbViewStack *self,
- if (GB_IS_VIEW (view))
- {
- - gtk_widget_hide (GTK_WIDGET (self->views_popover));
- gb_view_stack_set_active_view (self, GTK_WIDGET (view));
- + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->views_button), FALSE);
- + /* FIX: why we need this now ? */
- + gtk_widget_hide (GTK_WIDGET (self->views_popover));
- gtk_widget_grab_focus (GTK_WIDGET (view));
- }
- }
- @@ -405,6 +400,7 @@ gb_view_stack_destroy (GtkWidget *widget)
- self->destroyed = TRUE;
- +
- GTK_WIDGET_CLASS (gb_view_stack_parent_class)->destroy (widget);
- }
- @@ -429,7 +425,6 @@ gb_view_stack_finalize (GObject *object)
- {
- GbViewStack *self = (GbViewStack *)object;
- - g_clear_pointer (&self->focus_history, g_list_free);
- ide_clear_weak_pointer (&self->context);
- ide_clear_weak_pointer (&self->title_binding);
- ide_clear_weak_pointer (&self->active_view);
- @@ -611,14 +606,13 @@ gb_view_stack_set_active_view (GbViewStack *self,
- GtkWidget *controls;
- GBinding *binding;
- GActionGroup *group;
- + GList *children;
- + GList *iter;
- ide_set_weak_pointer (&self->active_view, active_view);
- if (active_view != gtk_stack_get_visible_child (self->stack))
- gtk_stack_set_visible_child (self->stack, active_view);
- - self->focus_history = g_list_remove (self->focus_history, active_view);
- - self->focus_history = g_list_prepend (self->focus_history, active_view);
- -
- binding = g_object_bind_property (active_view, "title",
- self->title_label, "label",
- G_BINDING_SYNC_CREATE);
- @@ -640,7 +634,18 @@ gb_view_stack_set_active_view (GbViewStack *self,
- if (group)
- gtk_widget_insert_action_group (GTK_WIDGET (self), "view", group);
- - gb_view_stack_move_top_list_row (self, GB_VIEW (active_view));
- + children = gtk_container_get_children (GTK_CONTAINER (self->views_listbox));
- + for (iter = children; iter; iter = iter->next)
- + {
- + GtkWidget *view = g_object_get_data (iter->data, "GB_VIEW");
- + if (view == active_view)
- + {
- + gtk_list_box_select_row (self->views_listbox, GTK_LIST_BOX_ROW (iter->data));
- + break;
- + }
- + }
- +
- + g_list_free (children);
- }
- g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_ACTIVE_VIEW]);
- @@ -771,20 +776,24 @@ GbDocument *
- gb_view_stack_find_document_typed (GbViewStack *self,
- GType document_type)
- {
- + GList *children;
- GList *iter;
- g_return_val_if_fail (GB_IS_VIEW_STACK (self), NULL);
- g_return_val_if_fail (g_type_is_a (document_type, GB_TYPE_DOCUMENT), NULL);
- - for (iter = self->focus_history; iter; iter = iter->next)
- + children = gtk_container_get_children (GTK_CONTAINER (self->views_listbox));
- +
- + for (iter = children; iter; iter = iter->next)
- {
- - GbDocument *document;
- + GbView *view = g_object_get_data (iter->data, "GB_VIEW");
- + GbDocument *document = gb_view_get_document (view);
- - document = gb_view_get_document (iter->data);
- if (g_type_is_a (G_TYPE_FROM_INSTANCE (document), document_type))
- return document;
- }
- + g_list_free (children);
- return NULL;
- }
- diff --git a/tests/Makefile.am b/tests/Makefile.am
- index bdeff67..891c909 100644
- --- a/tests/Makefile.am
- +++ b/tests/Makefile.am
- @@ -132,6 +132,15 @@ test_vim_LDADD = \
- $(top_builddir)/src/libgnome-builder.la \
- $(NULL)
- +TESTS += test-ide-vim-parser
- +test_ide_vim_parser_SOURCES = test-ide-vim-parser.c
- +test_ide_vim_parser_CFLAGS = $(tests_cflags)
- +test_ide_vim_parser_LDADD = $(tests_libs)
- +
- +TESTS += test-ide-vim-parser-settable
- +test_ide_vim_parser_settable_SOURCES = test-ide-vim-parser-settable.c
- +test_ide_vim_parser_settable_CFLAGS = $(tests_cflags)
- +test_ide_vim_parser_settable_LDADD = $(tests_libs)
- misc_programs += test-ide-source-view
- test_ide_source_view_SOURCES = test-ide-source-view.c
- diff --git a/tests/test-ide-vim-parser-settable.c b/tests/test-ide-vim-parser-settable.c
- new file mode 100644
- index 0000000..5f249fc
- --- /dev/null
- +++ b/tests/test-ide-vim-parser-settable.c
- @@ -0,0 +1,280 @@
- +/* test-ide-vim-parser-settable.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <string.h>
- +
- +#include <glib/gprintf.h>
- +#include <gtk/gtk.h>
- +
- +#include <ide.h>
- +
- +static IdeVimParser *global_parser = NULL;
- +
- +static gboolean boolean_state = TRUE;
- +static gint integer_state = 1;
- +static gchar *string_state = NULL;
- +
- +static gboolean
- +boolean_func (IdeVimParserSettable *settable,
- + GValue *value,
- + IdeVimParserSettableOp op,
- + IdeVimParserError **error)
- +{
- + if (op == IDE_VIM_PARSER_SETTABLE_OP_SET || op == IDE_VIM_PARSER_SETTABLE_OP_RESET)
- + boolean_state = g_value_get_boolean (value);
- +
- + if (op == IDE_VIM_PARSER_SETTABLE_OP_GET)
- + g_value_set_boolean (value, boolean_state);
- +
- + return TRUE;
- +}
- +
- +static gboolean
- +integer_func (IdeVimParserSettable *settable,
- + GValue *value,
- + IdeVimParserSettableOp op,
- + IdeVimParserError **error)
- +{
- + if (op == IDE_VIM_PARSER_SETTABLE_OP_SET || op == IDE_VIM_PARSER_SETTABLE_OP_RESET)
- + integer_state = g_value_get_int64 (value);
- +
- + if (op == IDE_VIM_PARSER_SETTABLE_OP_GET)
- + g_value_set_int64 (value, integer_state);
- +
- + return TRUE;
- +}
- +
- +static gboolean
- +string_func (IdeVimParserSettable *settable,
- + GValue *value,
- + IdeVimParserSettableOp op,
- + IdeVimParserError **error)
- +{
- + if (op == IDE_VIM_PARSER_SETTABLE_OP_SET || op == IDE_VIM_PARSER_SETTABLE_OP_RESET)
- + {
- + g_clear_pointer (&string_state, g_free);
- + string_state = g_strdup (g_value_get_string (value));
- + }
- +
- + if (op == IDE_VIM_PARSER_SETTABLE_OP_GET)
- + g_value_set_string (value, string_state);
- +
- + return TRUE;
- +}
- +
- +static void
- +test_boolean_settable (void)
- +{
- + IdeVimParserSettable *settable;
- + GValue g_value = G_VALUE_INIT;
- + IdeVimParserError *error = NULL;
- + const gchar *name;
- + const gchar *shortname;
- + const gchar *help;
- +
- + name = g_strdup ("name");
- + shortname = g_strdup ("shortname");
- + help = g_strdup ("help");
- +
- + g_value_init (&g_value, G_TYPE_BOOLEAN);
- + g_value_set_boolean (&g_value, FALSE);
- +
- + settable = ide_vim_parser_settable_boolean_new (name, shortname, help, TRUE, TRUE, boolean_func, NULL);
- + g_assert (!g_strcmp0 (name, ide_vim_parser_settable_get_name (settable)));
- + g_assert (!g_strcmp0 (shortname, ide_vim_parser_settable_get_shortname (settable)));
- + g_assert (!g_strcmp0 (help, ide_vim_parser_settable_get_help (settable)));
- + g_assert (g_value_get_boolean (ide_vim_parser_settable_get_default_value (settable)) == TRUE);
- +
- + g_assert (g_value_get_boolean (ide_vim_parser_settable_get_value (settable)) == TRUE);
- + g_assert (ide_vim_parser_settable_set_value (settable, &g_value, &error));
- + g_assert (error == NULL);
- + g_assert (g_value_get_boolean (ide_vim_parser_settable_get_value (settable)) == FALSE);
- + ide_vim_parser_settable_reset_value (settable);
- + g_assert (g_value_get_boolean (ide_vim_parser_settable_get_value (settable)) == TRUE);
- +}
- +
- +static void
- +test_integer_settable (void)
- +{
- + IdeVimParserSettable *settable;
- + GValue g_value = G_VALUE_INIT;
- + IdeVimParserError *error = NULL;
- + const gchar *name;
- + const gchar *shortname;
- + const gchar *help;
- +
- + name = g_strdup ("name");
- + shortname = g_strdup ("shortname");
- + help = g_strdup ("help");
- +
- + g_value_init (&g_value, G_TYPE_INT64);
- + g_value_set_int64 (&g_value, 15);
- +
- + settable = ide_vim_parser_settable_integer_new (name, shortname, help, 5, 10, 0, 20, integer_func, NULL);
- + g_assert (!g_strcmp0 (name, ide_vim_parser_settable_get_name (settable)));
- + g_assert (!g_strcmp0 (shortname, ide_vim_parser_settable_get_shortname (settable)));
- + g_assert (!g_strcmp0 (help, ide_vim_parser_settable_get_help (settable)));
- + g_assert (g_value_get_int64 (ide_vim_parser_settable_get_default_value (settable)) == 10);
- +
- + g_assert (g_value_get_int64 (ide_vim_parser_settable_get_value (settable)) == 5);
- + g_assert (ide_vim_parser_settable_set_value (settable, &g_value, &error));
- + g_assert (error == NULL);
- + g_assert (g_value_get_int64 (ide_vim_parser_settable_get_value (settable)) == 15);
- + ide_vim_parser_settable_reset_value (settable);
- + g_assert (g_value_get_int64 (ide_vim_parser_settable_get_value (settable)) == 10);
- +
- + g_value_set_int64 (&g_value, 30);
- + g_assert (!ide_vim_parser_settable_set_value (settable, &g_value, &error));
- + g_assert (error != NULL);
- +}
- +
- +static void
- +test_string_settable (void)
- +{
- + IdeVimParserSettable *settable;
- + GValue g_value = G_VALUE_INIT;
- + IdeVimParserError *error = NULL;
- + const gchar *name;
- + const gchar *shortname;
- + const gchar *help;
- +
- + name = g_strdup ("name");
- + shortname = g_strdup ("shortname");
- + help = g_strdup ("help");
- +
- + g_value_init (&g_value, G_TYPE_STRING);
- + g_value_set_string (&g_value, "value 1");
- +
- + settable = ide_vim_parser_settable_string_new (name, shortname, help, "initial value", "default value", string_func, NULL);
- + g_assert (!g_strcmp0 (name, ide_vim_parser_settable_get_name (settable)));
- + g_assert (!g_strcmp0 (shortname, ide_vim_parser_settable_get_shortname (settable)));
- + g_assert (!g_strcmp0 (help, ide_vim_parser_settable_get_help (settable)));
- + g_assert (!g_strcmp0 (g_value_get_string (ide_vim_parser_settable_get_default_value (settable)), "default value"));
- +
- + g_assert (!g_strcmp0 (g_value_get_string (ide_vim_parser_settable_get_value (settable)), "initial value"));
- + g_assert (ide_vim_parser_settable_set_value (settable, &g_value, &error));
- + g_assert (error == NULL);
- + g_assert (!g_strcmp0 (g_value_get_string (ide_vim_parser_settable_get_value (settable)), "value 1"));
- + ide_vim_parser_settable_reset_value (settable);
- + g_assert (!g_strcmp0 (g_value_get_string (ide_vim_parser_settable_get_value (settable)), "default value"));
- +}
- +
- +static void
- +test_objects_pool (void)
- +{
- + IdeVimParserSettable *boolean_settable;
- + IdeVimParserSettable *string_settable;
- + IdeVimParserSettable *integer_settable;
- + IdeVimParserObjectsPool *pool = ide_vim_parser_objects_pool_new ();
- +
- + boolean_settable = ide_vim_parser_settable_boolean_new ("auto-indent", "ai", "auto indent parameter",
- + TRUE, FALSE, boolean_func, NULL);
- + g_assert (boolean_settable != NULL);
- + g_assert (ide_vim_parser_objects_pool_add_settable (pool, boolean_settable, TRUE));
- +
- + string_settable = ide_vim_parser_settable_string_new ("filetype", "ft", "language file type",
- + "c", "none", string_func, NULL);
- + g_assert (string_settable != NULL);
- + g_assert (ide_vim_parser_objects_pool_add_settable (pool, string_settable, TRUE));
- +
- + integer_settable = ide_vim_parser_settable_integer_new ("scrolloff", "so", "scroll offset",
- + 50, 0, 0, 1000, integer_func, NULL);
- + g_assert (integer_settable != NULL);
- + g_assert (ide_vim_parser_objects_pool_add_settable (pool, integer_settable, TRUE));
- +
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "ai") == boolean_settable);
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "auto-indent") == boolean_settable);
- +
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "filetype") == string_settable);
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "ft") == string_settable);
- +
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "scrolloff") == integer_settable);
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "so") == integer_settable);
- +
- + g_assert (ide_vim_parser_objects_pool_remove_settable (pool, "ai"));
- + g_assert (!ide_vim_parser_objects_pool_remove_settable (pool, "auto-indent"));
- +
- + g_assert (ide_vim_parser_objects_pool_remove_settable (pool, "filetype"));
- + g_assert (!ide_vim_parser_objects_pool_remove_settable (pool, "ft"));
- +
- + g_assert (ide_vim_parser_objects_pool_remove_settable (pool, "scrolloff"));
- + g_assert (!ide_vim_parser_objects_pool_remove_settable (pool, "so"));
- +
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "auto-indent") == NULL);
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "ai") == NULL);
- +
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "ft") == NULL);
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "filetype") == NULL);
- +
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "so") == NULL);
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "scrolloff") == NULL);
- +
- + g_object_unref (pool);
- +}
- +
- +static void
- +test_objects_pool2 (void)
- +{
- + IdeVimParserSettable *boolean1_settable;
- + IdeVimParserSettable *boolean2_settable;
- + IdeVimParserObjectsPool *pool = ide_vim_parser_objects_pool_new ();
- +
- + boolean1_settable = ide_vim_parser_settable_boolean_new ("auto-indent", "ai", "auto indent parameter",
- + TRUE, FALSE, boolean_func, NULL);
- +
- + boolean2_settable = ide_vim_parser_settable_boolean_new ("auto-indent", "xx", "auto indent parameter",
- + TRUE, FALSE, boolean_func, NULL);
- +
- + ide_vim_parser_objects_pool_add_settable (pool, boolean1_settable, TRUE);
- + g_assert (ide_vim_parser_objects_pool_add_settable (pool, boolean2_settable, TRUE));
- +
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "ai") == NULL);
- + g_assert (ide_vim_parser_objects_pool_lookup_settable (pool, "xx") == boolean2_settable);
- +
- + g_assert (!ide_vim_parser_objects_pool_add_settable (pool, boolean1_settable, FALSE));
- +
- + g_object_unref (pool);
- +}
- +
- +static void
- +test_parse_set (void)
- +{
- + global_parser = ide_vim_parser_new ();
- +
- + ide_vim_parser_parse_settable (global_parser, " ai filetype=html scrolloff:10 ", NULL);
- +
- + g_object_unref (global_parser);
- +}
- +
- +gint
- +main (gint argc, gchar *argv[])
- +{
- + gtk_init (&argc, &argv);
- + g_test_init (&argc, &argv, NULL);
- +
- + g_test_add_func ("/Ide/VimParser/settable", test_boolean_settable);
- + g_test_add_func ("/Ide/VimParser/settable", test_integer_settable);
- + g_test_add_func ("/Ide/VimParser/settable", test_string_settable);
- +
- + g_test_add_func ("/Ide/VimParser/objects-pool", test_objects_pool);
- + g_test_add_func ("/Ide/VimParser/objects-pool2", test_objects_pool2);
- +
- + g_test_add_func ("/Ide/VimParser/parse-set", test_parse_set);
- +
- + return g_test_run ();
- +}
- diff --git a/tests/test-ide-vim-parser.c b/tests/test-ide-vim-parser.c
- new file mode 100644
- index 0000000..e1b0fec
- --- /dev/null
- +++ b/tests/test-ide-vim-parser.c
- @@ -0,0 +1,283 @@
- +/* test-ide-vim-parser.c
- + *
- + * Copyright (C) 2015 Sébastien Lafargue <slafargue@gnome.org>
- + *
- + * 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 3 of the License, or
- + * (at your option) any later version.
- + *
- + * This program 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 General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <string.h>
- +
- +#include <glib/gprintf.h>
- +#include <gtk/gtk.h>
- +
- +#include <ide.h>
- +
- +static IdeVimParser *global_parser = NULL;
- +static GtkTextBuffer *global_buffer = NULL;
- +
- +typedef struct
- +{
- + const gchar *comment;
- + const gchar *line;
- + IdeVimParserErrorCode error_code;
- +} ParseTest;
- +
- +typedef struct
- +{
- + IdeVimCompleteItemKind kind;
- + const gchar *name;
- + const gchar *shortname;
- +} CompleteResult;
- +
- +static gboolean
- +test_cmd_a_func (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- +{
- + return TRUE;
- +}
- +
- +static gboolean
- +test_generic_func (GtkSourceView *source_view,
- + IdeVimParser *parser,
- + IdeVimParserCommand *command,
- + IdeVimParserError **error)
- +{
- + return TRUE;
- +}
- +
- +static void
- +context_test_complete_create (void)
- +{
- + global_buffer = gtk_text_buffer_new (NULL);
- + global_parser = ide_vim_parser_new ();
- +
- + g_assert_true (ide_vim_parser_add_command (global_parser, "test_comp_a", "test_comp", test_generic_func,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL));
- +
- + g_assert_true (ide_vim_parser_add_command (global_parser, "test_comp_b", "test_co", test_generic_func,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL));
- +
- +}
- +
- +static void
- +context_create (void)
- +{
- + global_buffer = gtk_text_buffer_new (NULL);
- + global_parser = ide_vim_parser_new ();
- +
- + g_assert_true (ide_vim_parser_add_command (global_parser, "test_cmd_a", "test_cm", test_cmd_a_func,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL));
- +
- + g_assert_true (ide_vim_parser_add_command (global_parser, "test_cmd_b", "test_cmd", test_generic_func,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL));
- +
- + g_assert_true (ide_vim_parser_add_command (global_parser, "test_cmd_c", "", test_generic_func,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL));
- +
- + g_assert_true (ide_vim_parser_add_command (global_parser, "test_cmd_d", "", test_generic_func,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL));
- +
- + g_assert_true (ide_vim_parser_add_command (global_parser, "test_cmd_e", "", test_generic_func,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_NUMBER, IDE_VIM_PARSER_TOKEN_FLAG_OPTIONNAL,
- + NULL));
- +
- + g_assert_true (ide_vim_parser_add_command (global_parser, "test_cmd_f", "", test_generic_func,
- + IDE_VIM_PARSER_TOKEN_MARK, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL));
- +
- + g_assert_true (ide_vim_parser_add_command (global_parser, "test_cmd_g", "", test_generic_func,
- + IDE_VIM_PARSER_TOKEN_REGISTER, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL));
- +
- + g_assert_true (ide_vim_parser_add_command (global_parser, "test_cmd_h", "", test_generic_func,
- + IDE_VIM_PARSER_TOKEN_RANGE, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + IDE_VIM_PARSER_TOKEN_COMMAND_NAME, IDE_VIM_PARSER_TOKEN_FLAG_NONE,
- + NULL));
- +}
- +
- +static void
- +context_destroy (void)
- +{
- + g_object_unref (global_parser);
- + g_object_unref (global_buffer);
- +}
- +
- +static gint
- +sort_complete_item (IdeVimCompleteItem **i1,
- + IdeVimCompleteItem **i2)
- +{
- + return strcmp (ide_vim_complete_item_get_name (*i1),
- + ide_vim_complete_item_get_name (*i2));
- +}
- +
- +static gboolean
- +compare_complete_result (GPtrArray *array,
- + const CompleteResult result_list [],
- + gint size)
- +{
- + const CompleteResult *result;
- + IdeVimCompleteItem *item;
- + IdeVimCompleteItemKind kind;
- + const gchar *name;
- + const gchar *shortname;
- + gint len;
- + gboolean ret = TRUE;
- + gint i;
- +
- + g_ptr_array_sort (array, (GCompareFunc)sort_complete_item);
- + len =array->len;
- + if (len != size)
- + {
- + ret = FALSE;
- + goto out;
- + }
- +
- + for (i=0; i < len; i++)
- + {
- + item = g_ptr_array_index (array, i);
- + kind = ide_vim_complete_item_get_kind (item);
- + name = ide_vim_complete_item_get_name (item);
- + shortname = ide_vim_complete_item_get_shortname (item);
- +
- + result = &result_list [i];
- + printf ("\tcomplete: kind:%i, name:%s, shortname:%s\t", kind, name, shortname);
- +
- + ret = ret && (kind == result->kind && ide_str_equal0 (name, result->name) && ide_str_equal0 (shortname, result->shortname));
- + printf ("%s\n", ret ? "OK" : "NOK");
- + }
- +
- +out:
- + return ret;
- +}
- +
- +static void
- +test_complete (void)
- +{
- + static const CompleteResult comp_list1 [] = {
- + { IDE_VIM_COMPLETE_ITEM_KIND_COMMAND, "test_comp_a", "test_comp"},
- + { IDE_VIM_COMPLETE_ITEM_KIND_COMMAND, "test_comp_b", "test_co"}
- + };
- +
- + GPtrArray *result;
- +
- + context_test_complete_create ();
- +
- + g_assert ((result = ide_vim_parser_complete (global_parser, global_buffer, "test_c")) != NULL);
- + g_assert (compare_complete_result (result, comp_list1, G_N_ELEMENTS (comp_list1)) == TRUE);
- +
- + context_destroy ();
- +}
- +
- +static void
- +test_parse (void)
- +{
- + static const ParseTest parse_samples[] = {
- + /* Command syntax tests */
- + { "full syntax a1 spaces", " 2 test_cmd_a 4 ", IDE_VIM_PARSER_ERROR_NONE},
- + { "full syntax a2 tabs ", "-4,2\ttest_cmd_a\t 4", IDE_VIM_PARSER_ERROR_NONE},
- + { "minimum syntax a", "test_cmd_a", IDE_VIM_PARSER_ERROR_NONE},
- + /* Sign tests */
- + { "partial syntax a1, sign", "-4 test_cmd_a", IDE_VIM_PARSER_ERROR_NONE},
- + { "partial syntax a2, sign", "+4 test_cmd_a", IDE_VIM_PARSER_ERROR_NONE},
- + /* number or range tests */
- + { "partial syntax a3, range or number", "-4,2 test_cmd_a", IDE_VIM_PARSER_ERROR_NONE},
- + { "partial syntax a4, range or number", ".,$ test_cmd_a", IDE_VIM_PARSER_ERROR_NONE},
- + /* Command syntax tests */
- + { "partial syntax a7", "test_cmd_a 4", IDE_VIM_PARSER_ERROR_NONE},
- + { "full syntax b1", "test_cmd_b", IDE_VIM_PARSER_ERROR_NONE},
- + { "full syntax c1", "2 test_cmd_c 4", IDE_VIM_PARSER_ERROR_NONE},
- + { "full syntax d1", "2 test_cmd_d 4", IDE_VIM_PARSER_ERROR_NONE},
- + { "partial syntax d1", "test_cmd_d 4", IDE_VIM_PARSER_ERROR_NONE},
- + { "full syntax e1", "2 test_cmd_e 4", IDE_VIM_PARSER_ERROR_NONE},
- + { "partial syntax e1", "2 test_cmd_e", IDE_VIM_PARSER_ERROR_NONE},
- + /* Mark tests */
- + { "mark f1", "'a test_cmd_f", IDE_VIM_PARSER_ERROR_NONE},
- + { "mark f2", "'^ test_cmd_f", IDE_VIM_PARSER_ERROR_NONE},
- + /* Registers tests */
- + { "register g1", "\"a test_cmd_g", IDE_VIM_PARSER_ERROR_NONE},
- + { "register g2", "\"- test_cmd_g", IDE_VIM_PARSER_ERROR_NONE},
- + /* Range test */
- + { "full syntax h1, range", "%test_cmd_h", IDE_VIM_PARSER_ERROR_NONE},
- + { "full syntax h2, range", "\\/,\\&,\\? test_cmd_h", IDE_VIM_PARSER_ERROR_NONE},
- + /* Errors test */
- + { "cmdline empty", "", IDE_VIM_PARSER_ERROR_CMDLINE_EMPTY},
- + //{ "command not found", "xx", IDE_VIM_PARSER_ERROR_COMMAND_NOT_FOUND}
- +
- + };
- +
- + IdeVimParserError *parse_error = NULL;
- + ParseTest sample;
- + /* TODO: set autofree func in IdeVimParserCommand */
- + IdeVimParserCommand *result = NULL;
- + gint i;
- +
- + context_create ();
- + g_printf ("\n");
- +
- + for (i = 0; i < G_N_ELEMENTS (parse_samples); i++)
- + {
- + sample = parse_samples [i];
- + g_printf ("TEST: %s: %s\n", sample.comment, sample.line);
- +
- + result = ide_vim_parser_parse (global_parser, global_buffer, sample.line, &parse_error);
- + g_assert ((result == NULL && parse_error != NULL) || (result != NULL && parse_error == NULL));
- + if (parse_error != NULL)
- + {
- + ide_vim_parser_error_print (parse_error);
- + g_assert (sample.error_code == parse_error->code);
- + ide_vim_parser_error_free (parse_error);
- + g_printf ("\n");
- + }
- + else
- + {
- + g_assert (sample.error_code == IDE_VIM_PARSER_ERROR_NONE);
- + ide_vim_parser_debug_show_parsed (result);
- + }
- +
- + g_printf ("\n");
- + }
- +
- + context_destroy ();
- +}
- +
- +gint
- +main (gint argc,
- + gchar *argv[])
- +{
- + gtk_init (&argc, &argv);
- + g_test_init (&argc, &argv, NULL);
- +
- + g_test_add_func ("/Ide/VimParser/complete", test_complete);
- + g_test_add_func ("/Ide/VimParser/parse", test_parse);
- +
- + return g_test_run ();
- +}
- --
- 2.4.3
Add Comment
Please, Sign In to add comment