|
Packit |
a7d494 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
|
|
Packit |
a7d494 |
/* gtksourceiter.c
|
|
Packit |
a7d494 |
* This file is part of GtkSourceView
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* Copyright (C) 2014, 2016 - Sébastien Wilmet <swilmet@gnome.org>
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* GtkSourceView is free software; you can redistribute it and/or
|
|
Packit |
a7d494 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
a7d494 |
* License as published by the Free Software Foundation; either
|
|
Packit |
a7d494 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* GtkSourceView is distributed in the hope that it will be useful,
|
|
Packit |
a7d494 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a7d494 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
a7d494 |
* Lesser General Public License for more details.
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
a7d494 |
* License along with this library; if not, write to the Free Software
|
|
Packit |
a7d494 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
#include "gtksourceiter.h"
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* GtkTextIter functions. Contains forward/backward functions for word
|
|
Packit |
a7d494 |
* movements, with custom word boundaries that are used for word selection
|
|
Packit |
a7d494 |
* (double-click) and cursor movements (Ctrl+left, Ctrl+right, etc). The
|
|
Packit |
a7d494 |
* initial idea was to use those word boundaries directly in GTK+, for all text
|
|
Packit |
a7d494 |
* widgets. But in the end only the GtkTextView::extend-selection signal has
|
|
Packit |
a7d494 |
* been added to be able to customize the boundaries for double- and
|
|
Packit |
a7d494 |
* triple-click (the ::move-cursor and ::delete-from-cursor signals were already
|
|
Packit |
a7d494 |
* present to customize boundaries for cursor movements). The GTK+ developers
|
|
Packit |
a7d494 |
* didn't want to change the word boundaries for text widgets. More information:
|
|
Packit |
a7d494 |
* https://mail.gnome.org/archives/gtk-devel-list/2014-September/msg00019.html
|
|
Packit |
a7d494 |
* https://bugzilla.gnome.org/show_bug.cgi?id=111503
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Go to the end of the next or current "full word". A full word is a group of
|
|
Packit |
a7d494 |
* non-blank chars.
|
|
Packit |
a7d494 |
* In other words, this function is the same as the 'E' Vim command.
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* Examples ('|' is the iter position):
|
|
Packit |
a7d494 |
* "|---- abcd" -> "----| abcd"
|
|
Packit |
a7d494 |
* "| ---- abcd" -> " ----| abcd"
|
|
Packit |
a7d494 |
* "--|-- abcd" -> "----| abcd"
|
|
Packit |
a7d494 |
* "---- a|bcd" -> "---- abcd|"
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
void
|
|
Packit |
a7d494 |
_gtk_source_iter_forward_full_word_end (GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter pos;
|
|
Packit |
a7d494 |
gboolean non_blank_found = FALSE;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* It would be better to use gtk_text_iter_forward_visible_char(), but
|
|
Packit |
a7d494 |
* it doesn't exist. So move by cursor position instead, it should be
|
|
Packit |
a7d494 |
* equivalent here.
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
pos = *iter;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
while (g_unichar_isspace (gtk_text_iter_get_char (&pos)))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
gtk_text_iter_forward_visible_cursor_position (&pos;;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
while (!gtk_text_iter_is_end (&pos) &&
|
|
Packit |
a7d494 |
!g_unichar_isspace (gtk_text_iter_get_char (&pos)))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
non_blank_found = TRUE;
|
|
Packit |
a7d494 |
gtk_text_iter_forward_visible_cursor_position (&pos;;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (non_blank_found)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = pos;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Symmetric of iter_forward_full_word_end(). */
|
|
Packit |
a7d494 |
void
|
|
Packit |
a7d494 |
_gtk_source_iter_backward_full_word_start (GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter pos;
|
|
Packit |
a7d494 |
GtkTextIter prev;
|
|
Packit |
a7d494 |
gboolean non_blank_found = FALSE;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
pos = *iter;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
while (!gtk_text_iter_is_start (&pos))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
prev = pos;
|
|
Packit |
a7d494 |
gtk_text_iter_backward_visible_cursor_position (&prev;;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (!g_unichar_isspace (gtk_text_iter_get_char (&prev)))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
break;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
pos = prev;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
while (!gtk_text_iter_is_start (&pos))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
prev = pos;
|
|
Packit |
a7d494 |
gtk_text_iter_backward_visible_cursor_position (&prev;;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (g_unichar_isspace (gtk_text_iter_get_char (&prev)))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
break;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
non_blank_found = TRUE;
|
|
Packit |
a7d494 |
pos = prev;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (non_blank_found)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = pos;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_starts_full_word (const GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter prev = *iter;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (gtk_text_iter_is_end (iter))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return FALSE;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (!gtk_text_iter_backward_visible_cursor_position (&prev))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return !g_unichar_isspace (gtk_text_iter_get_char (iter));
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
return (g_unichar_isspace (gtk_text_iter_get_char (&prev)) &&
|
|
Packit |
a7d494 |
!g_unichar_isspace (gtk_text_iter_get_char (iter)));
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_ends_full_word (const GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter prev = *iter;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (!gtk_text_iter_backward_visible_cursor_position (&prev))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return FALSE;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
return (!g_unichar_isspace (gtk_text_iter_get_char (&prev)) &&
|
|
Packit |
a7d494 |
(gtk_text_iter_is_end (iter) ||
|
|
Packit |
a7d494 |
g_unichar_isspace (gtk_text_iter_get_char (iter))));
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Extends the definition of a natural-language word used by Pango. The
|
|
Packit |
a7d494 |
* underscore is added to the possible characters of a natural-language word.
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
void
|
|
Packit |
a7d494 |
_gtk_source_iter_forward_extra_natural_word_end (GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter next_word_end = *iter;
|
|
Packit |
a7d494 |
GtkTextIter next_underscore_end = *iter;
|
|
Packit |
a7d494 |
GtkTextIter *limit = NULL;
|
|
Packit |
a7d494 |
gboolean found;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (gtk_text_iter_forward_visible_word_end (&next_word_end))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
limit = &next_word_end;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
found = gtk_text_iter_forward_search (iter,
|
|
Packit |
a7d494 |
"_",
|
|
Packit |
a7d494 |
GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY,
|
|
Packit |
a7d494 |
NULL,
|
|
Packit |
a7d494 |
&next_underscore_end,
|
|
Packit |
a7d494 |
limit);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (found)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = next_underscore_end;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
else
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = next_word_end;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
while (TRUE)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
if (gtk_text_iter_get_char (iter) == '_')
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
gtk_text_iter_forward_visible_cursor_position (iter);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
else if (gtk_text_iter_starts_word (iter))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
gtk_text_iter_forward_visible_word_end (iter);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
else
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
break;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Symmetric of iter_forward_extra_natural_word_end(). */
|
|
Packit |
a7d494 |
void
|
|
Packit |
a7d494 |
_gtk_source_iter_backward_extra_natural_word_start (GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter prev_word_start = *iter;
|
|
Packit |
a7d494 |
GtkTextIter prev_underscore_start = *iter;
|
|
Packit |
a7d494 |
GtkTextIter *limit = NULL;
|
|
Packit |
a7d494 |
gboolean found;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (gtk_text_iter_backward_visible_word_start (&prev_word_start))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
limit = &prev_word_start;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
found = gtk_text_iter_backward_search (iter,
|
|
Packit |
a7d494 |
"_",
|
|
Packit |
a7d494 |
GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY,
|
|
Packit |
a7d494 |
&prev_underscore_start,
|
|
Packit |
a7d494 |
NULL,
|
|
Packit |
a7d494 |
limit);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (found)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = prev_underscore_start;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
else
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = prev_word_start;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
while (!gtk_text_iter_is_start (iter))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter prev = *iter;
|
|
Packit |
a7d494 |
gtk_text_iter_backward_visible_cursor_position (&prev;;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (gtk_text_iter_get_char (&prev) == '_')
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = prev;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
else if (gtk_text_iter_ends_word (iter))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
gtk_text_iter_backward_visible_word_start (iter);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
else
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
break;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
static gboolean
|
|
Packit |
a7d494 |
backward_cursor_position (GtkTextIter *iter,
|
|
Packit |
a7d494 |
gboolean visible)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
if (visible)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return gtk_text_iter_backward_visible_cursor_position (iter);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
return gtk_text_iter_backward_cursor_position (iter);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_starts_extra_natural_word (const GtkTextIter *iter,
|
|
Packit |
a7d494 |
gboolean visible)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
gboolean starts_word;
|
|
Packit |
a7d494 |
GtkTextIter prev;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
starts_word = gtk_text_iter_starts_word (iter);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
prev = *iter;
|
|
Packit |
a7d494 |
if (!backward_cursor_position (&prev, visible))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return starts_word || gtk_text_iter_get_char (iter) == '_';
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (starts_word)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return gtk_text_iter_get_char (&prev) != '_';
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
return (gtk_text_iter_get_char (iter) == '_' &&
|
|
Packit |
a7d494 |
gtk_text_iter_get_char (&prev) != '_' &&
|
|
Packit |
a7d494 |
!gtk_text_iter_ends_word (iter));
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_ends_extra_natural_word (const GtkTextIter *iter,
|
|
Packit |
a7d494 |
gboolean visible)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter prev;
|
|
Packit |
a7d494 |
gboolean ends_word;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
prev = *iter;
|
|
Packit |
a7d494 |
if (!backward_cursor_position (&prev, visible))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return FALSE;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
ends_word = gtk_text_iter_ends_word (iter);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (gtk_text_iter_is_end (iter))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return ends_word || gtk_text_iter_get_char (&prev) == '_';
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (ends_word)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return gtk_text_iter_get_char (iter) != '_';
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
return (gtk_text_iter_get_char (&prev) == '_' &&
|
|
Packit |
a7d494 |
gtk_text_iter_get_char (iter) != '_' &&
|
|
Packit |
a7d494 |
!gtk_text_iter_starts_word (iter));
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Similar to gtk_text_iter_forward_visible_word_end, but with a custom
|
|
Packit |
a7d494 |
* definition of "word".
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* It is normally the same word boundaries as in Vim. This function is the same
|
|
Packit |
a7d494 |
* as the 'e' command.
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* With the custom word definition, a word can be:
|
|
Packit |
a7d494 |
* - a natural-language word as defined by Pango, plus the underscore. The
|
|
Packit |
a7d494 |
* underscore is added because it is often used in programming languages.
|
|
Packit |
a7d494 |
* - a group of contiguous non-blank characters.
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_forward_visible_word_end (GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter orig = *iter;
|
|
Packit |
a7d494 |
GtkTextIter farthest = *iter;
|
|
Packit |
a7d494 |
GtkTextIter next_word_end = *iter;
|
|
Packit |
a7d494 |
GtkTextIter word_start;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* 'farthest' is the farthest position that this function can return. Example:
|
|
Packit |
a7d494 |
* "|---- aaaa" -> "----| aaaa"
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
_gtk_source_iter_forward_full_word_end (&farthest);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Go to the next extra-natural word end. It can be farther than
|
|
Packit |
a7d494 |
* 'farthest':
|
|
Packit |
a7d494 |
* "|---- aaaa" -> "---- aaaa|"
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* Or it can remain at the same place:
|
|
Packit |
a7d494 |
* "aaaa| ----" -> "aaaa| ----"
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
_gtk_source_iter_forward_extra_natural_word_end (&next_word_end);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (gtk_text_iter_compare (&farthest, &next_word_end) < 0 ||
|
|
Packit |
a7d494 |
gtk_text_iter_equal (iter, &next_word_end))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = farthest;
|
|
Packit |
a7d494 |
goto end;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* From 'next_word_end', go to the previous extra-natural word start.
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* Example 1:
|
|
Packit |
a7d494 |
* iter: "ab|cd"
|
|
Packit |
a7d494 |
* next_word_end: "abcd|" -> the good one
|
|
Packit |
a7d494 |
* word_start: "|abcd"
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* Example 2:
|
|
Packit |
a7d494 |
* iter: "| abcd()"
|
|
Packit |
a7d494 |
* next_word_end: " abcd|()" -> the good one
|
|
Packit |
a7d494 |
* word_start: " |abcd()"
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* Example 3:
|
|
Packit |
a7d494 |
* iter: "abcd|()efgh"
|
|
Packit |
a7d494 |
* next_word_end: "abcd()efgh|"
|
|
Packit |
a7d494 |
* word_start: "abcd()|efgh" -> the good one, at the end of the word "()".
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
word_start = next_word_end;
|
|
Packit |
a7d494 |
_gtk_source_iter_backward_extra_natural_word_start (&word_start);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Example 1 */
|
|
Packit |
a7d494 |
if (gtk_text_iter_compare (&word_start, iter) <= 0)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = next_word_end;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Example 2 */
|
|
Packit |
a7d494 |
else if (_gtk_source_iter_starts_full_word (&word_start))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = next_word_end;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Example 3 */
|
|
Packit |
a7d494 |
else
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = word_start;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
end:
|
|
Packit |
a7d494 |
return !gtk_text_iter_equal (&orig, iter) && !gtk_text_iter_is_end (iter);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Symmetric of _gtk_source_iter_forward_visible_word_end(). */
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_backward_visible_word_start (GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter orig = *iter;
|
|
Packit |
a7d494 |
GtkTextIter farthest = *iter;
|
|
Packit |
a7d494 |
GtkTextIter prev_word_start = *iter;
|
|
Packit |
a7d494 |
GtkTextIter word_end;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* 'farthest' is the farthest position that this function can return. Example:
|
|
Packit |
a7d494 |
* "aaaa ----|" -> "aaaa |----"
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
_gtk_source_iter_backward_full_word_start (&farthest);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Go to the previous extra-natural word start. It can be farther than
|
|
Packit |
a7d494 |
* 'farthest':
|
|
Packit |
a7d494 |
* "aaaa ----|" -> "|aaaa ----"
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* Or it can remain at the same place:
|
|
Packit |
a7d494 |
* "---- |aaaa" -> "---- |aaaa"
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
_gtk_source_iter_backward_extra_natural_word_start (&prev_word_start);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (gtk_text_iter_compare (&prev_word_start, &farthest) < 0 ||
|
|
Packit |
a7d494 |
gtk_text_iter_equal (iter, &prev_word_start))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = farthest;
|
|
Packit |
a7d494 |
goto end;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* From 'prev_word_start', go to the next extra-natural word end.
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* Example 1:
|
|
Packit |
a7d494 |
* iter: "ab|cd"
|
|
Packit |
a7d494 |
* prev_word_start: "|abcd" -> the good one
|
|
Packit |
a7d494 |
* word_end: "abcd|"
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* Example 2:
|
|
Packit |
a7d494 |
* iter: "()abcd |"
|
|
Packit |
a7d494 |
* prev_word_start: "()|abcd " -> the good one
|
|
Packit |
a7d494 |
* word_end: "()abcd| "
|
|
Packit |
a7d494 |
*
|
|
Packit |
a7d494 |
* Example 3:
|
|
Packit |
a7d494 |
* iter: "abcd()|"
|
|
Packit |
a7d494 |
* prev_word_start: "|abcd()"
|
|
Packit |
a7d494 |
* word_end: "abcd|()" -> the good one, at the start of the word "()".
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
word_end = prev_word_start;
|
|
Packit |
a7d494 |
_gtk_source_iter_forward_extra_natural_word_end (&word_end);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Example 1 */
|
|
Packit |
a7d494 |
if (gtk_text_iter_compare (iter, &word_end) <= 0)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = prev_word_start;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Example 2 */
|
|
Packit |
a7d494 |
else if (_gtk_source_iter_ends_full_word (&word_end))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = prev_word_start;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Example 3 */
|
|
Packit |
a7d494 |
else
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*iter = word_end;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
end:
|
|
Packit |
a7d494 |
return !gtk_text_iter_equal (&orig, iter) && !gtk_text_iter_is_end (iter);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Similar to gtk_text_iter_forward_visible_word_ends(). */
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_forward_visible_word_ends (GtkTextIter *iter,
|
|
Packit |
a7d494 |
gint count)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter orig = *iter;
|
|
Packit |
a7d494 |
gint i;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (count < 0)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return _gtk_source_iter_backward_visible_word_starts (iter, -count);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
for (i = 0; i < count; i++)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
if (!_gtk_source_iter_forward_visible_word_end (iter))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
break;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
return !gtk_text_iter_equal (&orig, iter) && !gtk_text_iter_is_end (iter);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Similar to gtk_text_iter_backward_visible_word_starts(). */
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_backward_visible_word_starts (GtkTextIter *iter,
|
|
Packit |
a7d494 |
gint count)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter orig = *iter;
|
|
Packit |
a7d494 |
gint i;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (count < 0)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return _gtk_source_iter_forward_visible_word_ends (iter, -count);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
for (i = 0; i < count; i++)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
if (!_gtk_source_iter_backward_visible_word_start (iter))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
break;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
return !gtk_text_iter_equal (&orig, iter) && !gtk_text_iter_is_end (iter);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_starts_word (const GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
if (_gtk_source_iter_starts_full_word (iter) ||
|
|
Packit |
a7d494 |
_gtk_source_iter_starts_extra_natural_word (iter, TRUE))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return TRUE;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Example: "abcd|()", at the start of the word "()". */
|
|
Packit |
a7d494 |
return (!_gtk_source_iter_ends_full_word (iter) &&
|
|
Packit |
a7d494 |
_gtk_source_iter_ends_extra_natural_word (iter, TRUE));
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_ends_word (const GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
if (_gtk_source_iter_ends_full_word (iter) ||
|
|
Packit |
a7d494 |
_gtk_source_iter_ends_extra_natural_word (iter, TRUE))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return TRUE;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Example: "abcd()|efgh", at the end of the word "()". */
|
|
Packit |
a7d494 |
return (!_gtk_source_iter_starts_full_word (iter) &&
|
|
Packit |
a7d494 |
_gtk_source_iter_starts_extra_natural_word (iter, TRUE));
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
gboolean
|
|
Packit |
a7d494 |
_gtk_source_iter_inside_word (const GtkTextIter *iter)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter prev_word_start;
|
|
Packit |
a7d494 |
GtkTextIter word_end;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (_gtk_source_iter_starts_word (iter))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return TRUE;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
prev_word_start = *iter;
|
|
Packit |
a7d494 |
if (!_gtk_source_iter_backward_visible_word_start (&prev_word_start))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
return FALSE;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
word_end = prev_word_start;
|
|
Packit |
a7d494 |
_gtk_source_iter_forward_visible_word_end (&word_end);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
return (gtk_text_iter_compare (&prev_word_start, iter) <= 0 &&
|
|
Packit |
a7d494 |
gtk_text_iter_compare (iter, &word_end) < 0);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Used for the GtkTextView::extend-selection signal. */
|
|
Packit |
a7d494 |
void
|
|
Packit |
a7d494 |
_gtk_source_iter_extend_selection_word (const GtkTextIter *location,
|
|
Packit |
a7d494 |
GtkTextIter *start,
|
|
Packit |
a7d494 |
GtkTextIter *end)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
/* Exactly the same algorithm as in GTK+, but with our custom word
|
|
Packit |
a7d494 |
* boundaries.
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
*start = *location;
|
|
Packit |
a7d494 |
*end = *location;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (_gtk_source_iter_inside_word (start))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
if (!_gtk_source_iter_starts_word (start))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
_gtk_source_iter_backward_visible_word_start (start);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (!_gtk_source_iter_ends_word (end))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
_gtk_source_iter_forward_visible_word_end (end);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
else
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter tmp;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
tmp = *start;
|
|
Packit |
a7d494 |
if (_gtk_source_iter_backward_visible_word_start (&tmp))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
_gtk_source_iter_forward_visible_word_end (&tmp);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (start))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*start = tmp;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
else
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
gtk_text_iter_set_line_offset (start, 0);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
tmp = *end;
|
|
Packit |
a7d494 |
if (!_gtk_source_iter_forward_visible_word_end (&tmp))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
gtk_text_iter_forward_to_end (&tmp);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (_gtk_source_iter_ends_word (&tmp))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
_gtk_source_iter_backward_visible_word_start (&tmp);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (end))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
*end = tmp;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
else
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
gtk_text_iter_forward_to_line_end (end);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Get the boundary, on @iter's line, between leading spaces (indentation) and
|
|
Packit |
a7d494 |
* the text.
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
void
|
|
Packit |
a7d494 |
_gtk_source_iter_get_leading_spaces_end_boundary (const GtkTextIter *iter,
|
|
Packit |
a7d494 |
GtkTextIter *leading_end)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
g_return_if_fail (iter != NULL);
|
|
Packit |
a7d494 |
g_return_if_fail (leading_end != NULL);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
*leading_end = *iter;
|
|
Packit |
a7d494 |
gtk_text_iter_set_line_offset (leading_end, 0);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
while (!gtk_text_iter_ends_line (leading_end))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
gunichar ch = gtk_text_iter_get_char (leading_end);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
if (!g_unichar_isspace (ch))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
break;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
gtk_text_iter_forward_char (leading_end);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
/* Get the boundary, on @iter's line, between the end of the text and trailing
|
|
Packit |
a7d494 |
* spaces.
|
|
Packit |
a7d494 |
*/
|
|
Packit |
a7d494 |
void
|
|
Packit |
a7d494 |
_gtk_source_iter_get_trailing_spaces_start_boundary (const GtkTextIter *iter,
|
|
Packit |
a7d494 |
GtkTextIter *trailing_start)
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
g_return_if_fail (iter != NULL);
|
|
Packit |
a7d494 |
g_return_if_fail (trailing_start != NULL);
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
*trailing_start = *iter;
|
|
Packit |
a7d494 |
if (!gtk_text_iter_ends_line (trailing_start))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
gtk_text_iter_forward_to_line_end (trailing_start);
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
while (!gtk_text_iter_starts_line (trailing_start))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
GtkTextIter prev;
|
|
Packit |
a7d494 |
gunichar ch;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
prev = *trailing_start;
|
|
Packit |
a7d494 |
gtk_text_iter_backward_char (&prev;;
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
ch = gtk_text_iter_get_char (&prev;;
|
|
Packit |
a7d494 |
if (!g_unichar_isspace (ch))
|
|
Packit |
a7d494 |
{
|
|
Packit |
a7d494 |
break;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
|
|
Packit |
a7d494 |
*trailing_start = prev;
|
|
Packit |
a7d494 |
}
|
|
Packit |
a7d494 |
}
|