1 /* GTK - The GIMP Toolkit
2 * gtktextiter.c Copyright (C) 2000 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
27 #include "gtktextiter.h"
28 #include "gtktextbtree.h"
29 #include "gtktextiterprivate.h"
38 * @Short_description: Text buffer iterator
41 * You may wish to begin by reading the <link linkend="TextWidget">text widget
42 * conceptual overview</link> which gives an overview of all the objects and data
43 * types related to the text widget and how they work together.
47 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
49 typedef struct _GtkTextRealIter GtkTextRealIter;
51 struct G_GNUC_MAY_ALIAS _GtkTextRealIter
53 /* Always-valid information */
56 /* At least one of these is always valid;
57 if invalid, they are -1.
59 If the line byte offset is valid, so is the segment byte offset;
60 and ditto for char offsets. */
61 gint line_byte_offset;
62 gint line_char_offset;
63 /* These two are valid if >= 0 */
64 gint cached_char_index;
65 gint cached_line_number;
66 /* Stamps to detect the buffer changing under us */
67 gint chars_changed_stamp;
68 gint segments_changed_stamp;
69 /* Valid if the segments_changed_stamp is up-to-date */
70 GtkTextLineSegment *segment; /* indexable segment we index */
71 GtkTextLineSegment *any_segment; /* first segment in our location,
72 maybe same as "segment" */
73 /* One of these will always be valid if segments_changed_stamp is
74 up-to-date. If invalid, they are -1.
76 If the line byte offset is valid, so is the segment byte offset;
77 and ditto for char offsets. */
78 gint segment_byte_offset;
79 gint segment_char_offset;
86 /* These "set" functions should not assume any fields
87 other than the char stamp and the tree are valid.
90 iter_set_common (GtkTextRealIter *iter,
93 /* Update segments stamp */
94 iter->segments_changed_stamp =
95 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
99 iter->line_byte_offset = -1;
100 iter->line_char_offset = -1;
101 iter->segment_byte_offset = -1;
102 iter->segment_char_offset = -1;
103 iter->cached_char_index = -1;
104 iter->cached_line_number = -1;
108 iter_set_from_byte_offset (GtkTextRealIter *iter,
112 iter_set_common (iter, line);
114 if (!_gtk_text_line_byte_locate (iter->line,
118 &iter->segment_byte_offset,
119 &iter->line_byte_offset))
120 g_error ("Byte index %d is off the end of the line",
125 iter_set_from_char_offset (GtkTextRealIter *iter,
129 iter_set_common (iter, line);
131 if (!_gtk_text_line_char_locate (iter->line,
135 &iter->segment_char_offset,
136 &iter->line_char_offset))
137 g_error ("Char offset %d is off the end of the line",
142 iter_set_from_segment (GtkTextRealIter *iter,
144 GtkTextLineSegment *segment)
146 GtkTextLineSegment *seg;
149 /* This could theoretically be optimized by computing all the iter
150 fields in this same loop, but I'm skipping it for now. */
152 seg = line->segments;
153 while (seg != segment)
155 byte_offset += seg->byte_count;
159 iter_set_from_byte_offset (iter, line, byte_offset);
162 /* This function ensures that the segment-dependent information is
163 truly computed lazily; often we don't need to do the full make_real
164 work. This ensures the btree and line are valid, but doesn't
165 update the segments. */
166 static GtkTextRealIter*
167 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
169 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
171 if (iter->chars_changed_stamp !=
172 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
174 g_warning ("Invalid text buffer iterator: either the iterator "
175 "is uninitialized, or the characters/pixbufs/widgets "
176 "in the buffer have been modified since the iterator "
177 "was created.\nYou must use marks, character numbers, "
178 "or line numbers to preserve a position across buffer "
179 "modifications.\nYou can apply tags and insert marks "
180 "without invalidating your iterators,\n"
181 "but any mutation that affects 'indexable' buffer contents "
182 "(contents that can be referred to by character offset)\n"
183 "will invalidate all outstanding iterators");
187 /* We don't update the segments information since we are becoming
188 only surreal. However we do invalidate the segments information
189 if appropriate, to be sure we segfault if we try to use it and we
190 should have used make_real. */
192 if (iter->segments_changed_stamp !=
193 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
195 iter->segment = NULL;
196 iter->any_segment = NULL;
197 /* set to segfault-causing values. */
198 iter->segment_byte_offset = -10000;
199 iter->segment_char_offset = -10000;
205 static GtkTextRealIter*
206 gtk_text_iter_make_real (const GtkTextIter *_iter)
208 GtkTextRealIter *iter;
210 iter = gtk_text_iter_make_surreal (_iter);
212 if (iter->segments_changed_stamp !=
213 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
215 if (iter->line_byte_offset >= 0)
217 iter_set_from_byte_offset (iter,
219 iter->line_byte_offset);
223 g_assert (iter->line_char_offset >= 0);
225 iter_set_from_char_offset (iter,
227 iter->line_char_offset);
231 g_assert (iter->segment != NULL);
232 g_assert (iter->any_segment != NULL);
233 g_assert (iter->segment->char_count > 0);
238 static GtkTextRealIter*
239 iter_init_common (GtkTextIter *_iter,
242 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
244 g_return_val_if_fail (iter != NULL, NULL);
245 g_return_val_if_fail (tree != NULL, NULL);
249 iter->chars_changed_stamp =
250 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
255 static GtkTextRealIter*
256 iter_init_from_segment (GtkTextIter *iter,
259 GtkTextLineSegment *segment)
261 GtkTextRealIter *real;
263 g_return_val_if_fail (line != NULL, NULL);
265 real = iter_init_common (iter, tree);
267 iter_set_from_segment (real, line, segment);
272 static GtkTextRealIter*
273 iter_init_from_byte_offset (GtkTextIter *iter,
276 gint line_byte_offset)
278 GtkTextRealIter *real;
280 g_return_val_if_fail (line != NULL, NULL);
282 real = iter_init_common (iter, tree);
284 iter_set_from_byte_offset (real, line, line_byte_offset);
286 if (real->segment->type == >k_text_char_type &&
287 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
288 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
289 "character; this will crash the text buffer. "
290 "Byte indexes must refer to the start of a character.",
296 static GtkTextRealIter*
297 iter_init_from_char_offset (GtkTextIter *iter,
300 gint line_char_offset)
302 GtkTextRealIter *real;
304 g_return_val_if_fail (line != NULL, NULL);
306 real = iter_init_common (iter, tree);
308 iter_set_from_char_offset (real, line, line_char_offset);
314 invalidate_char_index (GtkTextRealIter *iter)
316 iter->cached_char_index = -1;
320 adjust_char_index (GtkTextRealIter *iter, gint count)
322 if (iter->cached_char_index >= 0)
323 iter->cached_char_index += count;
327 adjust_line_number (GtkTextRealIter *iter, gint count)
329 if (iter->cached_line_number >= 0)
330 iter->cached_line_number += count;
334 ensure_char_offsets (GtkTextRealIter *iter)
336 if (iter->line_char_offset < 0)
338 g_assert (iter->line_byte_offset >= 0);
340 _gtk_text_line_byte_to_char_offsets (iter->line,
341 iter->line_byte_offset,
342 &iter->line_char_offset,
343 &iter->segment_char_offset);
348 ensure_byte_offsets (GtkTextRealIter *iter)
350 if (iter->line_byte_offset < 0)
352 g_assert (iter->line_char_offset >= 0);
354 _gtk_text_line_char_to_byte_offsets (iter->line,
355 iter->line_char_offset,
356 &iter->line_byte_offset,
357 &iter->segment_byte_offset);
361 static inline gboolean
362 is_segment_start (GtkTextRealIter *real)
364 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
367 #ifdef G_ENABLE_DEBUG
369 check_invariants (const GtkTextIter *iter)
371 if (gtk_get_debug_flags () & GTK_DEBUG_TEXT)
372 _gtk_text_iter_check (iter);
375 #define check_invariants(x)
379 * gtk_text_iter_get_buffer:
382 * Returns the #GtkTextBuffer this iterator is associated with.
384 * Return value: (transfer none): the buffer
387 gtk_text_iter_get_buffer (const GtkTextIter *iter)
389 GtkTextRealIter *real;
391 g_return_val_if_fail (iter != NULL, NULL);
393 real = gtk_text_iter_make_surreal (iter);
398 check_invariants (iter);
400 return _gtk_text_btree_get_buffer (real->tree);
404 * gtk_text_iter_copy:
407 * Creates a dynamically-allocated copy of an iterator. This function
408 * is not useful in applications, because iterators can be copied with a
409 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
410 * function is used by language bindings.
412 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
415 gtk_text_iter_copy (const GtkTextIter *iter)
417 GtkTextIter *new_iter;
419 g_return_val_if_fail (iter != NULL, NULL);
421 new_iter = g_slice_new (GtkTextIter);
429 * gtk_text_iter_free:
430 * @iter: a dynamically-allocated iterator
432 * Free an iterator allocated on the heap. This function
433 * is intended for use in language bindings, and is not
434 * especially useful for applications, because iterators can
435 * simply be allocated on the stack.
438 gtk_text_iter_free (GtkTextIter *iter)
440 g_return_if_fail (iter != NULL);
442 g_slice_free (GtkTextIter, iter);
446 * gtk_text_iter_assign:
447 * @iter: a #GtkTextIter
448 * @other: another #GtkTextIter
450 * Assigns the value of @other to @iter. This function
451 * is not useful in applications, because iterators can be assigned
452 * with <literal>GtkTextIter i = j;</literal>. The
453 * function is used by language bindings.
458 gtk_text_iter_assign (GtkTextIter *iter,
459 const GtkTextIter *other)
461 g_return_if_fail (iter != NULL);
462 g_return_if_fail (other != NULL);
467 G_DEFINE_BOXED_TYPE (GtkTextIter, gtk_text_iter,
472 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
474 GtkTextRealIter *real;
476 g_return_val_if_fail (iter != NULL, NULL);
478 real = gtk_text_iter_make_real (iter);
483 check_invariants (iter);
485 g_assert (real->segment != NULL);
487 return real->segment;
491 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
493 GtkTextRealIter *real;
495 g_return_val_if_fail (iter != NULL, NULL);
497 real = gtk_text_iter_make_real (iter);
502 check_invariants (iter);
504 g_assert (real->any_segment != NULL);
506 return real->any_segment;
510 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
512 GtkTextRealIter *real;
514 g_return_val_if_fail (iter != NULL, 0);
516 real = gtk_text_iter_make_real (iter);
521 ensure_byte_offsets (real);
523 check_invariants (iter);
525 return real->segment_byte_offset;
529 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
531 GtkTextRealIter *real;
533 g_return_val_if_fail (iter != NULL, 0);
535 real = gtk_text_iter_make_real (iter);
540 ensure_char_offsets (real);
542 check_invariants (iter);
544 return real->segment_char_offset;
547 /* This function does not require a still-valid
550 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
552 const GtkTextRealIter *real;
554 g_return_val_if_fail (iter != NULL, NULL);
556 real = (const GtkTextRealIter*)iter;
561 /* This function does not require a still-valid
564 _gtk_text_iter_get_btree (const GtkTextIter *iter)
566 const GtkTextRealIter *real;
568 g_return_val_if_fail (iter != NULL, NULL);
570 real = (const GtkTextRealIter*)iter;
580 * gtk_text_iter_get_offset:
583 * Returns the character offset of an iterator.
584 * Each character in a #GtkTextBuffer has an offset,
585 * starting with 0 for the first character in the buffer.
586 * Use gtk_text_buffer_get_iter_at_offset () to convert an
587 * offset back into an iterator.
589 * Return value: a character offset
592 gtk_text_iter_get_offset (const GtkTextIter *iter)
594 GtkTextRealIter *real;
596 g_return_val_if_fail (iter != NULL, 0);
598 real = gtk_text_iter_make_surreal (iter);
603 check_invariants (iter);
605 if (real->cached_char_index < 0)
607 ensure_char_offsets (real);
609 real->cached_char_index =
610 _gtk_text_line_char_index (real->line);
611 real->cached_char_index += real->line_char_offset;
614 check_invariants (iter);
616 return real->cached_char_index;
620 * gtk_text_iter_get_line:
623 * Returns the line number containing the iterator. Lines in
624 * a #GtkTextBuffer are numbered beginning with 0 for the first
625 * line in the buffer.
627 * Return value: a line number
630 gtk_text_iter_get_line (const GtkTextIter *iter)
632 GtkTextRealIter *real;
634 g_return_val_if_fail (iter != NULL, 0);
636 real = gtk_text_iter_make_surreal (iter);
641 if (real->cached_line_number < 0)
642 real->cached_line_number =
643 _gtk_text_line_get_number (real->line);
645 check_invariants (iter);
647 return real->cached_line_number;
651 * gtk_text_iter_get_line_offset:
654 * Returns the character offset of the iterator,
655 * counting from the start of a newline-terminated line.
656 * The first character on the line has offset 0.
658 * Return value: offset from start of line
661 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
663 GtkTextRealIter *real;
665 g_return_val_if_fail (iter != NULL, 0);
667 real = gtk_text_iter_make_surreal (iter);
672 ensure_char_offsets (real);
674 check_invariants (iter);
676 return real->line_char_offset;
680 * gtk_text_iter_get_line_index:
683 * Returns the byte index of the iterator, counting
684 * from the start of a newline-terminated line.
685 * Remember that #GtkTextBuffer encodes text in
686 * UTF-8, and that characters can require a variable
687 * number of bytes to represent.
689 * Return value: distance from start of line, in bytes
692 gtk_text_iter_get_line_index (const GtkTextIter *iter)
694 GtkTextRealIter *real;
696 g_return_val_if_fail (iter != NULL, 0);
698 real = gtk_text_iter_make_surreal (iter);
703 ensure_byte_offsets (real);
705 check_invariants (iter);
707 return real->line_byte_offset;
711 * gtk_text_iter_get_visible_line_offset:
712 * @iter: a #GtkTextIter
714 * Returns the offset in characters from the start of the
715 * line to the given @iter, not counting characters that
716 * are invisible due to tags with the "invisible" flag
719 * Return value: offset in visible characters from the start of the line
722 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
724 GtkTextRealIter *real;
726 GtkTextLineSegment *seg;
729 g_return_val_if_fail (iter != NULL, 0);
731 real = gtk_text_iter_make_real (iter);
736 ensure_char_offsets (real);
738 check_invariants (iter);
740 vis_offset = real->line_char_offset;
742 g_assert (vis_offset >= 0);
744 _gtk_text_btree_get_iter_at_line (real->tree,
749 seg = _gtk_text_iter_get_indexable_segment (&pos);
751 while (seg != real->segment)
753 /* This is a pretty expensive call, making the
754 * whole function pretty lame; we could keep track
755 * of current invisibility state by looking at toggle
756 * segments as we loop, and then call this function
757 * only once per line, in order to speed up the loop
760 if (_gtk_text_btree_char_is_invisible (&pos))
761 vis_offset -= seg->char_count;
763 _gtk_text_iter_forward_indexable_segment (&pos);
765 seg = _gtk_text_iter_get_indexable_segment (&pos);
768 if (_gtk_text_btree_char_is_invisible (&pos))
769 vis_offset -= real->segment_char_offset;
776 * gtk_text_iter_get_visible_line_index:
777 * @iter: a #GtkTextIter
779 * Returns the number of bytes from the start of the
780 * line to the given @iter, not counting bytes that
781 * are invisible due to tags with the "invisible" flag
784 * Return value: byte index of @iter with respect to the start of the line
787 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
789 GtkTextRealIter *real;
791 GtkTextLineSegment *seg;
794 g_return_val_if_fail (iter != NULL, 0);
796 real = gtk_text_iter_make_real (iter);
801 ensure_byte_offsets (real);
803 check_invariants (iter);
805 vis_offset = real->line_byte_offset;
807 g_assert (vis_offset >= 0);
809 _gtk_text_btree_get_iter_at_line (real->tree,
814 seg = _gtk_text_iter_get_indexable_segment (&pos);
816 while (seg != real->segment)
818 /* This is a pretty expensive call, making the
819 * whole function pretty lame; we could keep track
820 * of current invisibility state by looking at toggle
821 * segments as we loop, and then call this function
822 * only once per line, in order to speed up the loop
825 if (_gtk_text_btree_char_is_invisible (&pos))
826 vis_offset -= seg->byte_count;
828 _gtk_text_iter_forward_indexable_segment (&pos);
830 seg = _gtk_text_iter_get_indexable_segment (&pos);
833 if (_gtk_text_btree_char_is_invisible (&pos))
834 vis_offset -= real->segment_byte_offset;
844 * gtk_text_iter_get_char:
847 * Returns the Unicode character at this iterator. (Equivalent to
848 * operator* on a C++ iterator.) If the element at this iterator is a
849 * non-character element, such as an image embedded in the buffer, the
850 * Unicode "unknown" character 0xFFFC is returned. If invoked on
851 * the end iterator, zero is returned; zero is not a valid Unicode character.
852 * So you can write a loop which ends when gtk_text_iter_get_char ()
855 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
858 gtk_text_iter_get_char (const GtkTextIter *iter)
860 GtkTextRealIter *real;
862 g_return_val_if_fail (iter != NULL, 0);
864 real = gtk_text_iter_make_real (iter);
869 check_invariants (iter);
871 if (gtk_text_iter_is_end (iter))
873 else if (real->segment->type == >k_text_char_type)
875 ensure_byte_offsets (real);
877 return g_utf8_get_char (real->segment->body.chars +
878 real->segment_byte_offset);
882 /* Unicode "unknown character" 0xFFFC */
883 return GTK_TEXT_UNKNOWN_CHAR;
888 * gtk_text_iter_get_slice:
889 * @start: iterator at start of a range
890 * @end: iterator at end of a range
892 * Returns the text in the given range. A "slice" is an array of
893 * characters encoded in UTF-8 format, including the Unicode "unknown"
894 * character 0xFFFC for iterable non-character elements in the buffer,
895 * such as images. Because images are encoded in the slice, byte and
896 * character offsets in the returned array will correspond to byte
897 * offsets in the text buffer. Note that 0xFFFC can occur in normal
898 * text as well, so it is not a reliable indicator that a pixbuf or
899 * widget is in the buffer.
901 * Return value: slice of text from the buffer
904 gtk_text_iter_get_slice (const GtkTextIter *start,
905 const GtkTextIter *end)
907 g_return_val_if_fail (start != NULL, NULL);
908 g_return_val_if_fail (end != NULL, NULL);
910 check_invariants (start);
911 check_invariants (end);
913 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
917 * gtk_text_iter_get_text:
918 * @start: iterator at start of a range
919 * @end: iterator at end of a range
921 * Returns <emphasis>text</emphasis> in the given range. If the range
922 * contains non-text elements such as images, the character and byte
923 * offsets in the returned string will not correspond to character and
924 * byte offsets in the buffer. If you want offsets to correspond, see
925 * gtk_text_iter_get_slice ().
927 * Return value: array of characters from the buffer
930 gtk_text_iter_get_text (const GtkTextIter *start,
931 const GtkTextIter *end)
933 g_return_val_if_fail (start != NULL, NULL);
934 g_return_val_if_fail (end != NULL, NULL);
936 check_invariants (start);
937 check_invariants (end);
939 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
943 * gtk_text_iter_get_visible_slice:
944 * @start: iterator at start of range
945 * @end: iterator at end of range
947 * Like gtk_text_iter_get_slice (), but invisible text is not included.
948 * Invisible text is usually invisible because a #GtkTextTag with the
949 * "invisible" attribute turned on has been applied to it.
951 * Return value: slice of text from the buffer
954 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
955 const GtkTextIter *end)
957 g_return_val_if_fail (start != NULL, NULL);
958 g_return_val_if_fail (end != NULL, NULL);
960 check_invariants (start);
961 check_invariants (end);
963 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
967 * gtk_text_iter_get_visible_text:
968 * @start: iterator at start of range
969 * @end: iterator at end of range
971 * Like gtk_text_iter_get_text (), but invisible text is not included.
972 * Invisible text is usually invisible because a #GtkTextTag with the
973 * "invisible" attribute turned on has been applied to it.
975 * Return value: string containing visible text in the range
978 gtk_text_iter_get_visible_text (const GtkTextIter *start,
979 const GtkTextIter *end)
981 g_return_val_if_fail (start != NULL, NULL);
982 g_return_val_if_fail (end != NULL, NULL);
984 check_invariants (start);
985 check_invariants (end);
987 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
991 * gtk_text_iter_get_pixbuf:
994 * If the element at @iter is a pixbuf, the pixbuf is returned
995 * (with no new reference count added). Otherwise,
998 * Return value: (transfer none): the pixbuf at @iter
1001 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1003 GtkTextRealIter *real;
1005 g_return_val_if_fail (iter != NULL, NULL);
1007 real = gtk_text_iter_make_real (iter);
1012 check_invariants (iter);
1014 if (real->segment->type != >k_text_pixbuf_type)
1017 return real->segment->body.pixbuf.pixbuf;
1021 * gtk_text_iter_get_child_anchor:
1022 * @iter: an iterator
1024 * If the location at @iter contains a child anchor, the
1025 * anchor is returned (with no new reference count added). Otherwise,
1026 * %NULL is returned.
1028 * Return value: (transfer none): the anchor at @iter
1031 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1033 GtkTextRealIter *real;
1035 g_return_val_if_fail (iter != NULL, NULL);
1037 real = gtk_text_iter_make_real (iter);
1042 check_invariants (iter);
1044 if (real->segment->type != >k_text_child_type)
1047 return real->segment->body.child.obj;
1051 * gtk_text_iter_get_marks:
1052 * @iter: an iterator
1054 * Returns a list of all #GtkTextMark at this location. Because marks
1055 * are not iterable (they don't take up any "space" in the buffer,
1056 * they are just marks in between iterable locations), multiple marks
1057 * can exist in the same place. The returned list is not in any
1060 * Return value: (element-type GtkTextMark) (transfer container): list of #GtkTextMark
1063 gtk_text_iter_get_marks (const GtkTextIter *iter)
1065 GtkTextRealIter *real;
1066 GtkTextLineSegment *seg;
1069 g_return_val_if_fail (iter != NULL, NULL);
1071 real = gtk_text_iter_make_real (iter);
1076 check_invariants (iter);
1079 seg = real->any_segment;
1080 while (seg != real->segment)
1082 if (seg->type == >k_text_left_mark_type ||
1083 seg->type == >k_text_right_mark_type)
1084 retval = g_slist_prepend (retval, seg->body.mark.obj);
1089 /* The returned list isn't guaranteed to be in any special order,
1095 * gtk_text_iter_get_toggled_tags:
1096 * @iter: an iterator
1097 * @toggled_on: %TRUE to get toggled-on tags
1099 * Returns a list of #GtkTextTag that are toggled on or off at this
1100 * point. (If @toggled_on is %TRUE, the list contains tags that are
1101 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1102 * range of characters following @iter has that tag applied to it. If
1103 * a tag is toggled off, then some non-empty range following @iter
1104 * does <emphasis>not</emphasis> have the tag applied to it.
1106 * Return value: (element-type GtkTextTag) (transfer container): tags toggled at this point
1109 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1110 gboolean toggled_on)
1112 GtkTextRealIter *real;
1113 GtkTextLineSegment *seg;
1116 g_return_val_if_fail (iter != NULL, NULL);
1118 real = gtk_text_iter_make_real (iter);
1123 check_invariants (iter);
1126 seg = real->any_segment;
1127 while (seg != real->segment)
1131 if (seg->type == >k_text_toggle_on_type)
1133 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1138 if (seg->type == >k_text_toggle_off_type)
1140 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1147 /* The returned list isn't guaranteed to be in any special order,
1153 * gtk_text_iter_begins_tag:
1154 * @iter: an iterator
1155 * @tag: (allow-none): a #GtkTextTag, or %NULL
1157 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1158 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1159 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1160 * <emphasis>start</emphasis> of the tagged range;
1161 * gtk_text_iter_has_tag () tells you whether an iterator is
1162 * <emphasis>within</emphasis> a tagged range.
1164 * Return value: whether @iter is the start of a range tagged with @tag
1167 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1170 GtkTextRealIter *real;
1171 GtkTextLineSegment *seg;
1173 g_return_val_if_fail (iter != NULL, FALSE);
1175 real = gtk_text_iter_make_real (iter);
1180 check_invariants (iter);
1182 seg = real->any_segment;
1183 while (seg != real->segment)
1185 if (seg->type == >k_text_toggle_on_type)
1188 seg->body.toggle.info->tag == tag)
1199 * gtk_text_iter_ends_tag:
1200 * @iter: an iterator
1201 * @tag: (allow-none): a #GtkTextTag, or %NULL
1203 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1204 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1205 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1206 * <emphasis>end</emphasis> of the tagged range;
1207 * gtk_text_iter_has_tag () tells you whether an iterator is
1208 * <emphasis>within</emphasis> a tagged range.
1210 * Return value: whether @iter is the end of a range tagged with @tag
1214 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1217 GtkTextRealIter *real;
1218 GtkTextLineSegment *seg;
1220 g_return_val_if_fail (iter != NULL, FALSE);
1222 real = gtk_text_iter_make_real (iter);
1227 check_invariants (iter);
1229 seg = real->any_segment;
1230 while (seg != real->segment)
1232 if (seg->type == >k_text_toggle_off_type)
1235 seg->body.toggle.info->tag == tag)
1246 * gtk_text_iter_toggles_tag:
1247 * @iter: an iterator
1248 * @tag: (allow-none): a #GtkTextTag, or %NULL
1250 * This is equivalent to (gtk_text_iter_begins_tag () ||
1251 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1252 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1254 * Return value: whether @tag is toggled on or off at @iter
1257 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1260 GtkTextRealIter *real;
1261 GtkTextLineSegment *seg;
1263 g_return_val_if_fail (iter != NULL, FALSE);
1265 real = gtk_text_iter_make_real (iter);
1270 check_invariants (iter);
1272 seg = real->any_segment;
1273 while (seg != real->segment)
1275 if ( (seg->type == >k_text_toggle_off_type ||
1276 seg->type == >k_text_toggle_on_type) &&
1278 seg->body.toggle.info->tag == tag) )
1288 * gtk_text_iter_has_tag:
1289 * @iter: an iterator
1290 * @tag: a #GtkTextTag
1292 * Returns %TRUE if @iter is within a range tagged with @tag.
1294 * Return value: whether @iter is tagged with @tag
1297 gtk_text_iter_has_tag (const GtkTextIter *iter,
1300 GtkTextRealIter *real;
1302 g_return_val_if_fail (iter != NULL, FALSE);
1303 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1305 real = gtk_text_iter_make_surreal (iter);
1310 check_invariants (iter);
1312 if (real->line_byte_offset >= 0)
1314 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1315 real->line_byte_offset, tag);
1319 g_assert (real->line_char_offset >= 0);
1320 return _gtk_text_line_char_has_tag (real->line, real->tree,
1321 real->line_char_offset, tag);
1326 * gtk_text_iter_get_tags:
1327 * @iter: a #GtkTextIter
1329 * Returns a list of tags that apply to @iter, in ascending order of
1330 * priority (highest-priority tags are last). The #GtkTextTag in the
1331 * list don't have a reference added, but you have to free the list
1334 * Return value: (element-type GtkTextTag) (transfer container): list of #GtkTextTag
1337 gtk_text_iter_get_tags (const GtkTextIter *iter)
1344 g_return_val_if_fail (iter != NULL, NULL);
1346 /* Get the tags at this spot */
1347 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1349 /* No tags, use default style */
1350 if (tags == NULL || tag_count == 0)
1359 while (i < tag_count)
1361 retval = g_slist_prepend (retval, tags[i]);
1367 /* Return tags in ascending order of priority */
1368 return g_slist_reverse (retval);
1372 * gtk_text_iter_editable:
1373 * @iter: an iterator
1374 * @default_setting: %TRUE if text is editable by default
1376 * Returns whether the character at @iter is within an editable region
1377 * of text. Non-editable text is "locked" and can't be changed by the
1378 * user via #GtkTextView. This function is simply a convenience
1379 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1380 * to this text affect editability, @default_setting will be returned.
1382 * You don't want to use this function to decide whether text can be
1383 * inserted at @iter, because for insertion you don't want to know
1384 * whether the char at @iter is inside an editable range, you want to
1385 * know whether a new character inserted at @iter would be inside an
1386 * editable range. Use gtk_text_iter_can_insert() to handle this
1389 * Return value: whether @iter is inside an editable range
1392 gtk_text_iter_editable (const GtkTextIter *iter,
1393 gboolean default_setting)
1395 GtkTextAttributes *values;
1398 g_return_val_if_fail (iter != NULL, FALSE);
1400 values = gtk_text_attributes_new ();
1402 values->editable = default_setting;
1404 gtk_text_iter_get_attributes (iter, values);
1406 retval = values->editable;
1408 gtk_text_attributes_unref (values);
1414 * gtk_text_iter_can_insert:
1415 * @iter: an iterator
1416 * @default_editability: %TRUE if text is editable by default
1418 * Considering the default editability of the buffer, and tags that
1419 * affect editability, determines whether text inserted at @iter would
1420 * be editable. If text inserted at @iter would be editable then the
1421 * user should be allowed to insert text at @iter.
1422 * gtk_text_buffer_insert_interactive() uses this function to decide
1423 * whether insertions are allowed at a given position.
1425 * Return value: whether text inserted at @iter would be editable
1428 gtk_text_iter_can_insert (const GtkTextIter *iter,
1429 gboolean default_editability)
1431 g_return_val_if_fail (iter != NULL, FALSE);
1433 if (gtk_text_iter_editable (iter, default_editability))
1435 /* If at start/end of buffer, default editability is used */
1436 else if ((gtk_text_iter_is_start (iter) ||
1437 gtk_text_iter_is_end (iter)) &&
1438 default_editability)
1442 /* if iter isn't editable, and the char before iter is,
1443 * then iter is the first char in an editable region
1444 * and thus insertion at iter results in editable text.
1446 GtkTextIter prev = *iter;
1447 gtk_text_iter_backward_char (&prev);
1448 return gtk_text_iter_editable (&prev, default_editability);
1454 * gtk_text_iter_get_language:
1455 * @iter: an iterator
1457 * A convenience wrapper around gtk_text_iter_get_attributes (),
1458 * which returns the language in effect at @iter. If no tags affecting
1459 * language apply to @iter, the return value is identical to that of
1460 * gtk_get_default_language ().
1462 * Return value: language in effect at @iter
1465 gtk_text_iter_get_language (const GtkTextIter *iter)
1467 GtkTextAttributes *values;
1468 PangoLanguage *retval;
1470 values = gtk_text_attributes_new ();
1472 gtk_text_iter_get_attributes (iter, values);
1474 retval = values->language;
1476 gtk_text_attributes_unref (values);
1482 * gtk_text_iter_starts_line:
1483 * @iter: an iterator
1485 * Returns %TRUE if @iter begins a paragraph,
1486 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1487 * However this function is potentially more efficient than
1488 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1489 * the offset, it just has to see whether it's 0.
1491 * Return value: whether @iter begins a line
1494 gtk_text_iter_starts_line (const GtkTextIter *iter)
1496 GtkTextRealIter *real;
1498 g_return_val_if_fail (iter != NULL, FALSE);
1500 real = gtk_text_iter_make_surreal (iter);
1505 check_invariants (iter);
1507 if (real->line_byte_offset >= 0)
1509 return (real->line_byte_offset == 0);
1513 g_assert (real->line_char_offset >= 0);
1514 return (real->line_char_offset == 0);
1519 * gtk_text_iter_ends_line:
1520 * @iter: an iterator
1522 * Returns %TRUE if @iter points to the start of the paragraph
1523 * delimiter characters for a line (delimiters will be either a
1524 * newline, a carriage return, a carriage return followed by a
1525 * newline, or a Unicode paragraph separator character). Note that an
1526 * iterator pointing to the \n of a \r\n pair will not be counted as
1527 * the end of a line, the line ends before the \r. The end iterator is
1528 * considered to be at the end of a line, even though there are no
1529 * paragraph delimiter chars there.
1531 * Return value: whether @iter is at the end of a line
1534 gtk_text_iter_ends_line (const GtkTextIter *iter)
1538 g_return_val_if_fail (iter != NULL, FALSE);
1540 check_invariants (iter);
1542 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1543 * Unicode 3.0; update this if that changes.
1545 #define PARAGRAPH_SEPARATOR 0x2029
1547 wc = gtk_text_iter_get_char (iter);
1549 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1551 else if (wc == '\n')
1553 GtkTextIter tmp = *iter;
1555 /* need to determine if a \r precedes the \n, in which case
1556 * we aren't the end of the line.
1557 * Note however that if \r and \n are on different lines, they
1558 * both are terminators. This for instance may happen after
1559 * deleting some text:
1561 1 some text\r delete 'a' 1 some text\r
1562 2 a\n ---------> 2 \n
1567 if (gtk_text_iter_get_line_offset (&tmp) == 0)
1570 if (!gtk_text_iter_backward_char (&tmp))
1573 return gtk_text_iter_get_char (&tmp) != '\r';
1580 * gtk_text_iter_is_end:
1581 * @iter: an iterator
1583 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1584 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1585 * the most efficient way to check whether an iterator is the end
1588 * Return value: whether @iter is the end iterator
1591 gtk_text_iter_is_end (const GtkTextIter *iter)
1593 GtkTextRealIter *real;
1595 g_return_val_if_fail (iter != NULL, FALSE);
1597 real = gtk_text_iter_make_surreal (iter);
1602 check_invariants (iter);
1604 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1607 /* Now we need the segments validated */
1608 real = gtk_text_iter_make_real (iter);
1613 return _gtk_text_btree_is_end (real->tree, real->line,
1615 real->segment_byte_offset,
1616 real->segment_char_offset);
1620 * gtk_text_iter_is_start:
1621 * @iter: an iterator
1623 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1624 * if @iter has a character offset of 0.
1626 * Return value: whether @iter is the first in the buffer
1629 gtk_text_iter_is_start (const GtkTextIter *iter)
1631 return gtk_text_iter_get_offset (iter) == 0;
1635 * gtk_text_iter_get_chars_in_line:
1636 * @iter: an iterator
1638 * Returns the number of characters in the line containing @iter,
1639 * including the paragraph delimiters.
1641 * Return value: number of characters in the line
1644 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1646 GtkTextRealIter *real;
1648 GtkTextLineSegment *seg;
1650 g_return_val_if_fail (iter != NULL, 0);
1652 real = gtk_text_iter_make_surreal (iter);
1657 check_invariants (iter);
1659 if (real->line_char_offset >= 0)
1661 /* We can start at the segments we've already found. */
1662 count = real->line_char_offset - real->segment_char_offset;
1663 seg = _gtk_text_iter_get_indexable_segment (iter);
1667 /* count whole line. */
1668 seg = real->line->segments;
1675 count += seg->char_count;
1680 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1681 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1687 * gtk_text_iter_get_bytes_in_line:
1688 * @iter: an iterator
1690 * Returns the number of bytes in the line containing @iter,
1691 * including the paragraph delimiters.
1693 * Return value: number of bytes in the line
1696 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1698 GtkTextRealIter *real;
1700 GtkTextLineSegment *seg;
1702 g_return_val_if_fail (iter != NULL, 0);
1704 real = gtk_text_iter_make_surreal (iter);
1709 check_invariants (iter);
1711 if (real->line_byte_offset >= 0)
1713 /* We can start at the segments we've already found. */
1714 count = real->line_byte_offset - real->segment_byte_offset;
1715 seg = _gtk_text_iter_get_indexable_segment (iter);
1719 /* count whole line. */
1720 seg = real->line->segments;
1726 count += seg->byte_count;
1731 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1732 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1738 * gtk_text_iter_get_attributes:
1739 * @iter: an iterator
1740 * @values: (out): a #GtkTextAttributes to be filled in
1742 * Computes the effect of any tags applied to this spot in the
1743 * text. The @values parameter should be initialized to the default
1744 * settings you wish to use if no tags are in effect. You'd typically
1745 * obtain the defaults from gtk_text_view_get_default_attributes().
1747 * gtk_text_iter_get_attributes () will modify @values, applying the
1748 * effects of any tags present at @iter. If any tags affected @values,
1749 * the function returns %TRUE.
1751 * Return value: %TRUE if @values was modified
1754 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1755 GtkTextAttributes *values)
1760 /* Get the tags at this spot */
1761 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1763 /* No tags, use default style */
1764 if (tags == NULL || tag_count == 0)
1771 _gtk_text_attributes_fill_from_tags (values,
1781 * Increments/decrements
1784 /* The return value of this indicates WHETHER WE MOVED.
1785 * The return value of public functions indicates
1786 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1788 * This function will not change the iterator if
1789 * it's already on the last (end iter) line, i.e. it
1790 * won't move to the end of the last line.
1793 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1795 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1797 GtkTextLine *new_line;
1799 new_line = _gtk_text_line_next (real->line);
1800 g_assert (new_line);
1801 g_assert (new_line != real->line);
1802 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1804 real->line = new_line;
1806 real->line_byte_offset = 0;
1807 real->line_char_offset = 0;
1809 real->segment_byte_offset = 0;
1810 real->segment_char_offset = 0;
1812 /* Find first segments in new line */
1813 real->any_segment = real->line->segments;
1814 real->segment = real->any_segment;
1815 while (real->segment->char_count == 0)
1816 real->segment = real->segment->next;
1822 /* There is no way to move forward a line; we were already at
1823 * the line containing the end iterator.
1824 * However we may not be at the end iterator itself.
1832 /* The return value of this indicates WHETHER WE MOVED.
1833 * The return value of public functions indicates
1834 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1836 * This function is currently unused, thus it is #if-0-ed. It is
1837 * left here, since it's non-trivial code that might be useful in
1841 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1843 GtkTextLine *new_line;
1845 new_line = _gtk_text_line_previous (real->line);
1847 g_assert (new_line != real->line);
1849 if (new_line != NULL)
1851 real->line = new_line;
1853 real->line_byte_offset = 0;
1854 real->line_char_offset = 0;
1856 real->segment_byte_offset = 0;
1857 real->segment_char_offset = 0;
1859 /* Find first segments in new line */
1860 real->any_segment = real->line->segments;
1861 real->segment = real->any_segment;
1862 while (real->segment->char_count == 0)
1863 real->segment = real->segment->next;
1869 /* There is no way to move backward; we were already
1870 at the first line. */
1872 /* We leave real->line as-is */
1874 /* Note that we didn't clamp to the start of the first line. */
1881 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1885 forward_char (GtkTextRealIter *real)
1887 GtkTextIter *iter = (GtkTextIter*)real;
1889 check_invariants ((GtkTextIter*)real);
1891 ensure_char_offsets (real);
1893 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1895 /* Need to move to the next segment; if no next segment,
1896 need to move to next line. */
1897 return _gtk_text_iter_forward_indexable_segment (iter);
1901 /* Just moving within a segment. Keep byte count
1902 up-to-date, if it was already up-to-date. */
1904 g_assert (real->segment->type == >k_text_char_type);
1906 if (real->line_byte_offset >= 0)
1909 const char * start =
1910 real->segment->body.chars + real->segment_byte_offset;
1912 bytes = g_utf8_next_char (start) - start;
1914 real->line_byte_offset += bytes;
1915 real->segment_byte_offset += bytes;
1917 g_assert (real->segment_byte_offset < real->segment->byte_count);
1920 real->line_char_offset += 1;
1921 real->segment_char_offset += 1;
1923 adjust_char_index (real, 1);
1925 g_assert (real->segment_char_offset < real->segment->char_count);
1927 /* We moved into the middle of a segment, so the any_segment
1928 must now be the segment we're in the middle of. */
1929 real->any_segment = real->segment;
1931 check_invariants ((GtkTextIter*)real);
1933 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1941 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1943 /* Need to move to the next segment; if no next segment,
1944 need to move to next line. */
1945 GtkTextLineSegment *seg;
1946 GtkTextLineSegment *any_seg;
1947 GtkTextRealIter *real;
1951 g_return_val_if_fail (iter != NULL, FALSE);
1953 real = gtk_text_iter_make_real (iter);
1958 check_invariants (iter);
1960 if (real->line_char_offset >= 0)
1962 chars_skipped = real->segment->char_count - real->segment_char_offset;
1963 g_assert (chars_skipped > 0);
1968 if (real->line_byte_offset >= 0)
1970 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1971 g_assert (bytes_skipped > 0);
1976 /* Get first segment of any kind */
1977 any_seg = real->segment->next;
1978 /* skip non-indexable segments, if any */
1980 while (seg != NULL && seg->char_count == 0)
1985 real->any_segment = any_seg;
1986 real->segment = seg;
1988 if (real->line_byte_offset >= 0)
1990 g_assert (bytes_skipped > 0);
1991 real->segment_byte_offset = 0;
1992 real->line_byte_offset += bytes_skipped;
1995 if (real->line_char_offset >= 0)
1997 g_assert (chars_skipped > 0);
1998 real->segment_char_offset = 0;
1999 real->line_char_offset += chars_skipped;
2000 adjust_char_index (real, chars_skipped);
2003 check_invariants (iter);
2005 return !gtk_text_iter_is_end (iter);
2009 /* End of the line */
2010 if (forward_line_leaving_caches_unmodified (real))
2012 adjust_line_number (real, 1);
2013 if (real->line_char_offset >= 0)
2014 adjust_char_index (real, chars_skipped);
2016 g_assert (real->line_byte_offset == 0);
2017 g_assert (real->line_char_offset == 0);
2018 g_assert (real->segment_byte_offset == 0);
2019 g_assert (real->segment_char_offset == 0);
2020 g_assert (gtk_text_iter_starts_line (iter));
2022 check_invariants (iter);
2024 return !gtk_text_iter_is_end (iter);
2028 /* End of buffer, but iter is still at start of last segment,
2029 * not at the end iterator. We put it on the end iterator.
2032 check_invariants (iter);
2034 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2035 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2037 gtk_text_iter_forward_to_line_end (iter);
2039 g_assert (gtk_text_iter_is_end (iter));
2047 at_last_indexable_segment (GtkTextRealIter *real)
2049 GtkTextLineSegment *seg;
2051 /* Return TRUE if there are no indexable segments after
2055 seg = real->segment->next;
2058 if (seg->char_count > 0)
2065 /* Goes back to the start of the next segment, even if
2066 * we're not at the start of the current segment (always
2067 * ends up on a different segment if it returns TRUE)
2070 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2072 /* Move to the start of the previous segment; if no previous
2073 * segment, to the last segment in the previous line. This is
2074 * inherently a bit inefficient due to the singly-linked list and
2075 * tree nodes, but we can't afford the RAM for doubly-linked.
2077 GtkTextRealIter *real;
2078 GtkTextLineSegment *seg;
2079 GtkTextLineSegment *any_seg;
2080 GtkTextLineSegment *prev_seg;
2081 GtkTextLineSegment *prev_any_seg;
2085 g_return_val_if_fail (iter != NULL, FALSE);
2087 real = gtk_text_iter_make_real (iter);
2092 check_invariants (iter);
2094 /* Find first segments in line */
2095 any_seg = real->line->segments;
2097 while (seg->char_count == 0)
2100 if (seg == real->segment)
2102 /* Could probably do this case faster by hand-coding the
2106 /* We were already at the start of a line;
2107 * go back to the previous line.
2109 if (gtk_text_iter_backward_line (iter))
2111 /* Go forward to last indexable segment in line. */
2112 while (!at_last_indexable_segment (real))
2113 _gtk_text_iter_forward_indexable_segment (iter);
2115 check_invariants (iter);
2120 return FALSE; /* We were at the start of the first line. */
2123 /* We must be in the middle of a line; so find the indexable
2124 * segment just before our current segment.
2126 g_assert (seg != real->segment);
2130 prev_any_seg = any_seg;
2132 any_seg = seg->next;
2134 while (seg->char_count == 0)
2137 while (seg != real->segment);
2139 g_assert (prev_seg != NULL);
2140 g_assert (prev_any_seg != NULL);
2141 g_assert (prev_seg->char_count > 0);
2143 /* We skipped the entire previous segment, plus any
2144 * chars we were into the current segment.
2146 if (real->segment_byte_offset >= 0)
2147 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2151 if (real->segment_char_offset >= 0)
2152 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2156 real->segment = prev_seg;
2157 real->any_segment = prev_any_seg;
2158 real->segment_byte_offset = 0;
2159 real->segment_char_offset = 0;
2161 if (bytes_skipped >= 0)
2163 if (real->line_byte_offset >= 0)
2165 real->line_byte_offset -= bytes_skipped;
2166 g_assert (real->line_byte_offset >= 0);
2170 real->line_byte_offset = -1;
2172 if (chars_skipped >= 0)
2174 if (real->line_char_offset >= 0)
2176 real->line_char_offset -= chars_skipped;
2177 g_assert (real->line_char_offset >= 0);
2180 if (real->cached_char_index >= 0)
2182 real->cached_char_index -= chars_skipped;
2183 g_assert (real->cached_char_index >= 0);
2188 real->line_char_offset = -1;
2189 real->cached_char_index = -1;
2192 /* line number is unchanged. */
2194 check_invariants (iter);
2200 * gtk_text_iter_forward_char:
2201 * @iter: an iterator
2203 * Moves @iter forward by one character offset. Note that images
2204 * embedded in the buffer occupy 1 character slot, so
2205 * gtk_text_iter_forward_char () may actually move onto an image instead
2206 * of a character, if you have images in your buffer. If @iter is the
2207 * end iterator or one character before it, @iter will now point at
2208 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2209 * convenience when writing loops.
2211 * Return value: whether @iter moved and is dereferenceable
2214 gtk_text_iter_forward_char (GtkTextIter *iter)
2216 GtkTextRealIter *real;
2218 g_return_val_if_fail (iter != NULL, FALSE);
2220 real = gtk_text_iter_make_real (iter);
2226 check_invariants (iter);
2227 return forward_char (real);
2232 * gtk_text_iter_backward_char:
2233 * @iter: an iterator
2235 * Moves backward by one character offset. Returns %TRUE if movement
2236 * was possible; if @iter was the first in the buffer (character
2237 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2240 * Return value: whether movement was possible
2243 gtk_text_iter_backward_char (GtkTextIter *iter)
2245 g_return_val_if_fail (iter != NULL, FALSE);
2247 check_invariants (iter);
2249 return gtk_text_iter_backward_chars (iter, 1);
2253 Definitely we should try to linear scan as often as possible for
2254 movement within a single line, because we can't use the BTree to
2255 speed within-line searches up; for movement between lines, we would
2256 like to avoid the linear scan probably.
2258 Instead of using this constant, it might be nice to cache the line
2259 length in the iterator and linear scan if motion is within a single
2262 I guess you'd have to profile the various approaches.
2264 #define MAX_LINEAR_SCAN 150
2268 * gtk_text_iter_forward_chars:
2269 * @iter: an iterator
2270 * @count: number of characters to move, may be negative
2272 * Moves @count characters if possible (if @count would move past the
2273 * start or end of the buffer, moves to the start or end of the
2274 * buffer). The return value indicates whether the new position of
2275 * @iter is different from its original position, and dereferenceable
2276 * (the last iterator in the buffer is not dereferenceable). If @count
2277 * is 0, the function does nothing and returns %FALSE.
2279 * Return value: whether @iter moved and is dereferenceable
2282 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2284 GtkTextRealIter *real;
2286 g_return_val_if_fail (iter != NULL, FALSE);
2288 FIX_OVERFLOWS (count);
2290 real = gtk_text_iter_make_real (iter);
2294 else if (count == 0)
2297 return gtk_text_iter_backward_chars (iter, 0 - count);
2298 else if (count < MAX_LINEAR_SCAN)
2300 check_invariants (iter);
2304 if (!forward_char (real))
2309 return forward_char (real);
2313 gint current_char_index;
2314 gint new_char_index;
2316 check_invariants (iter);
2318 current_char_index = gtk_text_iter_get_offset (iter);
2320 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2321 return FALSE; /* can't move forward */
2323 new_char_index = current_char_index + count;
2324 gtk_text_iter_set_offset (iter, new_char_index);
2326 check_invariants (iter);
2328 /* Return FALSE if we're on the non-dereferenceable end
2331 if (gtk_text_iter_is_end (iter))
2339 * gtk_text_iter_backward_chars:
2340 * @iter: an iterator
2341 * @count: number of characters to move
2343 * Moves @count characters backward, if possible (if @count would move
2344 * past the start or end of the buffer, moves to the start or end of
2345 * the buffer). The return value indicates whether the iterator moved
2346 * onto a dereferenceable position; if the iterator didn't move, or
2347 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2348 * the function does nothing and returns %FALSE.
2350 * Return value: whether @iter moved and is dereferenceable
2354 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2356 GtkTextRealIter *real;
2358 g_return_val_if_fail (iter != NULL, FALSE);
2360 FIX_OVERFLOWS (count);
2362 real = gtk_text_iter_make_real (iter);
2366 else if (count == 0)
2369 return gtk_text_iter_forward_chars (iter, 0 - count);
2371 ensure_char_offsets (real);
2372 check_invariants (iter);
2374 /* <, not <=, because if count == segment_char_offset
2375 * we're going to the front of the segment and the any_segment
2378 if (count < real->segment_char_offset)
2380 /* Optimize the within-segment case */
2381 g_assert (real->segment->char_count > 0);
2382 g_assert (real->segment->type == >k_text_char_type);
2384 if (real->line_byte_offset >= 0)
2387 gint new_byte_offset;
2389 /* if in the last fourth of the segment walk backwards */
2390 if (count < real->segment_char_offset / 4)
2391 p = g_utf8_offset_to_pointer (real->segment->body.chars + real->segment_byte_offset,
2394 p = g_utf8_offset_to_pointer (real->segment->body.chars,
2395 real->segment_char_offset - count);
2397 new_byte_offset = p - real->segment->body.chars;
2398 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2399 real->segment_byte_offset = new_byte_offset;
2402 real->segment_char_offset -= count;
2403 real->line_char_offset -= count;
2405 adjust_char_index (real, 0 - count);
2407 check_invariants (iter);
2413 /* We need to go back into previous segments. For now,
2414 * just keep this really simple. FIXME
2415 * use backward_indexable_segment.
2417 if (TRUE || count > MAX_LINEAR_SCAN)
2419 gint current_char_index;
2420 gint new_char_index;
2422 current_char_index = gtk_text_iter_get_offset (iter);
2424 if (current_char_index == 0)
2425 return FALSE; /* can't move backward */
2427 new_char_index = current_char_index - count;
2428 if (new_char_index < 0)
2431 gtk_text_iter_set_offset (iter, new_char_index);
2433 check_invariants (iter);
2439 /* FIXME backward_indexable_segment here */
2448 /* These two can't be implemented efficiently (always have to use
2449 * a linear scan, since that's the only way to find all the non-text
2454 * gtk_text_iter_forward_text_chars:
2455 * @iter: a #GtkTextIter
2456 * @count: number of chars to move
2458 * Moves forward by @count text characters (pixbufs, widgets,
2459 * etc. do not count as characters for this). Equivalent to moving
2460 * through the results of gtk_text_iter_get_text (), rather than
2461 * gtk_text_iter_get_slice ().
2463 * Return value: whether @iter moved and is dereferenceable
2466 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2475 * gtk_text_iter_backward_text_chars:
2476 * @iter: a #GtkTextIter
2477 * @count: number of chars to move
2479 * Moves backward by @count text characters (pixbufs, widgets,
2480 * etc. do not count as characters for this). Equivalent to moving
2481 * through the results of gtk_text_iter_get_text (), rather than
2482 * gtk_text_iter_get_slice ().
2484 * Return value: whether @iter moved and is dereferenceable
2487 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2496 * gtk_text_iter_forward_line:
2497 * @iter: an iterator
2499 * Moves @iter to the start of the next line. If the iter is already on the
2500 * last line of the buffer, moves the iter to the end of the current line.
2501 * If after the operation, the iter is at the end of the buffer and not
2502 * dereferencable, returns %FALSE. Otherwise, returns %TRUE.
2504 * Return value: whether @iter can be dereferenced
2507 gtk_text_iter_forward_line (GtkTextIter *iter)
2509 GtkTextRealIter *real;
2511 g_return_val_if_fail (iter != NULL, FALSE);
2513 real = gtk_text_iter_make_real (iter);
2518 check_invariants (iter);
2520 if (forward_line_leaving_caches_unmodified (real))
2522 invalidate_char_index (real);
2523 adjust_line_number (real, 1);
2525 check_invariants (iter);
2527 if (gtk_text_iter_is_end (iter))
2534 /* On the last line, move to end of it */
2536 if (!gtk_text_iter_is_end (iter))
2537 gtk_text_iter_forward_to_end (iter);
2539 check_invariants (iter);
2545 * gtk_text_iter_backward_line:
2546 * @iter: an iterator
2548 * Moves @iter to the start of the previous line. Returns %TRUE if
2549 * @iter could be moved; i.e. if @iter was at character offset 0, this
2550 * function returns %FALSE. Therefore if @iter was already on line 0,
2551 * but not at the start of the line, @iter is snapped to the start of
2552 * the line and the function returns %TRUE. (Note that this implies that
2553 * in a loop calling this function, the line number may not change on
2554 * every iteration, if your first iteration is on line 0.)
2556 * Return value: whether @iter moved
2559 gtk_text_iter_backward_line (GtkTextIter *iter)
2561 GtkTextLine *new_line;
2562 GtkTextRealIter *real;
2563 gboolean offset_will_change;
2566 g_return_val_if_fail (iter != NULL, FALSE);
2568 real = gtk_text_iter_make_real (iter);
2573 check_invariants (iter);
2575 new_line = _gtk_text_line_previous (real->line);
2577 offset_will_change = FALSE;
2578 if (real->line_char_offset > 0)
2579 offset_will_change = TRUE;
2581 if (new_line != NULL)
2583 real->line = new_line;
2585 adjust_line_number (real, -1);
2589 if (!offset_will_change)
2593 invalidate_char_index (real);
2595 real->line_byte_offset = 0;
2596 real->line_char_offset = 0;
2598 real->segment_byte_offset = 0;
2599 real->segment_char_offset = 0;
2601 /* Find first segment in line */
2602 real->any_segment = real->line->segments;
2603 real->segment = _gtk_text_line_byte_to_segment (real->line,
2606 g_assert (offset == 0);
2608 /* Note that if we are on the first line, we snap to the start of
2609 * the first line and return TRUE, so TRUE means the iterator
2610 * changed, not that the line changed; this is maybe a bit
2611 * weird. I'm not sure there's an obvious right thing to do though.
2614 check_invariants (iter);
2621 * gtk_text_iter_forward_lines:
2622 * @iter: a #GtkTextIter
2623 * @count: number of lines to move forward
2625 * Moves @count lines forward, if possible (if @count would move
2626 * past the start or end of the buffer, moves to the start or end of
2627 * the buffer). The return value indicates whether the iterator moved
2628 * onto a dereferenceable position; if the iterator didn't move, or
2629 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2630 * the function does nothing and returns %FALSE. If @count is negative,
2631 * moves backward by 0 - @count lines.
2633 * Return value: whether @iter moved and is dereferenceable
2636 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2638 FIX_OVERFLOWS (count);
2641 return gtk_text_iter_backward_lines (iter, 0 - count);
2642 else if (count == 0)
2644 else if (count == 1)
2646 check_invariants (iter);
2647 return gtk_text_iter_forward_line (iter);
2653 if (gtk_text_iter_is_end (iter))
2656 old_line = gtk_text_iter_get_line (iter);
2658 gtk_text_iter_set_line (iter, old_line + count);
2660 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2662 /* count went past the last line, so move to end of last line */
2663 if (!gtk_text_iter_is_end (iter))
2664 gtk_text_iter_forward_to_end (iter);
2667 return !gtk_text_iter_is_end (iter);
2672 * gtk_text_iter_backward_lines:
2673 * @iter: a #GtkTextIter
2674 * @count: number of lines to move backward
2676 * Moves @count lines backward, if possible (if @count would move
2677 * past the start or end of the buffer, moves to the start or end of
2678 * the buffer). The return value indicates whether the iterator moved
2679 * onto a dereferenceable position; if the iterator didn't move, or
2680 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2681 * the function does nothing and returns %FALSE. If @count is negative,
2682 * moves forward by 0 - @count lines.
2684 * Return value: whether @iter moved and is dereferenceable
2687 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2689 FIX_OVERFLOWS (count);
2692 return gtk_text_iter_forward_lines (iter, 0 - count);
2693 else if (count == 0)
2695 else if (count == 1)
2697 return gtk_text_iter_backward_line (iter);
2703 old_line = gtk_text_iter_get_line (iter);
2705 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2707 return (gtk_text_iter_get_line (iter) != old_line);
2712 * gtk_text_iter_forward_visible_line:
2713 * @iter: an iterator
2715 * Moves @iter to the start of the next visible line. Returns %TRUE if there
2716 * was a next line to move to, and %FALSE if @iter was simply moved to
2717 * the end of the buffer and is now not dereferenceable, or if @iter was
2718 * already at the end of the buffer.
2720 * Return value: whether @iter can be dereferenced
2725 gtk_text_iter_forward_visible_line (GtkTextIter *iter)
2727 while (gtk_text_iter_forward_line (iter))
2729 if (!_gtk_text_btree_char_is_invisible (iter))
2735 if (!gtk_text_iter_forward_char (iter))
2738 if (!_gtk_text_btree_char_is_invisible (iter))
2741 while (!gtk_text_iter_ends_line (iter));
2749 * gtk_text_iter_backward_visible_line:
2750 * @iter: an iterator
2752 * Moves @iter to the start of the previous visible line. Returns %TRUE if
2753 * @iter could be moved; i.e. if @iter was at character offset 0, this
2754 * function returns %FALSE. Therefore if @iter was already on line 0,
2755 * but not at the start of the line, @iter is snapped to the start of
2756 * the line and the function returns %TRUE. (Note that this implies that
2757 * in a loop calling this function, the line number may not change on
2758 * every iteration, if your first iteration is on line 0.)
2760 * Return value: whether @iter moved
2765 gtk_text_iter_backward_visible_line (GtkTextIter *iter)
2767 while (gtk_text_iter_backward_line (iter))
2769 if (!_gtk_text_btree_char_is_invisible (iter))
2775 if (!gtk_text_iter_backward_char (iter))
2778 if (!_gtk_text_btree_char_is_invisible (iter))
2781 while (!gtk_text_iter_starts_line (iter));
2789 * gtk_text_iter_forward_visible_lines:
2790 * @iter: a #GtkTextIter
2791 * @count: number of lines to move forward
2793 * Moves @count visible lines forward, if possible (if @count would move
2794 * past the start or end of the buffer, moves to the start or end of
2795 * the buffer). The return value indicates whether the iterator moved
2796 * onto a dereferenceable position; if the iterator didn't move, or
2797 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2798 * the function does nothing and returns %FALSE. If @count is negative,
2799 * moves backward by 0 - @count lines.
2801 * Return value: whether @iter moved and is dereferenceable
2806 gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
2809 FIX_OVERFLOWS (count);
2812 return gtk_text_iter_backward_visible_lines (iter, 0 - count);
2813 else if (count == 0)
2815 else if (count == 1)
2817 check_invariants (iter);
2818 return gtk_text_iter_forward_visible_line (iter);
2822 while (gtk_text_iter_forward_visible_line (iter) && count > 0)
2829 * gtk_text_iter_backward_visible_lines:
2830 * @iter: a #GtkTextIter
2831 * @count: number of lines to move backward
2833 * Moves @count visible lines backward, if possible (if @count would move
2834 * past the start or end of the buffer, moves to the start or end of
2835 * the buffer). The return value indicates whether the iterator moved
2836 * onto a dereferenceable position; if the iterator didn't move, or
2837 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2838 * the function does nothing and returns %FALSE. If @count is negative,
2839 * moves forward by 0 - @count lines.
2841 * Return value: whether @iter moved and is dereferenceable
2846 gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
2849 FIX_OVERFLOWS (count);
2852 return gtk_text_iter_forward_visible_lines (iter, 0 - count);
2853 else if (count == 0)
2855 else if (count == 1)
2857 return gtk_text_iter_backward_visible_line (iter);
2861 while (gtk_text_iter_backward_visible_line (iter) && count > 0)
2867 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2872 gboolean already_moved_initially);
2874 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2882 find_word_end_func (const PangoLogAttr *attrs,
2887 gboolean already_moved_initially)
2889 if (!already_moved_initially)
2892 /* Find end of next word */
2893 while (offset < min_offset + len &&
2894 !attrs[offset].is_word_end)
2897 *found_offset = offset;
2899 return offset < min_offset + len;
2903 is_word_end_func (const PangoLogAttr *attrs,
2908 return attrs[offset].is_word_end;
2912 find_word_start_func (const PangoLogAttr *attrs,
2917 gboolean already_moved_initially)
2919 if (!already_moved_initially)
2922 /* Find start of prev word */
2923 while (offset >= min_offset &&
2924 !attrs[offset].is_word_start)
2927 *found_offset = offset;
2929 return offset >= min_offset;
2933 is_word_start_func (const PangoLogAttr *attrs,
2938 return attrs[offset].is_word_start;
2942 inside_word_func (const PangoLogAttr *attrs,
2947 /* Find next word start or end */
2948 while (offset >= min_offset &&
2949 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2953 return attrs[offset].is_word_start;
2958 /* Sentence funcs */
2961 find_sentence_end_func (const PangoLogAttr *attrs,
2966 gboolean already_moved_initially)
2968 if (!already_moved_initially)
2971 /* Find end of next sentence */
2972 while (offset < min_offset + len &&
2973 !attrs[offset].is_sentence_end)
2976 *found_offset = offset;
2978 return offset < min_offset + len;
2982 is_sentence_end_func (const PangoLogAttr *attrs,
2987 return attrs[offset].is_sentence_end;
2991 find_sentence_start_func (const PangoLogAttr *attrs,
2996 gboolean already_moved_initially)
2998 if (!already_moved_initially)
3001 /* Find start of prev sentence */
3002 while (offset >= min_offset &&
3003 !attrs[offset].is_sentence_start)
3006 *found_offset = offset;
3008 return offset >= min_offset;
3012 is_sentence_start_func (const PangoLogAttr *attrs,
3017 return attrs[offset].is_sentence_start;
3021 inside_sentence_func (const PangoLogAttr *attrs,
3026 /* Find next sentence start or end */
3027 while (offset >= min_offset &&
3028 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
3031 return attrs[offset].is_sentence_start;
3035 test_log_attrs (const GtkTextIter *iter,
3036 TestLogAttrFunc func)
3039 const PangoLogAttr *attrs;
3041 gboolean result = FALSE;
3043 g_return_val_if_fail (iter != NULL, FALSE);
3045 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3048 offset = gtk_text_iter_get_line_offset (iter);
3050 /* char_len may be 0 and attrs will be NULL if so, if
3051 * iter is the end iter and the last line is empty.
3053 * offset may be equal to char_len, since attrs contains an entry
3054 * for one past the end
3057 if (attrs && offset <= char_len)
3058 result = (* func) (attrs, offset, 0, char_len);
3064 find_line_log_attrs (const GtkTextIter *iter,
3065 FindLogAttrFunc func,
3067 gboolean already_moved_initially)
3070 const PangoLogAttr *attrs;
3072 gboolean result = FALSE;
3074 g_return_val_if_fail (iter != NULL, FALSE);
3076 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3079 offset = gtk_text_iter_get_line_offset (iter);
3081 /* char_len may be 0 and attrs will be NULL if so, if
3082 * iter is the end iter and the last line is empty
3086 result = (* func) (attrs, offset, 0, char_len, found_offset,
3087 already_moved_initially);
3092 /* FIXME this function is very, very gratuitously slow */
3094 find_by_log_attrs (GtkTextIter *iter,
3095 FindLogAttrFunc func,
3097 gboolean already_moved_initially)
3101 gboolean found = FALSE;
3103 g_return_val_if_fail (iter != NULL, FALSE);
3107 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
3113 if (gtk_text_iter_forward_line (iter))
3114 return find_by_log_attrs (iter, func, forward,
3121 /* go to end of previous line. need to check that
3122 * line is > 0 because backward_line snaps to start of
3123 * line 0 if it's on line 0
3125 if (gtk_text_iter_get_line (iter) > 0 &&
3126 gtk_text_iter_backward_line (iter))
3128 if (!gtk_text_iter_ends_line (iter))
3129 gtk_text_iter_forward_to_line_end (iter);
3131 return find_by_log_attrs (iter, func, forward,
3140 gtk_text_iter_set_line_offset (iter, offset);
3143 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
3144 !gtk_text_iter_is_end (iter);
3149 find_visible_by_log_attrs (GtkTextIter *iter,
3150 FindLogAttrFunc func,
3152 gboolean already_moved_initially)
3156 g_return_val_if_fail (iter != NULL, FALSE);
3160 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3162 if (!_gtk_text_btree_char_is_invisible (&pos))
3172 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3173 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3176 move_multiple_steps (GtkTextIter *iter,
3178 OneStepFunc step_forward,
3179 MultipleStepFunc n_steps_backward)
3181 g_return_val_if_fail (iter != NULL, FALSE);
3183 FIX_OVERFLOWS (count);
3189 return n_steps_backward (iter, -count);
3191 if (!step_forward (iter))
3197 if (!step_forward (iter))
3202 return !gtk_text_iter_is_end (iter);
3207 * gtk_text_iter_forward_word_end:
3208 * @iter: a #GtkTextIter
3210 * Moves forward to the next word end. (If @iter is currently on a
3211 * word end, moves forward to the next one after that.) Word breaks
3212 * are determined by Pango and should be correct for nearly any
3213 * language (if not, the correct fix would be to the Pango word break
3216 * Return value: %TRUE if @iter moved and is not the end iterator
3219 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3221 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3225 * gtk_text_iter_backward_word_start:
3226 * @iter: a #GtkTextIter
3228 * Moves backward to the previous word start. (If @iter is currently on a
3229 * word start, moves backward to the next one after that.) Word breaks
3230 * are determined by Pango and should be correct for nearly any
3231 * language (if not, the correct fix would be to the Pango word break
3234 * Return value: %TRUE if @iter moved and is not the end iterator
3237 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3239 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3242 /* FIXME a loop around a truly slow function means
3243 * a truly spectacularly slow function.
3247 * gtk_text_iter_forward_word_ends:
3248 * @iter: a #GtkTextIter
3249 * @count: number of times to move
3251 * Calls gtk_text_iter_forward_word_end() up to @count times.
3253 * Return value: %TRUE if @iter moved and is not the end iterator
3256 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3259 return move_multiple_steps (iter, count,
3260 gtk_text_iter_forward_word_end,
3261 gtk_text_iter_backward_word_starts);
3265 * gtk_text_iter_backward_word_starts:
3266 * @iter: a #GtkTextIter
3267 * @count: number of times to move
3269 * Calls gtk_text_iter_backward_word_start() up to @count times.
3271 * Return value: %TRUE if @iter moved and is not the end iterator
3274 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3277 return move_multiple_steps (iter, count,
3278 gtk_text_iter_backward_word_start,
3279 gtk_text_iter_forward_word_ends);
3283 * gtk_text_iter_forward_visible_word_end:
3284 * @iter: a #GtkTextIter
3286 * Moves forward to the next visible word end. (If @iter is currently on a
3287 * word end, moves forward to the next one after that.) Word breaks
3288 * are determined by Pango and should be correct for nearly any
3289 * language (if not, the correct fix would be to the Pango word break
3292 * Return value: %TRUE if @iter moved and is not the end iterator
3297 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3299 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3303 * gtk_text_iter_backward_visible_word_start:
3304 * @iter: a #GtkTextIter
3306 * Moves backward to the previous visible word start. (If @iter is currently
3307 * on a word start, moves backward to the next one after that.) Word breaks
3308 * are determined by Pango and should be correct for nearly any
3309 * language (if not, the correct fix would be to the Pango word break
3312 * Return value: %TRUE if @iter moved and is not the end iterator
3317 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3319 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3323 * gtk_text_iter_forward_visible_word_ends:
3324 * @iter: a #GtkTextIter
3325 * @count: number of times to move
3327 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3329 * Return value: %TRUE if @iter moved and is not the end iterator
3334 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3337 return move_multiple_steps (iter, count,
3338 gtk_text_iter_forward_visible_word_end,
3339 gtk_text_iter_backward_visible_word_starts);
3343 * gtk_text_iter_backward_visible_word_starts:
3344 * @iter: a #GtkTextIter
3345 * @count: number of times to move
3347 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3349 * Return value: %TRUE if @iter moved and is not the end iterator
3354 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3357 return move_multiple_steps (iter, count,
3358 gtk_text_iter_backward_visible_word_start,
3359 gtk_text_iter_forward_visible_word_ends);
3363 * gtk_text_iter_starts_word:
3364 * @iter: a #GtkTextIter
3366 * Determines whether @iter begins a natural-language word. Word
3367 * breaks are determined by Pango and should be correct for nearly any
3368 * language (if not, the correct fix would be to the Pango word break
3371 * Return value: %TRUE if @iter is at the start of a word
3374 gtk_text_iter_starts_word (const GtkTextIter *iter)
3376 return test_log_attrs (iter, is_word_start_func);
3380 * gtk_text_iter_ends_word:
3381 * @iter: a #GtkTextIter
3383 * Determines whether @iter ends a natural-language word. Word breaks
3384 * are determined by Pango and should be correct for nearly any
3385 * language (if not, the correct fix would be to the Pango word break
3388 * Return value: %TRUE if @iter is at the end of a word
3391 gtk_text_iter_ends_word (const GtkTextIter *iter)
3393 return test_log_attrs (iter, is_word_end_func);
3397 * gtk_text_iter_inside_word:
3398 * @iter: a #GtkTextIter
3400 * Determines whether @iter is inside a natural-language word (as
3401 * opposed to say inside some whitespace). Word breaks are determined
3402 * by Pango and should be correct for nearly any language (if not, the
3403 * correct fix would be to the Pango word break algorithms).
3405 * Return value: %TRUE if @iter is inside a word
3408 gtk_text_iter_inside_word (const GtkTextIter *iter)
3410 return test_log_attrs (iter, inside_word_func);
3414 * gtk_text_iter_starts_sentence:
3415 * @iter: a #GtkTextIter
3417 * Determines whether @iter begins a sentence. Sentence boundaries are
3418 * determined by Pango and should be correct for nearly any language
3419 * (if not, the correct fix would be to the Pango text boundary
3422 * Return value: %TRUE if @iter is at the start of a sentence.
3425 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3427 return test_log_attrs (iter, is_sentence_start_func);
3431 * gtk_text_iter_ends_sentence:
3432 * @iter: a #GtkTextIter
3434 * Determines whether @iter ends a sentence. Sentence boundaries are
3435 * determined by Pango and should be correct for nearly any language
3436 * (if not, the correct fix would be to the Pango text boundary
3439 * Return value: %TRUE if @iter is at the end of a sentence.
3442 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3444 return test_log_attrs (iter, is_sentence_end_func);
3448 * gtk_text_iter_inside_sentence:
3449 * @iter: a #GtkTextIter
3451 * Determines whether @iter is inside a sentence (as opposed to in
3452 * between two sentences, e.g. after a period and before the first
3453 * letter of the next sentence). Sentence boundaries are determined
3454 * by Pango and should be correct for nearly any language (if not, the
3455 * correct fix would be to the Pango text boundary algorithms).
3457 * Return value: %TRUE if @iter is inside a sentence.
3460 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3462 return test_log_attrs (iter, inside_sentence_func);
3466 * gtk_text_iter_forward_sentence_end:
3467 * @iter: a #GtkTextIter
3469 * Moves forward to the next sentence end. (If @iter is at the end of
3470 * a sentence, moves to the next end of sentence.) Sentence
3471 * boundaries are determined by Pango and should be correct for nearly
3472 * any language (if not, the correct fix would be to the Pango text
3473 * boundary algorithms).
3475 * Return value: %TRUE if @iter moved and is not the end iterator
3478 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3480 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3484 * gtk_text_iter_backward_sentence_start:
3485 * @iter: a #GtkTextIter
3487 * Moves backward to the previous sentence start; if @iter is already at
3488 * the start of a sentence, moves backward to the next one. Sentence
3489 * boundaries are determined by Pango and should be correct for nearly
3490 * any language (if not, the correct fix would be to the Pango text
3491 * boundary algorithms).
3493 * Return value: %TRUE if @iter moved and is not the end iterator
3496 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3498 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3501 /* FIXME a loop around a truly slow function means
3502 * a truly spectacularly slow function.
3505 * gtk_text_iter_forward_sentence_ends:
3506 * @iter: a #GtkTextIter
3507 * @count: number of sentences to move
3509 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3510 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3511 * negative, moves backward instead of forward.
3513 * Return value: %TRUE if @iter moved and is not the end iterator
3516 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3519 return move_multiple_steps (iter, count,
3520 gtk_text_iter_forward_sentence_end,
3521 gtk_text_iter_backward_sentence_starts);
3525 * gtk_text_iter_backward_sentence_starts:
3526 * @iter: a #GtkTextIter
3527 * @count: number of sentences to move
3529 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3530 * or until it returns %FALSE. If @count is negative, moves forward
3531 * instead of backward.
3533 * Return value: %TRUE if @iter moved and is not the end iterator
3536 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3539 return move_multiple_steps (iter, count,
3540 gtk_text_iter_backward_sentence_start,
3541 gtk_text_iter_forward_sentence_ends);
3545 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3550 gboolean already_moved_initially)
3552 if (!already_moved_initially)
3555 while (offset < (min_offset + len) &&
3556 !attrs[offset].is_cursor_position)
3559 *found_offset = offset;
3561 return offset < (min_offset + len);
3565 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3570 gboolean already_moved_initially)
3572 if (!already_moved_initially)
3575 while (offset > min_offset &&
3576 !attrs[offset].is_cursor_position)
3579 *found_offset = offset;
3581 return offset >= min_offset;
3585 is_cursor_pos_func (const PangoLogAttr *attrs,
3590 return attrs[offset].is_cursor_position;
3594 * gtk_text_iter_forward_cursor_position:
3595 * @iter: a #GtkTextIter
3597 * Moves @iter forward by a single cursor position. Cursor positions
3598 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3599 * surprisingly, there may not be a cursor position between all
3600 * characters. The most common example for European languages would be
3601 * a carriage return/newline sequence. For some Unicode characters,
3602 * the equivalent of say the letter "a" with an accent mark will be
3603 * represented as two characters, first the letter then a "combining
3604 * mark" that causes the accent to be rendered; so the cursor can't go
3605 * between those two characters. See also the #PangoLogAttr structure and
3606 * pango_break() function.
3608 * Return value: %TRUE if we moved and the new position is dereferenceable
3611 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3613 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3617 * gtk_text_iter_backward_cursor_position:
3618 * @iter: a #GtkTextIter
3620 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3622 * Return value: %TRUE if we moved
3625 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3627 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3631 * gtk_text_iter_forward_cursor_positions:
3632 * @iter: a #GtkTextIter
3633 * @count: number of positions to move
3635 * Moves up to @count cursor positions. See
3636 * gtk_text_iter_forward_cursor_position() for details.
3638 * Return value: %TRUE if we moved and the new position is dereferenceable
3641 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3644 return move_multiple_steps (iter, count,
3645 gtk_text_iter_forward_cursor_position,
3646 gtk_text_iter_backward_cursor_positions);
3650 * gtk_text_iter_backward_cursor_positions:
3651 * @iter: a #GtkTextIter
3652 * @count: number of positions to move
3654 * Moves up to @count cursor positions. See
3655 * gtk_text_iter_forward_cursor_position() for details.
3657 * Return value: %TRUE if we moved and the new position is dereferenceable
3660 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3663 return move_multiple_steps (iter, count,
3664 gtk_text_iter_backward_cursor_position,
3665 gtk_text_iter_forward_cursor_positions);
3669 * gtk_text_iter_forward_visible_cursor_position:
3670 * @iter: a #GtkTextIter
3672 * Moves @iter forward to the next visible cursor position. See
3673 * gtk_text_iter_forward_cursor_position() for details.
3675 * Return value: %TRUE if we moved and the new position is dereferenceable
3680 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3682 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3686 * gtk_text_iter_backward_visible_cursor_position:
3687 * @iter: a #GtkTextIter
3689 * Moves @iter forward to the previous visible cursor position. See
3690 * gtk_text_iter_backward_cursor_position() for details.
3692 * Return value: %TRUE if we moved and the new position is dereferenceable
3697 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3699 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3703 * gtk_text_iter_forward_visible_cursor_positions:
3704 * @iter: a #GtkTextIter
3705 * @count: number of positions to move
3707 * Moves up to @count visible cursor positions. See
3708 * gtk_text_iter_forward_cursor_position() for details.
3710 * Return value: %TRUE if we moved and the new position is dereferenceable
3715 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3718 return move_multiple_steps (iter, count,
3719 gtk_text_iter_forward_visible_cursor_position,
3720 gtk_text_iter_backward_visible_cursor_positions);
3724 * gtk_text_iter_backward_visible_cursor_positions:
3725 * @iter: a #GtkTextIter
3726 * @count: number of positions to move
3728 * Moves up to @count visible cursor positions. See
3729 * gtk_text_iter_backward_cursor_position() for details.
3731 * Return value: %TRUE if we moved and the new position is dereferenceable
3736 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3739 return move_multiple_steps (iter, count,
3740 gtk_text_iter_backward_visible_cursor_position,
3741 gtk_text_iter_forward_visible_cursor_positions);
3745 * gtk_text_iter_is_cursor_position:
3746 * @iter: a #GtkTextIter
3748 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3749 * pango_break() for details on what a cursor position is.
3751 * Return value: %TRUE if the cursor can be placed at @iter
3754 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3756 return test_log_attrs (iter, is_cursor_pos_func);
3760 * gtk_text_iter_set_line_offset:
3761 * @iter: a #GtkTextIter
3762 * @char_on_line: a character offset relative to the start of @iter's current line
3764 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3765 * (not byte) offset. The given character offset must be less than or
3766 * equal to the number of characters in the line; if equal, @iter
3767 * moves to the start of the next line. See
3768 * gtk_text_iter_set_line_index() if you have a byte index rather than
3769 * a character offset.
3773 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3776 GtkTextRealIter *real;
3779 g_return_if_fail (iter != NULL);
3781 real = gtk_text_iter_make_surreal (iter);
3786 check_invariants (iter);
3788 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3790 g_return_if_fail (char_on_line <= chars_in_line);
3792 if (char_on_line < chars_in_line)
3793 iter_set_from_char_offset (real, real->line, char_on_line);
3795 gtk_text_iter_forward_line (iter); /* set to start of next line */
3797 check_invariants (iter);
3801 * gtk_text_iter_set_line_index:
3802 * @iter: a #GtkTextIter
3803 * @byte_on_line: a byte index relative to the start of @iter's current line
3805 * Same as gtk_text_iter_set_line_offset(), but works with a
3806 * <emphasis>byte</emphasis> index. The given byte index must be at
3807 * the start of a character, it can't be in the middle of a UTF-8
3808 * encoded character.
3812 gtk_text_iter_set_line_index (GtkTextIter *iter,
3815 GtkTextRealIter *real;
3818 g_return_if_fail (iter != NULL);
3820 real = gtk_text_iter_make_surreal (iter);
3825 check_invariants (iter);
3827 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3829 g_return_if_fail (byte_on_line <= bytes_in_line);
3831 if (byte_on_line < bytes_in_line)
3832 iter_set_from_byte_offset (real, real->line, byte_on_line);
3834 gtk_text_iter_forward_line (iter);
3836 if (real->segment->type == >k_text_char_type &&
3837 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3838 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3839 "character; this will crash the text buffer. "
3840 "Byte indexes must refer to the start of a character.",
3841 G_STRLOC, byte_on_line);
3843 check_invariants (iter);
3848 * gtk_text_iter_set_visible_line_offset:
3849 * @iter: a #GtkTextIter
3850 * @char_on_line: a character offset
3852 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3853 * characters, i.e. text with a tag making it invisible is not
3854 * counted in the offset.
3857 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3860 gint chars_seen = 0;
3863 g_return_if_fail (iter != NULL);
3865 gtk_text_iter_set_line_offset (iter, 0);
3869 /* For now we use a ludicrously slow implementation */
3870 while (chars_seen < char_on_line)
3872 if (!_gtk_text_btree_char_is_invisible (&pos))
3875 if (!gtk_text_iter_forward_char (&pos))
3878 if (chars_seen == char_on_line)
3882 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3885 gtk_text_iter_forward_line (iter);
3889 * gtk_text_iter_set_visible_line_index:
3890 * @iter: a #GtkTextIter
3891 * @byte_on_line: a byte index
3893 * Like gtk_text_iter_set_line_index(), but the index is in visible
3894 * bytes, i.e. text with a tag making it invisible is not counted
3898 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3901 GtkTextRealIter *real;
3904 GtkTextLineSegment *seg;
3906 g_return_if_fail (iter != NULL);
3908 gtk_text_iter_set_line_offset (iter, 0);
3912 real = gtk_text_iter_make_real (&pos);
3917 ensure_byte_offsets (real);
3919 check_invariants (&pos);
3921 seg = _gtk_text_iter_get_indexable_segment (&pos);
3923 while (seg != NULL && byte_on_line > 0)
3925 if (!_gtk_text_btree_char_is_invisible (&pos))
3927 if (byte_on_line < seg->byte_count)
3929 iter_set_from_byte_offset (real, real->line, offset + byte_on_line);
3934 byte_on_line -= seg->byte_count;
3937 offset += seg->byte_count;
3938 _gtk_text_iter_forward_indexable_segment (&pos);
3939 seg = _gtk_text_iter_get_indexable_segment (&pos);
3942 if (byte_on_line == 0)
3945 gtk_text_iter_forward_line (iter);
3949 * gtk_text_iter_set_line:
3950 * @iter: a #GtkTextIter
3951 * @line_number: line number (counted from 0)
3953 * Moves iterator @iter to the start of the line @line_number. If
3954 * @line_number is negative or larger than the number of lines in the
3955 * buffer, moves @iter to the start of the last line in the buffer.
3959 gtk_text_iter_set_line (GtkTextIter *iter,
3964 GtkTextRealIter *real;
3966 g_return_if_fail (iter != NULL);
3968 real = gtk_text_iter_make_surreal (iter);
3973 check_invariants (iter);
3975 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3977 iter_set_from_char_offset (real, line, 0);
3979 /* We might as well cache this, since we know it. */
3980 real->cached_line_number = real_line;
3982 check_invariants (iter);
3986 * gtk_text_iter_set_offset:
3987 * @iter: a #GtkTextIter
3988 * @char_offset: a character number
3990 * Sets @iter to point to @char_offset. @char_offset counts from the start
3991 * of the entire text buffer, starting with 0.
3994 gtk_text_iter_set_offset (GtkTextIter *iter,
3998 GtkTextRealIter *real;
4000 gint real_char_index;
4002 g_return_if_fail (iter != NULL);
4004 real = gtk_text_iter_make_surreal (iter);
4009 check_invariants (iter);
4011 if (real->cached_char_index >= 0 &&
4012 real->cached_char_index == char_offset)
4015 line = _gtk_text_btree_get_line_at_char (real->tree,
4020 iter_set_from_char_offset (real, line, real_char_index - line_start);
4022 /* Go ahead and cache this since we have it. */
4023 real->cached_char_index = real_char_index;
4025 check_invariants (iter);
4029 * gtk_text_iter_forward_to_end:
4030 * @iter: a #GtkTextIter
4032 * Moves @iter forward to the "end iterator," which points one past the last
4033 * valid character in the buffer. gtk_text_iter_get_char() called on the
4034 * end iterator returns 0, which is convenient for writing loops.
4037 gtk_text_iter_forward_to_end (GtkTextIter *iter)
4039 GtkTextBuffer *buffer;
4040 GtkTextRealIter *real;
4042 g_return_if_fail (iter != NULL);
4044 real = gtk_text_iter_make_surreal (iter);
4049 buffer = _gtk_text_btree_get_buffer (real->tree);
4051 gtk_text_buffer_get_end_iter (buffer, iter);
4054 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
4055 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
4056 * If all else fails we could cache the para delimiter pos in the iter.
4057 * I think forward_to_line_end() actually gets called fairly often.
4060 find_paragraph_delimiter_for_line (GtkTextIter *iter)
4065 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
4066 _gtk_text_iter_get_btree (&end)))
4068 gtk_text_iter_forward_to_end (&end);
4072 /* if we aren't on the last line, go forward to start of next line, then scan
4073 * back for the delimiters on the previous line
4075 gtk_text_iter_forward_line (&end);
4076 gtk_text_iter_backward_char (&end);
4077 while (!gtk_text_iter_ends_line (&end))
4078 gtk_text_iter_backward_char (&end);
4081 return gtk_text_iter_get_line_offset (&end);
4085 * gtk_text_iter_forward_to_line_end:
4086 * @iter: a #GtkTextIter
4088 * Moves the iterator to point to the paragraph delimiter characters,
4089 * which will be either a newline, a carriage return, a carriage
4090 * return/newline in sequence, or the Unicode paragraph separator
4091 * character. If the iterator is already at the paragraph delimiter
4092 * characters, moves to the paragraph delimiter characters for the
4093 * next line. If @iter is on the last line in the buffer, which does
4094 * not end in paragraph delimiters, moves to the end iterator (end of
4095 * the last line), and returns %FALSE.
4097 * Return value: %TRUE if we moved and the new location is not the end iterator
4100 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
4102 gint current_offset;
4106 g_return_val_if_fail (iter != NULL, FALSE);
4108 current_offset = gtk_text_iter_get_line_offset (iter);
4109 new_offset = find_paragraph_delimiter_for_line (iter);
4111 if (current_offset < new_offset)
4113 /* Move to end of this line. */
4114 gtk_text_iter_set_line_offset (iter, new_offset);
4115 return !gtk_text_iter_is_end (iter);
4119 /* Move to end of next line. */
4120 if (gtk_text_iter_forward_line (iter))
4122 /* We don't want to move past all
4125 if (!gtk_text_iter_ends_line (iter))
4126 gtk_text_iter_forward_to_line_end (iter);
4127 return !gtk_text_iter_is_end (iter);
4135 * gtk_text_iter_forward_to_tag_toggle:
4136 * @iter: a #GtkTextIter
4137 * @tag: (allow-none): a #GtkTextTag, or %NULL
4139 * Moves forward to the next toggle (on or off) of the
4140 * #GtkTextTag @tag, or to the next toggle of any tag if
4141 * @tag is %NULL. If no matching tag toggles are found,
4142 * returns %FALSE, otherwise %TRUE. Does not return toggles
4143 * located at @iter, only toggles after @iter. Sets @iter to
4144 * the location of the toggle, or to the end of the buffer
4145 * if no toggle is found.
4147 * Return value: whether we found a tag toggle after @iter
4150 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4153 GtkTextLine *next_line;
4154 GtkTextLine *current_line;
4155 GtkTextRealIter *real;
4157 g_return_val_if_fail (iter != NULL, FALSE);
4159 real = gtk_text_iter_make_real (iter);
4164 check_invariants (iter);
4166 current_line = real->line;
4167 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4170 while (_gtk_text_iter_forward_indexable_segment (iter))
4172 /* If we went forward to a line that couldn't contain a toggle
4173 for the tag, then skip forward to a line that could contain
4174 it. This potentially skips huge hunks of the tree, so we
4175 aren't a purely linear search. */
4176 if (real->line != current_line)
4178 if (next_line == NULL)
4180 /* End of search. Set to end of buffer. */
4181 _gtk_text_btree_get_end_iter (real->tree, iter);
4185 if (real->line != next_line)
4186 iter_set_from_byte_offset (real, next_line, 0);
4188 current_line = real->line;
4189 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4194 if (gtk_text_iter_toggles_tag (iter, tag))
4196 /* If there's a toggle here, it isn't indexable so
4197 any_segment can't be the indexable segment. */
4198 g_assert (real->any_segment != real->segment);
4203 /* Check end iterator for tags */
4204 if (gtk_text_iter_toggles_tag (iter, tag))
4206 /* If there's a toggle here, it isn't indexable so
4207 any_segment can't be the indexable segment. */
4208 g_assert (real->any_segment != real->segment);
4212 /* Reached end of buffer */
4217 * gtk_text_iter_backward_to_tag_toggle:
4218 * @iter: a #GtkTextIter
4219 * @tag: (allow-none): a #GtkTextTag, or %NULL
4221 * Moves backward to the next toggle (on or off) of the
4222 * #GtkTextTag @tag, or to the next toggle of any tag if
4223 * @tag is %NULL. If no matching tag toggles are found,
4224 * returns %FALSE, otherwise %TRUE. Does not return toggles
4225 * located at @iter, only toggles before @iter. Sets @iter
4226 * to the location of the toggle, or the start of the buffer
4227 * if no toggle is found.
4229 * Return value: whether we found a tag toggle before @iter
4232 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4235 GtkTextLine *prev_line;
4236 GtkTextLine *current_line;
4237 GtkTextRealIter *real;
4239 g_return_val_if_fail (iter != NULL, FALSE);
4241 real = gtk_text_iter_make_real (iter);
4246 check_invariants (iter);
4248 current_line = real->line;
4249 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4253 /* If we're at segment start, go to the previous segment;
4254 * if mid-segment, snap to start of current segment.
4256 if (is_segment_start (real))
4258 if (!_gtk_text_iter_backward_indexable_segment (iter))
4263 ensure_char_offsets (real);
4265 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4271 /* If we went backward to a line that couldn't contain a toggle
4272 * for the tag, then skip backward further to a line that
4273 * could contain it. This potentially skips huge hunks of the
4274 * tree, so we aren't a purely linear search.
4276 if (real->line != current_line)
4278 if (prev_line == NULL)
4280 /* End of search. Set to start of buffer. */
4281 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4285 if (real->line != prev_line)
4287 /* Set to last segment in prev_line (could do this
4290 iter_set_from_byte_offset (real, prev_line, 0);
4292 while (!at_last_indexable_segment (real))
4293 _gtk_text_iter_forward_indexable_segment (iter);
4296 current_line = real->line;
4297 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4302 if (gtk_text_iter_toggles_tag (iter, tag))
4304 /* If there's a toggle here, it isn't indexable so
4305 * any_segment can't be the indexable segment.
4307 g_assert (real->any_segment != real->segment);
4311 while (_gtk_text_iter_backward_indexable_segment (iter));
4313 /* Reached front of buffer */
4318 matches_pred (GtkTextIter *iter,
4319 GtkTextCharPredicate pred,
4324 ch = gtk_text_iter_get_char (iter);
4326 return (*pred) (ch, user_data);
4330 * gtk_text_iter_forward_find_char:
4331 * @iter: a #GtkTextIter
4332 * @pred: (scope call): a function to be called on each character
4333 * @user_data: user data for @pred
4334 * @limit: (allow-none): search limit, or %NULL for none
4336 * Advances @iter, calling @pred on each character. If
4337 * @pred returns %TRUE, returns %TRUE and stops scanning.
4338 * If @pred never returns %TRUE, @iter is set to @limit if
4339 * @limit is non-%NULL, otherwise to the end iterator.
4341 * Return value: whether a match was found
4344 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4345 GtkTextCharPredicate pred,
4347 const GtkTextIter *limit)
4349 g_return_val_if_fail (iter != NULL, FALSE);
4350 g_return_val_if_fail (pred != NULL, FALSE);
4353 gtk_text_iter_compare (iter, limit) >= 0)
4356 while ((limit == NULL ||
4357 !gtk_text_iter_equal (limit, iter)) &&
4358 gtk_text_iter_forward_char (iter))
4360 if (matches_pred (iter, pred, user_data))
4368 * gtk_text_iter_backward_find_char:
4369 * @iter: a #GtkTextIter
4370 * @pred: (scope call): function to be called on each character
4371 * @user_data: user data for @pred
4372 * @limit: (allow-none): search limit, or %NULL for none
4374 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4376 * Return value: whether a match was found
4379 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4380 GtkTextCharPredicate pred,
4382 const GtkTextIter *limit)
4384 g_return_val_if_fail (iter != NULL, FALSE);
4385 g_return_val_if_fail (pred != NULL, FALSE);
4388 gtk_text_iter_compare (iter, limit) <= 0)
4391 while ((limit == NULL ||
4392 !gtk_text_iter_equal (limit, iter)) &&
4393 gtk_text_iter_backward_char (iter))
4395 if (matches_pred (iter, pred, user_data))
4403 forward_chars_with_skipping (GtkTextIter *iter,
4405 gboolean skip_invisible,
4406 gboolean skip_nontext,
4407 gboolean skip_decomp)
4412 g_return_if_fail (count >= 0);
4418 gboolean ignored = FALSE;
4420 /* minimal workaround to avoid the infinite loop of bug #168247. */
4421 if (gtk_text_iter_is_end (iter))
4425 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4430 _gtk_text_btree_char_is_invisible (iter))
4433 if (!ignored && skip_decomp)
4435 /* being UTF8 correct sucks: this accounts for extra
4436 offsets coming from canonical decompositions of
4437 UTF8 characters (e.g. accented characters) which
4438 g_utf8_normalize() performs */
4444 buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer);
4445 casefold = g_utf8_casefold (buffer, buffer_len);
4446 normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4447 i -= (g_utf8_strlen (normal, -1) - 1);
4452 gtk_text_iter_forward_char (iter);
4459 static const gchar *
4460 pointer_from_offset_skipping_decomp (const gchar *str,
4463 gchar *casefold, *normal;
4470 q = g_utf8_next_char (p);
4471 casefold = g_utf8_casefold (p, q - p);
4472 normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4473 offset -= g_utf8_strlen (normal, -1);
4483 exact_prefix_cmp (const gchar *string,
4484 const gchar *prefix,
4489 if (strncmp (string, prefix, prefix_len) != 0)
4491 if (string[prefix_len] == '\0')
4494 type = g_unichar_type (g_utf8_get_char (string + prefix_len));
4496 /* If string contains prefix, check that prefix is not followed
4497 * by a unicode mark symbol, e.g. that trailing 'a' in prefix
4498 * is not part of two-char a-with-hat symbol in string. */
4499 return type != G_UNICODE_SPACING_MARK &&
4500 type != G_UNICODE_ENCLOSING_MARK &&
4501 type != G_UNICODE_NON_SPACING_MARK;
4504 static const gchar *
4505 utf8_strcasestr (const gchar *haystack,
4506 const gchar *needle)
4510 const gchar *ret = NULL;
4513 gchar *caseless_haystack;
4516 g_return_val_if_fail (haystack != NULL, NULL);
4517 g_return_val_if_fail (needle != NULL, NULL);
4519 casefold = g_utf8_casefold (haystack, -1);
4520 caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4523 needle_len = g_utf8_strlen (needle, -1);
4524 haystack_len = g_utf8_strlen (caseless_haystack, -1);
4526 if (needle_len == 0)
4528 ret = (gchar *)haystack;
4532 if (haystack_len < needle_len)
4538 p = (gchar *)caseless_haystack;
4539 needle_len = strlen (needle);
4544 if (exact_prefix_cmp (p, needle, needle_len))
4546 ret = pointer_from_offset_skipping_decomp (haystack, i);
4550 p = g_utf8_next_char (p);
4555 g_free (caseless_haystack);
4560 static const gchar *
4561 utf8_strrcasestr (const gchar *haystack,
4562 const gchar *needle)
4566 const gchar *ret = NULL;
4569 gchar *caseless_haystack;
4572 g_return_val_if_fail (haystack != NULL, NULL);
4573 g_return_val_if_fail (needle != NULL, NULL);
4575 casefold = g_utf8_casefold (haystack, -1);
4576 caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4579 needle_len = g_utf8_strlen (needle, -1);
4580 haystack_len = g_utf8_strlen (caseless_haystack, -1);
4582 if (needle_len == 0)
4584 ret = (gchar *)haystack;
4588 if (haystack_len < needle_len)
4594 i = haystack_len - needle_len;
4595 p = g_utf8_offset_to_pointer (caseless_haystack, i);
4596 needle_len = strlen (needle);
4598 while (p >= caseless_haystack)
4600 if (exact_prefix_cmp (p, needle, needle_len))
4602 ret = pointer_from_offset_skipping_decomp (haystack, i);
4606 p = g_utf8_prev_char (p);
4611 g_free (caseless_haystack);
4616 /* normalizes caseless strings and returns true if @s2 matches
4619 utf8_caselessnmatch (const gchar *s1,
4625 gchar *normalized_s1;
4626 gchar *normalized_s2;
4629 gboolean ret = FALSE;
4631 g_return_val_if_fail (s1 != NULL, FALSE);
4632 g_return_val_if_fail (s2 != NULL, FALSE);
4633 g_return_val_if_fail (n1 > 0, FALSE);
4634 g_return_val_if_fail (n2 > 0, FALSE);
4636 casefold = g_utf8_casefold (s1, n1);
4637 normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4640 casefold = g_utf8_casefold (s2, n2);
4641 normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4644 len_s1 = strlen (normalized_s1);
4645 len_s2 = strlen (normalized_s2);
4647 if (len_s1 >= len_s2)
4648 ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0);
4650 g_free (normalized_s1);
4651 g_free (normalized_s2);
4657 lines_match (const GtkTextIter *start,
4658 const gchar **lines,
4659 gboolean visible_only,
4661 gboolean case_insensitive,
4662 GtkTextIter *match_start,
4663 GtkTextIter *match_end)
4670 if (*lines == NULL || **lines == '\0')
4673 *match_start = *start;
4676 *match_end = *start;
4681 gtk_text_iter_forward_line (&next);
4683 /* No more text in buffer, but *lines is nonempty */
4684 if (gtk_text_iter_equal (start, &next))
4692 line_text = gtk_text_iter_get_visible_slice (start, &next);
4694 line_text = gtk_text_iter_get_slice (start, &next);
4699 line_text = gtk_text_iter_get_visible_text (start, &next);
4701 line_text = gtk_text_iter_get_text (start, &next);
4704 if (match_start) /* if this is the first line we're matching */
4706 if (!case_insensitive)
4707 found = strstr (line_text, *lines);
4709 found = utf8_strcasestr (line_text, *lines);
4713 /* If it's not the first line, we have to match from the
4714 * start of the line.
4716 if ((!case_insensitive &&
4717 (strncmp (line_text, *lines, strlen (*lines)) == 0)) ||
4718 (case_insensitive &&
4719 utf8_caselessnmatch (line_text, *lines, strlen (line_text),
4734 /* Get offset to start of search string */
4735 offset = g_utf8_strlen (line_text, found - line_text);
4739 /* If match start needs to be returned, set it to the
4740 * start of the search string.
4742 forward_chars_with_skipping (&next, offset,
4743 visible_only, !slice, FALSE);
4745 *match_start = next;
4747 /* Go to end of search string */
4748 forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1),
4749 visible_only, !slice, TRUE);
4758 /* pass NULL for match_start, since we don't need to find the
4761 return lines_match (&next, lines, visible_only, slice, case_insensitive, NULL, match_end);
4764 /* strsplit () that retains the delimiter as part of the string. */
4766 strbreakup (const char *string,
4767 const char *delimiter,
4770 gboolean case_insensitive)
4772 GSList *string_list = NULL, *slist;
4773 gchar **str_array, *s;
4774 gchar *casefold, *new_string;
4777 g_return_val_if_fail (string != NULL, NULL);
4778 g_return_val_if_fail (delimiter != NULL, NULL);
4781 max_tokens = G_MAXINT;
4783 s = strstr (string, delimiter);
4786 guint delimiter_len = strlen (delimiter);
4792 len = s - string + delimiter_len;
4793 new_string = g_new (gchar, len + 1);
4794 strncpy (new_string, string, len);
4795 new_string[len] = 0;
4797 if (case_insensitive)
4799 casefold = g_utf8_casefold (new_string, -1);
4800 g_free (new_string);
4801 new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4805 string_list = g_slist_prepend (string_list, new_string);
4807 string = s + delimiter_len;
4808 s = strstr (string, delimiter);
4810 while (--max_tokens && s);
4816 if (case_insensitive)
4818 casefold = g_utf8_casefold (string, -1);
4819 new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4823 new_string = g_strdup (string);
4825 string_list = g_slist_prepend (string_list, new_string);
4828 str_array = g_new (gchar*, n);
4832 str_array[i--] = NULL;
4833 for (slist = string_list; slist; slist = slist->next)
4834 str_array[i--] = slist->data;
4836 g_slist_free (string_list);
4838 if (num_strings != NULL)
4839 *num_strings = n - 1;
4845 * gtk_text_iter_forward_search:
4846 * @iter: start of search
4847 * @str: a search string
4848 * @flags: flags affecting how the search is done
4849 * @match_start: (out caller-allocates) (allow-none): return location for start of match, or %NULL
4850 * @match_end: (out caller-allocates) (allow-none): return location for end of match, or %NULL
4851 * @limit: (allow-none): bound for the search, or %NULL for the end of the buffer
4853 * Searches forward for @str. Any match is returned by setting
4854 * @match_start to the first character of the match and @match_end to the
4855 * first character after the match. The search will not continue past
4856 * @limit. Note that a search is a linear or O(n) operation, so you
4857 * may wish to use @limit to avoid locking up your UI on large
4860 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4861 * have invisible text interspersed in @str. i.e. @str will be a
4862 * possibly-noncontiguous subsequence of the matched range. similarly,
4863 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4864 * pixbufs or child widgets mixed inside the matched range. If these
4865 * flags are not given, the match must be exact; the special 0xFFFC
4866 * character in @str will match embedded pixbufs or child widgets.
4867 * If you specify the #GTK_TEXT_SEARCH_CASE_INSENSITIVE flag, the text will
4868 * be matched regardless of what case it is in.
4870 * Return value: whether a match was found
4873 gtk_text_iter_forward_search (const GtkTextIter *iter,
4875 GtkTextSearchFlags flags,
4876 GtkTextIter *match_start,
4877 GtkTextIter *match_end,
4878 const GtkTextIter *limit)
4880 gchar **lines = NULL;
4882 gboolean retval = FALSE;
4884 gboolean visible_only;
4886 gboolean case_insensitive;
4888 g_return_val_if_fail (iter != NULL, FALSE);
4889 g_return_val_if_fail (str != NULL, FALSE);
4892 gtk_text_iter_compare (iter, limit) >= 0)
4897 /* If we can move one char, return the empty string there */
4900 if (gtk_text_iter_forward_char (&match))
4903 gtk_text_iter_equal (&match, limit))
4907 *match_start = match;
4916 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4917 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4918 case_insensitive = (flags & GTK_TEXT_SEARCH_CASE_INSENSITIVE) != 0;
4920 /* locate all lines */
4922 lines = strbreakup (str, "\n", -1, NULL, case_insensitive);
4928 /* This loop has an inefficient worst-case, where
4929 * gtk_text_iter_get_text () is called repeatedly on
4935 gtk_text_iter_compare (&search, limit) >= 0)
4938 if (lines_match (&search, (const gchar**)lines,
4939 visible_only, slice, case_insensitive, &match, &end))
4941 if (limit == NULL ||
4943 gtk_text_iter_compare (&end, limit) <= 0))
4948 *match_start = match;
4957 while (gtk_text_iter_forward_line (&search));
4959 g_strfreev ((gchar**)lines);
4965 vectors_equal_ignoring_trailing (gchar **vec1,
4967 gboolean case_insensitive)
4969 /* Ignores trailing chars in vec2's last line */
4981 if (!case_insensitive)
4983 if (strcmp (*i1, *i2) != 0)
4985 if (*(i2 + 1) == NULL) /* if this is the last line */
4987 len1 = strlen (*i1);
4988 len2 = strlen (*i2);
4991 strncmp (*i1, *i2, len1) == 0)
4993 /* We matched ignoring the trailing stuff in vec2 */
5009 len1 = strlen (*i1);
5010 len2 = strlen (*i2);
5012 if (!utf8_caselessnmatch (*i1, *i2, len1, len2))
5014 if (*(i2 + 1) == NULL) /* if this is the last line */
5016 if (utf8_caselessnmatch (*i2, *i1, len2, len1))
5018 /* We matched ignoring the trailing stuff in vec2 */
5043 typedef struct _LinesWindow LinesWindow;
5050 GtkTextIter first_line_start;
5051 GtkTextIter first_line_end;
5054 guint visible_only : 1;
5058 lines_window_init (LinesWindow *win,
5059 const GtkTextIter *start)
5062 GtkTextIter line_start;
5063 GtkTextIter line_end;
5065 /* If we start on line 1, there are 2 lines to search (0 and 1), so
5068 if (gtk_text_iter_is_start (start) ||
5069 gtk_text_iter_get_line (start) + 1 < win->n_lines)
5071 /* Already at the end, or not enough lines to match */
5072 win->lines = g_new0 (gchar*, 1);
5077 line_start = *start;
5080 /* Move to start iter to start of line */
5081 gtk_text_iter_set_line_offset (&line_start, 0);
5083 if (gtk_text_iter_equal (&line_start, &line_end))
5085 /* we were already at the start; so go back one line */
5086 gtk_text_iter_backward_line (&line_start);
5089 win->first_line_start = line_start;
5090 win->first_line_end = line_end;
5092 win->lines = g_new0 (gchar*, win->n_lines + 1);
5094 i = win->n_lines - 1;
5101 if (win->visible_only)
5102 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
5104 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
5108 if (win->visible_only)
5109 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
5111 line_text = gtk_text_iter_get_text (&line_start, &line_end);
5114 win->lines[i] = line_text;
5115 win->first_line_start = line_start;
5116 win->first_line_end = line_end;
5118 line_end = line_start;
5119 gtk_text_iter_backward_line (&line_start);
5126 lines_window_back (LinesWindow *win)
5128 GtkTextIter new_start;
5131 new_start = win->first_line_start;
5133 if (!gtk_text_iter_backward_line (&new_start))
5137 win->first_line_start = new_start;
5138 win->first_line_end = new_start;
5140 gtk_text_iter_forward_line (&win->first_line_end);
5145 if (win->visible_only)
5146 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
5147 &win->first_line_end);
5149 line_text = gtk_text_iter_get_slice (&win->first_line_start,
5150 &win->first_line_end);
5154 if (win->visible_only)
5155 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
5156 &win->first_line_end);
5158 line_text = gtk_text_iter_get_text (&win->first_line_start,
5159 &win->first_line_end);
5162 /* Move lines to make room for first line. */
5163 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
5165 *win->lines = line_text;
5167 /* Free old last line and NULL-terminate */
5168 g_free (win->lines[win->n_lines]);
5169 win->lines[win->n_lines] = NULL;
5175 lines_window_free (LinesWindow *win)
5177 g_strfreev (win->lines);
5181 * gtk_text_iter_backward_search:
5182 * @iter: a #GtkTextIter where the search begins
5183 * @str: search string
5184 * @flags: bitmask of flags affecting the search
5185 * @match_start: (out caller-allocates) (allow-none): return location for start of match, or %NULL
5186 * @match_end: (out caller-allocates) (allow-none): return location for end of match, or %NULL
5187 * @limit: (allow-none): location of last possible @match_start, or %NULL for start of buffer
5189 * Same as gtk_text_iter_forward_search(), but moves backward.
5191 * Return value: whether a match was found
5194 gtk_text_iter_backward_search (const GtkTextIter *iter,
5196 GtkTextSearchFlags flags,
5197 GtkTextIter *match_start,
5198 GtkTextIter *match_end,
5199 const GtkTextIter *limit)
5201 gchar **lines = NULL;
5205 gboolean retval = FALSE;
5206 gboolean visible_only;
5208 gboolean case_insensitive;
5210 g_return_val_if_fail (iter != NULL, FALSE);
5211 g_return_val_if_fail (str != NULL, FALSE);
5214 gtk_text_iter_compare (limit, iter) > 0)
5219 /* If we can move one char, return the empty string there */
5220 GtkTextIter match = *iter;
5222 if (limit && gtk_text_iter_equal (limit, &match))
5225 if (gtk_text_iter_backward_char (&match))
5228 *match_start = match;
5237 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
5238 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
5239 case_insensitive = (flags & GTK_TEXT_SEARCH_CASE_INSENSITIVE) != 0;
5241 /* locate all lines */
5243 lines = strbreakup (str, "\n", -1, &n_lines, case_insensitive);
5245 win.n_lines = n_lines;
5247 win.visible_only = visible_only;
5249 lines_window_init (&win, iter);
5251 if (*win.lines == NULL)
5256 const gchar *first_line_match;
5259 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
5261 /* We're now before the search limit, abort. */
5265 /* If there are multiple lines, the first line will
5266 * end in '\n', so this will only match at the
5267 * end of the first line, which is correct.
5269 if (!case_insensitive)
5270 first_line_match = g_strrstr (*win.lines, *lines);
5272 first_line_match = utf8_strrcasestr (*win.lines, *lines);
5274 if (first_line_match &&
5275 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1,
5281 GtkTextIter start_tmp;
5283 /* Offset to start of search string */
5284 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
5286 next = win.first_line_start;
5288 forward_chars_with_skipping (&start_tmp, offset,
5289 visible_only, !slice, FALSE);
5292 gtk_text_iter_compare (limit, &start_tmp) > 0)
5293 goto out; /* match was bogus */
5296 *match_start = start_tmp;
5298 /* Go to end of search string */
5302 offset += g_utf8_strlen (*l, -1);
5306 forward_chars_with_skipping (&next, offset,
5307 visible_only, !slice, TRUE);
5316 while (lines_window_back (&win));
5319 lines_window_free (&win);
5330 * gtk_text_iter_equal:
5331 * @lhs: a #GtkTextIter
5332 * @rhs: another #GtkTextIter
5334 * Tests whether two iterators are equal, using the fastest possible
5335 * mechanism. This function is very fast; you can expect it to perform
5336 * better than e.g. getting the character offset for each iterator and
5337 * comparing the offsets yourself. Also, it's a bit faster than
5338 * gtk_text_iter_compare().
5340 * Return value: %TRUE if the iterators point to the same place in the buffer
5343 gtk_text_iter_equal (const GtkTextIter *lhs,
5344 const GtkTextIter *rhs)
5346 GtkTextRealIter *real_lhs;
5347 GtkTextRealIter *real_rhs;
5349 real_lhs = (GtkTextRealIter*)lhs;
5350 real_rhs = (GtkTextRealIter*)rhs;
5352 check_invariants (lhs);
5353 check_invariants (rhs);
5355 if (real_lhs->line != real_rhs->line)
5357 else if (real_lhs->line_byte_offset >= 0 &&
5358 real_rhs->line_byte_offset >= 0)
5359 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5362 /* the ensure_char_offsets () calls do nothing if the char offsets
5363 are already up-to-date. */
5364 ensure_char_offsets (real_lhs);
5365 ensure_char_offsets (real_rhs);
5366 return real_lhs->line_char_offset == real_rhs->line_char_offset;
5371 * gtk_text_iter_compare:
5372 * @lhs: a #GtkTextIter
5373 * @rhs: another #GtkTextIter
5375 * A qsort()-style function that returns negative if @lhs is less than
5376 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5377 * Ordering is in character offset order, i.e. the first character in the buffer
5378 * is less than the second character in the buffer.
5380 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5383 gtk_text_iter_compare (const GtkTextIter *lhs,
5384 const GtkTextIter *rhs)
5386 GtkTextRealIter *real_lhs;
5387 GtkTextRealIter *real_rhs;
5389 real_lhs = gtk_text_iter_make_surreal (lhs);
5390 real_rhs = gtk_text_iter_make_surreal (rhs);
5392 if (real_lhs == NULL ||
5394 return -1; /* why not */
5396 check_invariants (lhs);
5397 check_invariants (rhs);
5399 if (real_lhs->line == real_rhs->line)
5401 gint left_index, right_index;
5403 if (real_lhs->line_byte_offset >= 0 &&
5404 real_rhs->line_byte_offset >= 0)
5406 left_index = real_lhs->line_byte_offset;
5407 right_index = real_rhs->line_byte_offset;
5411 /* the ensure_char_offsets () calls do nothing if
5412 the offsets are already up-to-date. */
5413 ensure_char_offsets (real_lhs);
5414 ensure_char_offsets (real_rhs);
5415 left_index = real_lhs->line_char_offset;
5416 right_index = real_rhs->line_char_offset;
5419 if (left_index < right_index)
5421 else if (left_index > right_index)
5430 line1 = gtk_text_iter_get_line (lhs);
5431 line2 = gtk_text_iter_get_line (rhs);
5434 else if (line1 > line2)
5442 * gtk_text_iter_in_range:
5443 * @iter: a #GtkTextIter
5444 * @start: start of range
5445 * @end: end of range
5447 * Checks whether @iter falls in the range [@start, @end).
5448 * @start and @end must be in ascending order.
5450 * Return value: %TRUE if @iter is in the range
5453 gtk_text_iter_in_range (const GtkTextIter *iter,
5454 const GtkTextIter *start,
5455 const GtkTextIter *end)
5457 g_return_val_if_fail (iter != NULL, FALSE);
5458 g_return_val_if_fail (start != NULL, FALSE);
5459 g_return_val_if_fail (end != NULL, FALSE);
5460 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5462 return gtk_text_iter_compare (iter, start) >= 0 &&
5463 gtk_text_iter_compare (iter, end) < 0;
5467 * gtk_text_iter_order:
5468 * @first: a #GtkTextIter
5469 * @second: another #GtkTextIter
5471 * Swaps the value of @first and @second if @second comes before
5472 * @first in the buffer. That is, ensures that @first and @second are
5473 * in sequence. Most text buffer functions that take a range call this
5474 * automatically on your behalf, so there's no real reason to call it yourself
5475 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5476 * that expect a pre-sorted range.
5480 gtk_text_iter_order (GtkTextIter *first,
5481 GtkTextIter *second)
5483 g_return_if_fail (first != NULL);
5484 g_return_if_fail (second != NULL);
5486 if (gtk_text_iter_compare (first, second) > 0)
5497 * Init iterators from the BTree
5501 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5505 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5506 gint real_char_index;
5510 g_return_if_fail (iter != NULL);
5511 g_return_if_fail (tree != NULL);
5513 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5514 &line_start, &real_char_index);
5516 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5518 real->cached_char_index = real_char_index;
5520 check_invariants (iter);
5524 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5529 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5533 g_return_if_fail (iter != NULL);
5534 g_return_if_fail (tree != NULL);
5536 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5538 iter_init_from_char_offset (iter, tree, line, char_on_line);
5540 /* We might as well cache this, since we know it. */
5541 real->cached_line_number = real_line;
5543 check_invariants (iter);
5547 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5552 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5556 g_return_if_fail (iter != NULL);
5557 g_return_if_fail (tree != NULL);
5559 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5561 iter_init_from_byte_offset (iter, tree, line, byte_index);
5563 /* We might as well cache this, since we know it. */
5564 real->cached_line_number = real_line;
5566 check_invariants (iter);
5570 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5575 g_return_if_fail (iter != NULL);
5576 g_return_if_fail (tree != NULL);
5577 g_return_if_fail (line != NULL);
5579 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5581 check_invariants (iter);
5585 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5591 g_return_val_if_fail (iter != NULL, FALSE);
5592 g_return_val_if_fail (tree != NULL, FALSE);
5594 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5598 /* Set iter to last in tree */
5599 _gtk_text_btree_get_end_iter (tree, iter);
5600 check_invariants (iter);
5605 iter_init_from_byte_offset (iter, tree, line, 0);
5607 if (!gtk_text_iter_toggles_tag (iter, tag))
5608 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5610 check_invariants (iter);
5616 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5620 g_return_val_if_fail (iter != NULL, FALSE);
5621 g_return_val_if_fail (tree != NULL, FALSE);
5623 _gtk_text_btree_get_end_iter (tree, iter);
5624 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5625 check_invariants (iter);
5631 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5633 const gchar *mark_name)
5637 g_return_val_if_fail (iter != NULL, FALSE);
5638 g_return_val_if_fail (tree != NULL, FALSE);
5640 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5646 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5647 check_invariants (iter);
5653 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5657 GtkTextLineSegment *seg;
5659 g_return_if_fail (iter != NULL);
5660 g_return_if_fail (tree != NULL);
5661 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5663 seg = mark->segment;
5665 iter_init_from_segment (iter, tree,
5666 seg->body.mark.line, seg);
5667 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5668 check_invariants (iter);
5672 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5674 GtkTextChildAnchor *anchor)
5676 GtkTextLineSegment *seg;
5678 g_return_if_fail (iter != NULL);
5679 g_return_if_fail (tree != NULL);
5680 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5682 seg = anchor->segment;
5684 g_assert (seg->body.child.line != NULL);
5686 iter_init_from_segment (iter, tree,
5687 seg->body.child.line, seg);
5688 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5689 check_invariants (iter);
5693 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5696 g_return_if_fail (iter != NULL);
5697 g_return_if_fail (tree != NULL);
5699 _gtk_text_btree_get_iter_at_char (tree,
5701 _gtk_text_btree_char_count (tree));
5702 check_invariants (iter);
5706 _gtk_text_iter_check (const GtkTextIter *iter)
5708 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5709 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5710 GtkTextLineSegment *byte_segment = NULL;
5711 GtkTextLineSegment *byte_any_segment = NULL;
5712 GtkTextLineSegment *char_segment = NULL;
5713 GtkTextLineSegment *char_any_segment = NULL;
5714 gboolean segments_updated;
5716 /* This function checks our class invariants for the Iter class. */
5718 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5720 if (real->chars_changed_stamp !=
5721 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5722 g_error ("iterator check failed: invalid iterator");
5724 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5725 g_error ("iterator check failed: both char and byte offsets are invalid");
5727 segments_updated = (real->segments_changed_stamp ==
5728 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5731 printf ("checking iter, segments %s updated, byte %d char %d\n",
5732 segments_updated ? "are" : "aren't",
5733 real->line_byte_offset,
5734 real->line_char_offset);
5737 if (segments_updated)
5739 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5740 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5742 if (real->segment->char_count == 0)
5743 g_error ("iterator check failed: segment is not indexable.");
5745 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5746 g_error ("segment char offset is not properly up-to-date");
5748 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5749 g_error ("segment byte offset is not properly up-to-date");
5751 if (real->segment_byte_offset >= 0 &&
5752 real->segment_byte_offset >= real->segment->byte_count)
5753 g_error ("segment byte offset is too large.");
5755 if (real->segment_char_offset >= 0 &&
5756 real->segment_char_offset >= real->segment->char_count)
5757 g_error ("segment char offset is too large.");
5760 if (real->line_byte_offset >= 0)
5762 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5763 &byte_segment, &byte_any_segment,
5764 &seg_byte_offset, &line_byte_offset);
5766 if (line_byte_offset != real->line_byte_offset)
5767 g_error ("wrong byte offset was stored in iterator");
5769 if (segments_updated)
5771 if (real->segment != byte_segment)
5772 g_error ("wrong segment was stored in iterator");
5774 if (real->any_segment != byte_any_segment)
5775 g_error ("wrong any_segment was stored in iterator");
5777 if (seg_byte_offset != real->segment_byte_offset)
5778 g_error ("wrong segment byte offset was stored in iterator");
5780 if (byte_segment->type == >k_text_char_type)
5783 p = byte_segment->body.chars + seg_byte_offset;
5785 if (!gtk_text_byte_begins_utf8_char (p))
5786 g_error ("broken iterator byte index pointed into the middle of a character");
5791 if (real->line_char_offset >= 0)
5793 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5794 &char_segment, &char_any_segment,
5795 &seg_char_offset, &line_char_offset);
5797 if (line_char_offset != real->line_char_offset)
5798 g_error ("wrong char offset was stored in iterator");
5800 if (segments_updated)
5802 if (real->segment != char_segment)
5803 g_error ("wrong segment was stored in iterator");
5805 if (real->any_segment != char_any_segment)
5806 g_error ("wrong any_segment was stored in iterator");
5808 if (seg_char_offset != real->segment_char_offset)
5809 g_error ("wrong segment char offset was stored in iterator");
5811 if (char_segment->type == >k_text_char_type)
5814 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5817 /* hmm, not likely to happen eh */
5818 if (!gtk_text_byte_begins_utf8_char (p))
5819 g_error ("broken iterator char offset pointed into the middle of a character");
5824 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5826 if (byte_segment != char_segment)
5827 g_error ("char and byte offsets did not point to the same segment");
5829 if (byte_any_segment != char_any_segment)
5830 g_error ("char and byte offsets did not point to the same any segment");
5832 /* Make sure the segment offsets are equivalent, if it's a char
5834 if (char_segment->type == >k_text_char_type)
5836 gint byte_offset = 0;
5837 gint char_offset = 0;
5838 while (char_offset < seg_char_offset)
5840 const char * start = char_segment->body.chars + byte_offset;
5841 byte_offset += g_utf8_next_char (start) - start;
5845 if (byte_offset != seg_byte_offset)
5846 g_error ("byte offset did not correspond to char offset");
5849 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5851 if (char_offset != seg_char_offset)
5852 g_error ("char offset did not correspond to byte offset");
5854 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5855 g_error ("byte index for iterator does not index the start of a character");
5859 if (real->cached_line_number >= 0)
5863 should_be = _gtk_text_line_get_number (real->line);
5864 if (real->cached_line_number != should_be)
5865 g_error ("wrong line number was cached");
5868 if (real->cached_char_index >= 0)
5870 if (real->line_char_offset >= 0) /* only way we can check it
5871 efficiently, not a real
5876 char_index = _gtk_text_line_char_index (real->line);
5877 char_index += real->line_char_offset;
5879 if (real->cached_char_index != char_index)
5880 g_error ("wrong char index was cached");
5884 if (_gtk_text_line_is_last (real->line, real->tree))
5885 g_error ("Iterator was on last line (past the end iterator)");