[gnome-text-editor] spellcheck: extract iteration into cursor helper
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-text-editor] spellcheck: extract iteration into cursor helper
- Date: Mon, 28 Jun 2021 21:05:57 +0000 (UTC)
commit a7ca6fc666d36fbf19dc011967b1a9e0f5ae25c3
Author: Christian Hergert <chergert redhat com>
Date: Mon Jun 28 14:05:52 2021 -0700
spellcheck: extract iteration into cursor helper
src/editor-spell-cursor.c | 135 +++++++++++++++++++++++++++++++++
src/editor-spell-cursor.h | 47 ++++++++++++
src/editor-text-buffer-spell-adapter.c | 63 +++------------
src/meson.build | 1 +
4 files changed, 192 insertions(+), 54 deletions(-)
---
diff --git a/src/editor-spell-cursor.c b/src/editor-spell-cursor.c
new file mode 100644
index 0000000..e536cfc
--- /dev/null
+++ b/src/editor-spell-cursor.c
@@ -0,0 +1,135 @@
+/* editor-spell-cursor.c
+ *
+ * Copyright 2021 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "config.h"
+
+#include "editor-spell-cursor.h"
+
+static char *
+editor_spell_cursor_word (EditorSpellCursor *cursor)
+{
+ g_assert (cursor != NULL);
+ g_assert (!cursor->exhausted);
+
+ return gtk_text_iter_get_slice (&cursor->word_begin, &cursor->word_end);
+}
+
+void
+editor_spell_cursor_init (EditorSpellCursor *cursor,
+ const GtkTextIter *begin,
+ const GtkTextIter *end,
+ GtkTextTag *misspelled_tag)
+{
+ g_return_if_fail (cursor != NULL);
+ g_return_if_fail (begin != NULL);
+ g_return_if_fail (end != NULL);
+ g_return_if_fail (gtk_text_iter_get_buffer (begin) == gtk_text_iter_get_buffer (end));
+
+ cursor->buffer = gtk_text_iter_get_buffer (begin);
+ cursor->misspelled_tag = misspelled_tag;
+ cursor->begin = *begin;
+ cursor->end = *end;
+ gtk_text_iter_order (&cursor->begin, &cursor->end);
+ cursor->word_begin = cursor->begin;
+ cursor->word_end = cursor->begin;
+ cursor->exhausted = FALSE;
+}
+
+char *
+editor_spell_cursor_next_word (EditorSpellCursor *cursor)
+{
+ g_return_val_if_fail (cursor != NULL, NULL);
+
+ if (cursor->exhausted)
+ return NULL;
+
+ /* If this is the initial movement, then we need to handle the
+ * case where the first word overlaps the boundary.
+ */
+ if (gtk_text_iter_equal (&cursor->word_begin, &cursor->word_end))
+ {
+ if (!gtk_text_iter_starts_word (&cursor->word_begin))
+ {
+ if (gtk_text_iter_backward_word_start (&cursor->word_begin))
+ {
+ cursor->word_end = cursor->word_begin;
+ gtk_text_iter_forward_word_end (&cursor->word_end);
+ }
+ else
+ {
+ if (!gtk_text_iter_forward_word_end (&cursor->word_end))
+ goto exhausted;
+
+ cursor->word_begin = cursor->word_end;
+ gtk_text_iter_backward_word_start (&cursor->word_begin);
+ }
+ }
+
+ /* If the word position overlaps the region, then we can return it.
+ * Otherwise we need to try to move forward (the regular flow).
+ */
+ if (gtk_text_iter_compare (&cursor->word_end, &cursor->begin) > 0)
+ return editor_spell_cursor_word (cursor);
+ }
+
+ if (!gtk_text_iter_forward_word_end (&cursor->word_end))
+ goto exhausted;
+
+ cursor->word_begin = cursor->word_end;
+ gtk_text_iter_backward_word_start (&cursor->word_begin);
+
+ if (gtk_text_iter_compare (&cursor->word_begin, &cursor->end) <= 0)
+ return editor_spell_cursor_word (cursor);
+
+exhausted:
+ cursor->exhausted = TRUE;
+
+ return NULL;
+}
+
+void
+editor_spell_cursor_tag (EditorSpellCursor *cursor)
+{
+ g_return_if_fail (cursor != NULL);
+
+ gtk_text_buffer_apply_tag (cursor->buffer,
+ cursor->misspelled_tag,
+ &cursor->word_begin,
+ &cursor->word_end);
+}
+
+gboolean
+editor_spell_cursor_contains_tag (EditorSpellCursor *cursor,
+ GtkTextTag *tag)
+{
+ GtkTextIter toggle_iter;
+
+ if (tag == NULL || cursor->exhausted)
+ return FALSE;
+
+ if (gtk_text_iter_has_tag (&cursor->word_begin, tag))
+ return TRUE;
+
+ toggle_iter = cursor->word_begin;
+ if (!gtk_text_iter_forward_to_tag_toggle (&toggle_iter, tag))
+ return FALSE;
+
+ return gtk_text_iter_compare (&cursor->word_end, &toggle_iter) > 0;
+}
diff --git a/src/editor-spell-cursor.h b/src/editor-spell-cursor.h
new file mode 100644
index 0000000..230fc13
--- /dev/null
+++ b/src/editor-spell-cursor.h
@@ -0,0 +1,47 @@
+/* editor-spell-cursor.h
+ *
+ * Copyright 2021 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+ GtkTextBuffer *buffer;
+ GtkTextTag *misspelled_tag;
+ GtkTextIter begin;
+ GtkTextIter end;
+ GtkTextIter word_begin;
+ GtkTextIter word_end;
+ guint exhausted : 1;
+} EditorSpellCursor;
+
+void editor_spell_cursor_init (EditorSpellCursor *cursor,
+ const GtkTextIter *begin,
+ const GtkTextIter *end,
+ GtkTextTag *misspelled_tag);
+char *editor_spell_cursor_next_word (EditorSpellCursor *cursor);
+void editor_spell_cursor_tag (EditorSpellCursor *cursor);
+gboolean editor_spell_cursor_contains_tag (EditorSpellCursor *cursor,
+ GtkTextTag *tag);
+
+G_END_DECLS
diff --git a/src/editor-text-buffer-spell-adapter.c b/src/editor-text-buffer-spell-adapter.c
index 77b9b87..05b5d54 100644
--- a/src/editor-text-buffer-spell-adapter.c
+++ b/src/editor-text-buffer-spell-adapter.c
@@ -23,6 +23,7 @@
#include "cjhtextregionprivate.h"
#include "editor-spell-checker.h"
+#include "editor-spell-cursor.h"
#include "editor-text-buffer-spell-adapter.h"
#define UNCHECKED GSIZE_TO_POINTER(0)
@@ -111,34 +112,16 @@ scan_for_next_unchecked (CjhTextRegion *region,
return state.found;
}
-static inline gboolean
-word_contains_no_spell_context (EditorTextBufferSpellAdapter *self,
- const GtkTextIter *begin,
- const GtkTextIter *end)
-{
- GtkTextIter toggle_iter;
-
- if (self->no_spell_check_tag == NULL)
- return FALSE;
-
- if (gtk_text_iter_has_tag (begin, self->no_spell_check_tag))
- return TRUE;
-
- toggle_iter = *begin;
- if (!gtk_text_iter_forward_to_tag_toggle (&toggle_iter, self->no_spell_check_tag))
- return FALSE;
-
- return gtk_text_iter_compare (end, &toggle_iter) > 0;
-}
-
static gboolean
editor_text_buffer_spell_adapter_update_range (EditorTextBufferSpellAdapter *self,
gsize begin_offset,
gsize end_offset,
gint64 deadline)
{
- GtkTextIter iter, begin, end;
+ EditorSpellCursor cursor;
+ GtkTextIter begin, end;
gsize position;
+ char *word;
g_assert (EDITOR_IS_TEXT_BUFFER_SPELL_ADAPTER (self));
@@ -150,46 +133,18 @@ editor_text_buffer_spell_adapter_update_range (EditorTextBufferSpellAdapter *sel
gtk_text_buffer_get_iter_at_offset (self->buffer, &begin, position);
gtk_text_buffer_get_iter_at_offset (self->buffer, &end, end_offset);
- iter = begin;
-
gtk_text_buffer_remove_tag (self->buffer, self->tag, &begin, &end);
- if (!gtk_text_iter_starts_word (&iter))
+ editor_spell_cursor_init (&cursor, &begin, &end, self->tag);
+ while ((word = editor_spell_cursor_next_word (&cursor)))
{
- if (gtk_text_iter_is_start (&iter))
- gtk_text_iter_forward_word_end (&iter);
- gtk_text_iter_backward_word_start (&iter);
- }
-
- while (gtk_text_iter_compare (&iter, &end) < 0)
- {
- GtkTextIter word_end = iter;
- char *word;
-
- if (!gtk_text_iter_forward_word_end (&word_end))
- break;
-
- /* Skip until we are out of the no-spell-check region if necessary */
- if (word_contains_no_spell_context (self, &iter, &word_end))
+ if (!editor_spell_cursor_contains_tag (&cursor, self->no_spell_check_tag))
{
- if (!gtk_text_iter_ends_tag (&word_end, self->no_spell_check_tag))
- gtk_text_iter_forward_to_tag_toggle (&word_end, self->no_spell_check_tag);
- goto move_next_word;
+ if (!editor_spell_checker_check_word (self->checker, word, -1))
+ editor_spell_cursor_tag (&cursor);
}
- word = gtk_text_iter_get_slice (&iter, &word_end);
- if (!editor_spell_checker_check_word (self->checker, word, -1))
- gtk_text_buffer_apply_tag (self->buffer, self->tag, &iter, &word_end);
g_free (word);
-
- move_next_word:
- if (!gtk_text_iter_forward_word_end (&word_end))
- break;
-
- iter = word_end;
-
- if (!gtk_text_iter_backward_word_start (&iter))
- break;
}
_cjh_text_region_replace (self->region, begin_offset, end_offset - begin_offset, CHECKED);
diff --git a/src/meson.build b/src/meson.build
index 96431d4..cc438dc 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -33,6 +33,7 @@ editor_sources = [
'editor-sidebar-row.c',
'editor-signal-group.c',
'editor-spell-checker.c',
+ 'editor-spell-cursor.c',
'editor-spell-language.c',
'editor-spell-menu.c',
'editor-spell-provider.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]