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, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
28 #include "gtktextiter.h"
29 #include "gtktextbtree.h"
30 #include "gtktextiterprivate.h"
35 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
37 typedef struct _GtkTextRealIter GtkTextRealIter;
39 struct _GtkTextRealIter
41 /* Always-valid information */
44 /* At least one of these is always valid;
45 if invalid, they are -1.
47 If the line byte offset is valid, so is the segment byte offset;
48 and ditto for char offsets. */
49 gint line_byte_offset;
50 gint line_char_offset;
51 /* These two are valid if >= 0 */
52 gint cached_char_index;
53 gint cached_line_number;
54 /* Stamps to detect the buffer changing under us */
55 gint chars_changed_stamp;
56 gint segments_changed_stamp;
57 /* Valid if the segments_changed_stamp is up-to-date */
58 GtkTextLineSegment *segment; /* indexable segment we index */
59 GtkTextLineSegment *any_segment; /* first segment in our location,
60 maybe same as "segment" */
61 /* One of these will always be valid if segments_changed_stamp is
62 up-to-date. If invalid, they are -1.
64 If the line byte offset is valid, so is the segment byte offset;
65 and ditto for char offsets. */
66 gint segment_byte_offset;
67 gint segment_char_offset;
70 /* These "set" functions should not assume any fields
71 other than the char stamp and the tree are valid.
74 iter_set_common (GtkTextRealIter *iter,
77 /* Update segments stamp */
78 iter->segments_changed_stamp =
79 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
83 iter->line_byte_offset = -1;
84 iter->line_char_offset = -1;
85 iter->segment_byte_offset = -1;
86 iter->segment_char_offset = -1;
87 iter->cached_char_index = -1;
88 iter->cached_line_number = -1;
92 iter_set_from_byte_offset (GtkTextRealIter *iter,
96 iter_set_common (iter, line);
98 if (!_gtk_text_line_byte_locate (iter->line,
102 &iter->segment_byte_offset,
103 &iter->line_byte_offset))
104 g_error ("Byte index %d is off the end of the line",
109 iter_set_from_char_offset (GtkTextRealIter *iter,
113 iter_set_common (iter, line);
115 if (!_gtk_text_line_char_locate (iter->line,
119 &iter->segment_char_offset,
120 &iter->line_char_offset))
121 g_error ("Char offset %d is off the end of the line",
126 iter_set_from_segment (GtkTextRealIter *iter,
128 GtkTextLineSegment *segment)
130 GtkTextLineSegment *seg;
133 /* This could theoretically be optimized by computing all the iter
134 fields in this same loop, but I'm skipping it for now. */
136 seg = line->segments;
137 while (seg != segment)
139 byte_offset += seg->byte_count;
143 iter_set_from_byte_offset (iter, line, byte_offset);
146 /* This function ensures that the segment-dependent information is
147 truly computed lazily; often we don't need to do the full make_real
148 work. This ensures the btree and line are valid, but doesn't
149 update the segments. */
150 static GtkTextRealIter*
151 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
153 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
155 if (iter->chars_changed_stamp !=
156 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
158 g_warning ("Invalid text buffer iterator: either the iterator "
159 "is uninitialized, or the characters/pixbufs/widgets "
160 "in the buffer have been modified since the iterator "
161 "was created.\nYou must use marks, character numbers, "
162 "or line numbers to preserve a position across buffer "
163 "modifications.\nYou can apply tags and insert marks "
164 "without invalidating your iterators,\n"
165 "but any mutation that affects 'indexable' buffer contents "
166 "(contents that can be referred to by character offset)\n"
167 "will invalidate all outstanding iterators");
171 /* We don't update the segments information since we are becoming
172 only surreal. However we do invalidate the segments information
173 if appropriate, to be sure we segfault if we try to use it and we
174 should have used make_real. */
176 if (iter->segments_changed_stamp !=
177 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
179 iter->segment = NULL;
180 iter->any_segment = NULL;
181 /* set to segfault-causing values. */
182 iter->segment_byte_offset = -10000;
183 iter->segment_char_offset = -10000;
189 static GtkTextRealIter*
190 gtk_text_iter_make_real (const GtkTextIter *_iter)
192 GtkTextRealIter *iter;
194 iter = gtk_text_iter_make_surreal (_iter);
196 if (iter->segments_changed_stamp !=
197 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
199 if (iter->line_byte_offset >= 0)
201 iter_set_from_byte_offset (iter,
203 iter->line_byte_offset);
207 g_assert (iter->line_char_offset >= 0);
209 iter_set_from_char_offset (iter,
211 iter->line_char_offset);
215 g_assert (iter->segment != NULL);
216 g_assert (iter->any_segment != NULL);
217 g_assert (iter->segment->char_count > 0);
222 static GtkTextRealIter*
223 iter_init_common (GtkTextIter *_iter,
226 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
228 g_return_val_if_fail (iter != NULL, NULL);
229 g_return_val_if_fail (tree != NULL, NULL);
233 iter->chars_changed_stamp =
234 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
239 static GtkTextRealIter*
240 iter_init_from_segment (GtkTextIter *iter,
243 GtkTextLineSegment *segment)
245 GtkTextRealIter *real;
247 g_return_val_if_fail (line != NULL, NULL);
249 real = iter_init_common (iter, tree);
251 iter_set_from_segment (real, line, segment);
256 static GtkTextRealIter*
257 iter_init_from_byte_offset (GtkTextIter *iter,
260 gint line_byte_offset)
262 GtkTextRealIter *real;
264 g_return_val_if_fail (line != NULL, NULL);
266 real = iter_init_common (iter, tree);
268 iter_set_from_byte_offset (real, line, line_byte_offset);
270 if (real->segment->type == >k_text_char_type &&
271 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
272 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
273 "character; this will crash the text buffer. "
274 "Byte indexes must refer to the start of a character.",
280 static GtkTextRealIter*
281 iter_init_from_char_offset (GtkTextIter *iter,
284 gint line_char_offset)
286 GtkTextRealIter *real;
288 g_return_val_if_fail (line != NULL, NULL);
290 real = iter_init_common (iter, tree);
292 iter_set_from_char_offset (real, line, line_char_offset);
298 invalidate_segment (GtkTextRealIter *iter)
300 iter->segments_changed_stamp -= 1;
304 invalidate_char_index (GtkTextRealIter *iter)
306 iter->cached_char_index = -1;
310 invalidate_line_number (GtkTextRealIter *iter)
312 iter->cached_line_number = -1;
316 adjust_char_index (GtkTextRealIter *iter, gint count)
318 if (iter->cached_char_index >= 0)
319 iter->cached_char_index += count;
323 adjust_line_number (GtkTextRealIter *iter, gint count)
325 if (iter->cached_line_number >= 0)
326 iter->cached_line_number += count;
330 adjust_char_offsets (GtkTextRealIter *iter, gint count)
332 if (iter->line_char_offset >= 0)
334 iter->line_char_offset += count;
335 g_assert (iter->segment_char_offset >= 0);
336 iter->segment_char_offset += count;
341 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
343 if (iter->line_byte_offset >= 0)
345 iter->line_byte_offset += count;
346 g_assert (iter->segment_byte_offset >= 0);
347 iter->segment_byte_offset += count;
352 ensure_char_offsets (GtkTextRealIter *iter)
354 if (iter->line_char_offset < 0)
356 g_assert (iter->line_byte_offset >= 0);
358 _gtk_text_line_byte_to_char_offsets (iter->line,
359 iter->line_byte_offset,
360 &iter->line_char_offset,
361 &iter->segment_char_offset);
366 ensure_byte_offsets (GtkTextRealIter *iter)
368 if (iter->line_byte_offset < 0)
370 g_assert (iter->line_char_offset >= 0);
372 _gtk_text_line_char_to_byte_offsets (iter->line,
373 iter->line_char_offset,
374 &iter->line_byte_offset,
375 &iter->segment_byte_offset);
379 static inline gboolean
380 is_segment_start (GtkTextRealIter *real)
382 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
387 check_invariants (const GtkTextIter *iter)
389 if (gtk_debug_flags & GTK_DEBUG_TEXT)
390 _gtk_text_iter_check (iter);
393 #define check_invariants (x)
397 * gtk_text_iter_get_buffer:
400 * Return the #GtkTextBuffer this iterator is associated with
402 * Return value: the buffer
405 gtk_text_iter_get_buffer (const GtkTextIter *iter)
407 GtkTextRealIter *real;
409 g_return_val_if_fail (iter != NULL, NULL);
411 real = gtk_text_iter_make_surreal (iter);
416 check_invariants (iter);
418 return _gtk_text_btree_get_buffer (real->tree);
422 * gtk_text_iter_copy:
425 * Create a dynamically-allocated copy of an iterator. This function
426 * is not useful in applications, because iterators can be copied with a
427 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
428 * function is used by language bindings.
430 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
433 gtk_text_iter_copy (const GtkTextIter *iter)
435 GtkTextIter *new_iter;
437 g_return_val_if_fail (iter != NULL, NULL);
439 new_iter = g_new (GtkTextIter, 1);
447 * gtk_text_iter_free:
448 * @iter: a dynamically-allocated iterator
450 * Free an iterator allocated on the heap. This function
451 * is intended for use in language bindings, and is not
452 * especially useful for applications, because iterators can
453 * simply be allocated on the stack.
457 gtk_text_iter_free (GtkTextIter *iter)
459 g_return_if_fail (iter != NULL);
465 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
467 GtkTextRealIter *real;
469 g_return_val_if_fail (iter != NULL, 0);
471 real = gtk_text_iter_make_real (iter);
476 check_invariants (iter);
478 g_assert (real->segment != NULL);
480 return real->segment;
484 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
486 GtkTextRealIter *real;
488 g_return_val_if_fail (iter != NULL, 0);
490 real = gtk_text_iter_make_real (iter);
495 check_invariants (iter);
497 g_assert (real->any_segment != NULL);
499 return real->any_segment;
503 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
505 GtkTextRealIter *real;
507 g_return_val_if_fail (iter != NULL, 0);
509 real = gtk_text_iter_make_real (iter);
514 ensure_byte_offsets (real);
516 check_invariants (iter);
518 return real->segment_byte_offset;
522 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
524 GtkTextRealIter *real;
526 g_return_val_if_fail (iter != NULL, 0);
528 real = gtk_text_iter_make_real (iter);
533 ensure_char_offsets (real);
535 check_invariants (iter);
537 return real->segment_char_offset;
540 /* This function does not require a still-valid
543 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
545 const GtkTextRealIter *real;
547 g_return_val_if_fail (iter != NULL, 0);
549 real = (const GtkTextRealIter*)iter;
554 /* This function does not require a still-valid
557 _gtk_text_iter_get_btree (const GtkTextIter *iter)
559 const GtkTextRealIter *real;
561 g_return_val_if_fail (iter != NULL, 0);
563 real = (const GtkTextRealIter*)iter;
573 * gtk_text_iter_get_offset:
576 * Returns the character offset of an iterator.
577 * Each character in a #GtkTextBuffer has an offset,
578 * starting with 0 for the first character in the buffer.
579 * Use gtk_text_buffer_get_iter_at_offset () to convert an
580 * offset back into an iterator.
582 * Return value: a character offset
585 gtk_text_iter_get_offset (const GtkTextIter *iter)
587 GtkTextRealIter *real;
589 g_return_val_if_fail (iter != NULL, 0);
591 real = gtk_text_iter_make_surreal (iter);
596 check_invariants (iter);
598 if (real->cached_char_index < 0)
600 ensure_char_offsets (real);
602 real->cached_char_index =
603 _gtk_text_line_char_index (real->line);
604 real->cached_char_index += real->line_char_offset;
607 check_invariants (iter);
609 return real->cached_char_index;
613 * gtk_text_iter_get_line:
616 * Returns the line number containing the iterator. Lines in
617 * a #GtkTextBuffer are numbered beginning with 0 for the first
618 * line in the buffer.
620 * Return value: a line number
623 gtk_text_iter_get_line (const GtkTextIter *iter)
625 GtkTextRealIter *real;
627 g_return_val_if_fail (iter != NULL, 0);
629 real = gtk_text_iter_make_surreal (iter);
634 if (real->cached_line_number < 0)
635 real->cached_line_number =
636 _gtk_text_line_get_number (real->line);
638 check_invariants (iter);
640 return real->cached_line_number;
644 * gtk_text_iter_get_line_offset:
647 * Returns the character offset of the iterator,
648 * counting from the start of a newline-terminated line.
649 * The first character on the line has offset 0.
651 * Return value: offset from start of line
654 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
656 GtkTextRealIter *real;
658 g_return_val_if_fail (iter != NULL, 0);
660 real = gtk_text_iter_make_surreal (iter);
665 ensure_char_offsets (real);
667 check_invariants (iter);
669 return real->line_char_offset;
673 * gtk_text_iter_get_line_index:
676 * Returns the byte index of the iterator, counting
677 * from the start of a newline-terminated line.
678 * Remember that #GtkTextBuffer encodes text in
679 * UTF-8, and that characters can require a variable
680 * number of bytes to represent.
682 * Return value: distance from start of line, in bytes
685 gtk_text_iter_get_line_index (const GtkTextIter *iter)
687 GtkTextRealIter *real;
689 g_return_val_if_fail (iter != NULL, 0);
691 real = gtk_text_iter_make_surreal (iter);
696 ensure_byte_offsets (real);
698 check_invariants (iter);
700 return real->line_byte_offset;
704 * gtk_text_iter_get_visible_line_offset:
705 * @iter: a #GtkTextIter
707 * Returns the offset in characters from the start of the
708 * line to the given @iter, not counting characters that
709 * are invisible due to tags with the "invisible" flag
712 * Return value: offset in visible characters from the start of the line
715 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
717 GtkTextRealIter *real;
719 GtkTextLineSegment *seg;
722 g_return_val_if_fail (iter != NULL, 0);
724 real = gtk_text_iter_make_real (iter);
729 ensure_char_offsets (real);
731 check_invariants (iter);
733 vis_offset = real->line_char_offset;
735 _gtk_text_btree_get_iter_at_line (real->tree,
740 seg = _gtk_text_iter_get_indexable_segment (&pos);
742 while (seg != real->segment)
744 /* This is a pretty expensive call, making the
745 * whole function pretty lame; we could keep track
746 * of current invisibility state by looking at toggle
747 * segments as we loop, and then call this function
748 * only once per line, in order to speed up the loop
751 if (_gtk_text_btree_char_is_invisible (&pos))
752 vis_offset -= seg->char_count;
754 _gtk_text_iter_forward_indexable_segment (&pos);
756 seg = _gtk_text_iter_get_indexable_segment (&pos);
759 if (_gtk_text_btree_char_is_invisible (&pos))
760 vis_offset -= real->segment_char_offset;
767 * gtk_text_iter_get_visible_line_index:
768 * @iter: a #GtkTextIter
770 * Returns the number of bytes from the start of the
771 * line to the given @iter, not counting bytes that
772 * are invisible due to tags with the "invisible" flag
775 * Return value: byte index of @iter with respect to the start of the line
778 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
780 GtkTextRealIter *real;
782 GtkTextLineSegment *seg;
785 g_return_val_if_fail (iter != NULL, 0);
787 real = gtk_text_iter_make_real (iter);
792 ensure_char_offsets (real);
794 check_invariants (iter);
796 vis_offset = real->line_byte_offset;
798 _gtk_text_btree_get_iter_at_line (real->tree,
803 seg = _gtk_text_iter_get_indexable_segment (&pos);
805 while (seg != real->segment)
807 /* This is a pretty expensive call, making the
808 * whole function pretty lame; we could keep track
809 * of current invisibility state by looking at toggle
810 * segments as we loop, and then call this function
811 * only once per line, in order to speed up the loop
814 if (_gtk_text_btree_char_is_invisible (&pos))
815 vis_offset -= seg->byte_count;
817 _gtk_text_iter_forward_indexable_segment (&pos);
819 seg = _gtk_text_iter_get_indexable_segment (&pos);
822 if (_gtk_text_btree_char_is_invisible (&pos))
823 vis_offset -= real->segment_byte_offset;
833 * gtk_text_iter_get_char:
836 * Returns the Unicode character at this iterator. (Equivalent to
837 * operator* on a C++ iterator.) If the iterator points at a
838 * non-character element, such as an image embedded in the buffer, the
839 * Unicode "unknown" character 0xFFFC is returned. If invoked on
840 * the end iterator, zero is returned; zero is not a valid Unicode character.
841 * So you can write a loop which ends when gtk_text_iter_get_char ()
844 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
847 gtk_text_iter_get_char (const GtkTextIter *iter)
849 GtkTextRealIter *real;
851 g_return_val_if_fail (iter != NULL, 0);
853 real = gtk_text_iter_make_real (iter);
858 check_invariants (iter);
860 if (gtk_text_iter_is_end (iter))
862 else if (real->segment->type == >k_text_char_type)
864 ensure_byte_offsets (real);
866 return g_utf8_get_char (real->segment->body.chars +
867 real->segment_byte_offset);
871 /* Unicode "unknown character" 0xFFFC */
872 return GTK_TEXT_UNKNOWN_CHAR;
877 * gtk_text_iter_get_slice:
878 * @start: iterator at start of a range
879 * @end: iterator at end of a range
881 * Returns the text in the given range. A "slice" is an array of
882 * characters encoded in UTF-8 format, including the Unicode "unknown"
883 * character 0xFFFC for iterable non-character elements in the buffer,
884 * such as images. Because images are encoded in the slice, byte and
885 * character offsets in the returned array will correspond to byte
886 * offsets in the text buffer. Note that 0xFFFC can occur in normal
887 * text as well, so it is not a reliable indicator that a pixbuf or
888 * widget is in the buffer.
890 * Return value: slice of text from the buffer
893 gtk_text_iter_get_slice (const GtkTextIter *start,
894 const GtkTextIter *end)
896 g_return_val_if_fail (start != NULL, NULL);
897 g_return_val_if_fail (end != NULL, NULL);
899 check_invariants (start);
900 check_invariants (end);
902 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
906 * gtk_text_iter_get_text:
907 * @start: iterator at start of a range
908 * @end: iterator at end of a range
910 * Returns <emphasis>text</emphasis> in the given range. If the range
911 * contains non-text elements such as images, the character and byte
912 * offsets in the returned string will not correspond to character and
913 * byte offsets in the buffer. If you want offsets to correspond, see
914 * gtk_text_iter_get_slice ().
916 * Return value: array of characters from the buffer
919 gtk_text_iter_get_text (const GtkTextIter *start,
920 const GtkTextIter *end)
922 g_return_val_if_fail (start != NULL, NULL);
923 g_return_val_if_fail (end != NULL, NULL);
925 check_invariants (start);
926 check_invariants (end);
928 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
932 * gtk_text_iter_get_visible_slice:
933 * @start: iterator at start of range
934 * @end: iterator at end of range
936 * Like gtk_text_iter_get_slice (), but invisible text is not included.
937 * Invisible text is usually invisible because a #GtkTextTag with the
938 * "invisible" attribute turned on has been applied to it.
940 * Return value: slice of text from the buffer
943 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
944 const GtkTextIter *end)
946 g_return_val_if_fail (start != NULL, NULL);
947 g_return_val_if_fail (end != NULL, NULL);
949 check_invariants (start);
950 check_invariants (end);
952 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
956 * gtk_text_iter_get_visible_text:
957 * @start: iterator at start of range
958 * @end: iterator at end of range
960 * Like gtk_text_iter_get_text (), but invisible text is not included.
961 * Invisible text is usually invisible because a #GtkTextTag with the
962 * "invisible" attribute turned on has been applied to it.
964 * Return value: string containing visible text in the range
967 gtk_text_iter_get_visible_text (const GtkTextIter *start,
968 const GtkTextIter *end)
970 g_return_val_if_fail (start != NULL, NULL);
971 g_return_val_if_fail (end != NULL, NULL);
973 check_invariants (start);
974 check_invariants (end);
976 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
980 * gtk_text_iter_get_pixbuf:
983 * If the location pointed to by @iter contains a pixbuf, the pixbuf
984 * is returned (with no new reference count added). Otherwise,
987 * Return value: the pixbuf at @iter
990 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
992 GtkTextRealIter *real;
994 g_return_val_if_fail (iter != NULL, NULL);
996 real = gtk_text_iter_make_real (iter);
1001 check_invariants (iter);
1003 if (real->segment->type != >k_text_pixbuf_type)
1006 return real->segment->body.pixbuf.pixbuf;
1010 * gtk_text_iter_get_child_anchor:
1011 * @iter: an iterator
1013 * If the location pointed to by @iter contains a child anchor, the
1014 * anchor is returned (with no new reference count added). Otherwise,
1017 * Return value: the anchor at @iter
1020 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1022 GtkTextRealIter *real;
1024 g_return_val_if_fail (iter != NULL, NULL);
1026 real = gtk_text_iter_make_real (iter);
1031 check_invariants (iter);
1033 if (real->segment->type != >k_text_child_type)
1036 return real->segment->body.child.obj;
1040 * gtk_text_iter_get_marks:
1041 * @iter: an iterator
1043 * Returns a list of all #GtkTextMark at this location. Because marks
1044 * are not iterable (they don't take up any "space" in the buffer,
1045 * they are just marks in between iterable locations), multiple marks
1046 * can exist in the same place. The returned list is not in any
1049 * Return value: list of #GtkTextMark
1052 gtk_text_iter_get_marks (const GtkTextIter *iter)
1054 GtkTextRealIter *real;
1055 GtkTextLineSegment *seg;
1058 g_return_val_if_fail (iter != NULL, NULL);
1060 real = gtk_text_iter_make_real (iter);
1065 check_invariants (iter);
1068 seg = real->any_segment;
1069 while (seg != real->segment)
1071 if (seg->type == >k_text_left_mark_type ||
1072 seg->type == >k_text_right_mark_type)
1073 retval = g_slist_prepend (retval, seg->body.mark.obj);
1078 /* The returned list isn't guaranteed to be in any special order,
1084 * gtk_text_iter_get_toggled_tags:
1085 * @iter: an iterator
1086 * @toggled_on: TRUE to get toggled-on tags
1088 * Returns a list of #GtkTextTag that are toggled on or off at this
1089 * point. (If @toggled_on is TRUE, the list contains tags that are
1090 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1091 * range of characters following @iter has that tag applied to it. If
1092 * a tag is toggled off, then some non-empty range following @iter
1093 * does <emphasis>not</emphasis> have the tag applied to it.
1095 * Return value: tags toggled at this point
1098 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1099 gboolean toggled_on)
1101 GtkTextRealIter *real;
1102 GtkTextLineSegment *seg;
1105 g_return_val_if_fail (iter != NULL, NULL);
1107 real = gtk_text_iter_make_real (iter);
1112 check_invariants (iter);
1115 seg = real->any_segment;
1116 while (seg != real->segment)
1120 if (seg->type == >k_text_toggle_on_type)
1122 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1127 if (seg->type == >k_text_toggle_off_type)
1129 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1136 /* The returned list isn't guaranteed to be in any special order,
1142 * gtk_text_iter_begins_tag:
1143 * @iter: an iterator
1144 * @tag: a #GtkTextTag, or NULL
1146 * Returns TRUE if @tag is toggled on at exactly this point. If @tag
1147 * is NULL, returns TRUE if any tag is toggled on at this point. Note
1148 * that the gtk_text_iter_begins_tag () returns TRUE if @iter is the
1149 * <emphasis>start</emphasis> of the tagged range;
1150 * gtk_text_iter_has_tag () tells you whether an iterator is
1151 * <emphasis>within</emphasis> a tagged range.
1153 * Return value: whether @iter is the start of a range tagged with @tag
1156 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1159 GtkTextRealIter *real;
1160 GtkTextLineSegment *seg;
1162 g_return_val_if_fail (iter != NULL, FALSE);
1164 real = gtk_text_iter_make_real (iter);
1169 check_invariants (iter);
1171 seg = real->any_segment;
1172 while (seg != real->segment)
1174 if (seg->type == >k_text_toggle_on_type)
1177 seg->body.toggle.info->tag == tag)
1188 * gtk_text_iter_ends_tag:
1189 * @iter: an iterator
1190 * @tag: a #GtkTextTag, or NULL
1192 * Returns TRUE if @tag is toggled off at exactly this point. If @tag
1193 * is NULL, returns TRUE if any tag is toggled off at this point. Note
1194 * that the gtk_text_iter_ends_tag () returns TRUE if @iter is the
1195 * <emphasis>end</emphasis> of the tagged range;
1196 * gtk_text_iter_has_tag () tells you whether an iterator is
1197 * <emphasis>within</emphasis> a tagged range.
1199 * Return value: whether @iter is the end of a range tagged with @tag
1203 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1206 GtkTextRealIter *real;
1207 GtkTextLineSegment *seg;
1209 g_return_val_if_fail (iter != NULL, FALSE);
1211 real = gtk_text_iter_make_real (iter);
1216 check_invariants (iter);
1218 seg = real->any_segment;
1219 while (seg != real->segment)
1221 if (seg->type == >k_text_toggle_off_type)
1224 seg->body.toggle.info->tag == tag)
1235 * gtk_text_iter_toggles_tag:
1236 * @iter: an iterator
1237 * @tag: a #GtkTextTag, or NULL
1239 * This is equivalent to (gtk_text_iter_begins_tag () ||
1240 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1241 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1243 * Return value: whether @tag is toggled on or off at @iter
1246 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1249 GtkTextRealIter *real;
1250 GtkTextLineSegment *seg;
1252 g_return_val_if_fail (iter != NULL, FALSE);
1254 real = gtk_text_iter_make_real (iter);
1259 check_invariants (iter);
1261 seg = real->any_segment;
1262 while (seg != real->segment)
1264 if ( (seg->type == >k_text_toggle_off_type ||
1265 seg->type == >k_text_toggle_on_type) &&
1267 seg->body.toggle.info->tag == tag) )
1277 * gtk_text_iter_has_tag:
1278 * @iter: an iterator
1279 * @tag: a #GtkTextTag
1281 * Returns TRUE if @iter is within a range tagged with @tag.
1283 * Return value: whether @iter is tagged with @tag
1286 gtk_text_iter_has_tag (const GtkTextIter *iter,
1289 GtkTextRealIter *real;
1291 g_return_val_if_fail (iter != NULL, FALSE);
1292 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1294 real = gtk_text_iter_make_surreal (iter);
1299 check_invariants (iter);
1301 if (real->line_byte_offset >= 0)
1303 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1304 real->line_byte_offset, tag);
1308 g_assert (real->line_char_offset >= 0);
1309 return _gtk_text_line_char_has_tag (real->line, real->tree,
1310 real->line_char_offset, tag);
1315 * gtk_text_iter_get_tags:
1316 * @iter: a #GtkTextIter
1318 * Returns a list of tags that apply to @iter, in ascending order of
1319 * priority (highest-priority tags are last). The #GtkTextTag in the
1320 * list don't have a reference added, but you have to free the list
1323 * Return value: list of #GtkTextTag
1326 gtk_text_iter_get_tags (const GtkTextIter *iter)
1333 g_return_val_if_fail (iter != NULL, NULL);
1335 /* Get the tags at this spot */
1336 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1338 /* No tags, use default style */
1339 if (tags == NULL || tag_count == 0)
1347 /* Sort tags in ascending order of priority */
1348 _gtk_text_tag_array_sort (tags, tag_count);
1352 while (i < tag_count)
1354 retval = g_slist_prepend (retval, tags[i]);
1360 /* Return tags in ascending order of priority */
1361 return g_slist_reverse (retval);
1365 * gtk_text_iter_editable:
1366 * @iter: an iterator
1367 * @default_setting: %TRUE if text is editable by default
1369 * Returns whether the character at @iter is within an editable region
1370 * of text. Non-editable text is "locked" and can't be changed by the
1371 * user via #GtkTextView. This function is simply a convenience
1372 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1373 * to this text affect editability, @default_setting will be returned.
1375 * You don't want to use this function to decide whether text can be
1376 * inserted at @iter, because for insertion you don't want to know
1377 * whether the char at @iter is inside an editable range, you want to
1378 * know whether a new character inserted at @iter would be inside an
1379 * editable range. Use gtk_text_iter_can_insert() to handle this
1382 * Return value: whether @iter is inside an editable range
1385 gtk_text_iter_editable (const GtkTextIter *iter,
1386 gboolean default_setting)
1388 GtkTextAttributes *values;
1391 g_return_val_if_fail (iter != NULL, FALSE);
1393 values = gtk_text_attributes_new ();
1395 values->editable = default_setting;
1397 gtk_text_iter_get_attributes (iter, values);
1399 retval = values->editable;
1401 gtk_text_attributes_unref (values);
1407 * gtk_text_iter_can_insert:
1408 * @iter: an iterator
1409 * @default_editability: %TRUE if text is editable by default
1411 * Considering the default editability of the buffer, and tags that
1412 * affect editability, determines whether text inserted at @iter would
1413 * be editable. If text inserted at @iter would be editable then the
1414 * user should be allowed to insert text at @iter.
1415 * gtk_text_buffer_insert_interactive() uses this function to decide
1416 * whether insertions are allowed at a given position.
1418 * Return value: whether text inserted at @iter would be editable
1421 gtk_text_iter_can_insert (const GtkTextIter *iter,
1422 gboolean default_editability)
1424 g_return_val_if_fail (iter != NULL, FALSE);
1426 if (gtk_text_iter_editable (iter, default_editability))
1428 /* If at start/end of buffer, default editability is used */
1429 else if ((gtk_text_iter_is_start (iter) ||
1430 gtk_text_iter_is_end (iter)) &&
1431 default_editability)
1435 /* if iter isn't editable, and the char before iter is,
1436 * then iter is the first char in an editable region
1437 * and thus insertion at iter results in editable text.
1439 GtkTextIter prev = *iter;
1440 gtk_text_iter_backward_char (&prev);
1441 return gtk_text_iter_editable (&prev, default_editability);
1447 * gtk_text_iter_get_language:
1448 * @iter: an iterator
1450 * A convenience wrapper around gtk_text_iter_get_attributes (),
1451 * which returns the language in effect at @iter. If no tags affecting
1452 * language * apply to @iter, the return value is identical to that of
1453 * gtk_get_default_language ().
1455 * Return value: language in effect at @iter
1458 gtk_text_iter_get_language (const GtkTextIter *iter)
1460 GtkTextAttributes *values;
1461 PangoLanguage *retval;
1463 values = gtk_text_attributes_new ();
1465 gtk_text_iter_get_attributes (iter, values);
1467 retval = values->language;
1469 gtk_text_attributes_unref (values);
1475 * gtk_text_iter_starts_line:
1476 * @iter: an iterator
1478 * Returns TRUE if @iter begins a paragraph,
1479 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1480 * However this function is potentially more efficient than
1481 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1482 * the offset, it just has to see whether it's 0.
1484 * Return value: whether @iter begins a line
1487 gtk_text_iter_starts_line (const GtkTextIter *iter)
1489 GtkTextRealIter *real;
1491 g_return_val_if_fail (iter != NULL, FALSE);
1493 real = gtk_text_iter_make_surreal (iter);
1498 check_invariants (iter);
1500 if (real->line_byte_offset >= 0)
1502 return (real->line_byte_offset == 0);
1506 g_assert (real->line_char_offset >= 0);
1507 return (real->line_char_offset == 0);
1512 * gtk_text_iter_ends_line:
1513 * @iter: an iterator
1515 * Returns TRUE if @iter points to the start of the paragraph delimiter
1516 * characters for a line (delimiters will be either a newline, a
1517 * carriage return, a carriage return followed by a newline, or a
1518 * Unicode paragraph separator character). Note that an iterator pointing
1519 * to the \n of a \r\n pair will not be counted as the end of a line,
1520 * the line ends before the \r.
1522 * Return value: whether @iter is at the end of a line
1525 gtk_text_iter_ends_line (const GtkTextIter *iter)
1527 GtkTextRealIter *real;
1530 g_return_val_if_fail (iter != NULL, FALSE);
1532 real = gtk_text_iter_make_real (iter);
1534 check_invariants (iter);
1536 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1537 * Unicode 3.0; update this if that changes.
1539 #define PARAGRAPH_SEPARATOR 0x2029
1541 wc = gtk_text_iter_get_char (iter);
1543 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR)
1545 else if (wc == '\n')
1547 /* need to determine if a \r precedes the \n, in which case
1548 * we aren't the end of the line
1550 GtkTextIter tmp = *iter;
1551 if (!gtk_text_iter_backward_char (&tmp))
1554 return gtk_text_iter_get_char (&tmp) != '\r';
1561 * gtk_text_iter_is_end:
1562 * @iter: an iterator
1564 * Returns TRUE if @iter is the end iterator, i.e. one past the last
1565 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1566 * the most efficient way to check whether an iterator is the end
1569 * Return value: whether @iter is the end iterator
1572 gtk_text_iter_is_end (const GtkTextIter *iter)
1574 GtkTextRealIter *real;
1576 g_return_val_if_fail (iter != NULL, FALSE);
1578 real = gtk_text_iter_make_surreal (iter);
1583 check_invariants (iter);
1585 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1588 /* Now we need the segments validated */
1589 real = gtk_text_iter_make_real (iter);
1594 return _gtk_text_btree_is_end (real->tree, real->line,
1596 real->segment_byte_offset,
1597 real->segment_char_offset);
1601 * gtk_text_iter_is_start:
1602 * @iter: an iterator
1604 * Returns TRUE if @iter is the first iterator in the buffer, that is
1605 * if @iter has a character offset of 0.
1607 * Return value: whether @iter is the first in the buffer
1610 gtk_text_iter_is_start (const GtkTextIter *iter)
1612 return gtk_text_iter_get_offset (iter) == 0;
1616 * gtk_text_iter_get_chars_in_line:
1617 * @iter: an iterator
1619 * Returns the number of characters in the line containing @iter,
1620 * including the paragraph delimiters.
1622 * Return value: number of characters in the line
1625 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1627 GtkTextRealIter *real;
1629 GtkTextLineSegment *seg;
1631 g_return_val_if_fail (iter != NULL, FALSE);
1633 real = gtk_text_iter_make_surreal (iter);
1638 check_invariants (iter);
1640 if (real->line_char_offset >= 0)
1642 /* We can start at the segments we've already found. */
1643 count = real->line_char_offset - real->segment_char_offset;
1644 seg = _gtk_text_iter_get_indexable_segment (iter);
1648 /* count whole line. */
1649 seg = real->line->segments;
1656 count += seg->char_count;
1661 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1662 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1668 * gtk_text_iter_get_bytes_in_line:
1669 * @iter: an iterator
1671 * Returns the number of bytes in the line containing @iter,
1672 * including the paragraph delimiters.
1674 * Return value: number of bytes in the line
1677 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1679 GtkTextRealIter *real;
1681 GtkTextLineSegment *seg;
1683 g_return_val_if_fail (iter != NULL, FALSE);
1685 real = gtk_text_iter_make_surreal (iter);
1690 check_invariants (iter);
1692 if (real->line_byte_offset >= 0)
1694 /* We can start at the segments we've already found. */
1695 count = real->line_byte_offset - real->segment_byte_offset;
1696 seg = _gtk_text_iter_get_indexable_segment (iter);
1700 /* count whole line. */
1701 seg = real->line->segments;
1707 count += seg->byte_count;
1712 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1713 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1719 * gtk_text_iter_get_attributes:
1720 * @iter: an iterator
1721 * @values: a #GtkTextAttributes to be filled in
1723 * Computes the effect of any tags applied to this spot in the
1724 * text. The @values parameter should be initialized to the default
1725 * settings you wish to use if no tags are in effect. You'd typically
1726 * obtain the defaults from gtk_text_view_get_default_attributes().
1728 * gtk_text_iter_get_attributes () will modify @values, applying the
1729 * effects of any tags present at @iter. If any tags affected @values,
1730 * the function returns %TRUE.
1732 * Return value: %TRUE if @values was modified
1735 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1736 GtkTextAttributes *values)
1741 /* Get the tags at this spot */
1742 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1744 /* No tags, use default style */
1745 if (tags == NULL || tag_count == 0)
1753 /* Sort tags in ascending order of priority */
1754 _gtk_text_tag_array_sort (tags, tag_count);
1756 _gtk_text_attributes_fill_from_tags (values,
1766 * Increments/decrements
1769 /* The return value of this indicates WHETHER WE MOVED.
1770 * The return value of public functions indicates
1771 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1773 * This function will not change the iterator if
1774 * it's already on the last (end iter) line, i.e. it
1775 * won't move to the end of the last line.
1778 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1780 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1782 GtkTextLine *new_line;
1784 new_line = _gtk_text_line_next (real->line);
1785 g_assert (new_line);
1786 g_assert (new_line != real->line);
1787 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1789 real->line = new_line;
1791 real->line_byte_offset = 0;
1792 real->line_char_offset = 0;
1794 real->segment_byte_offset = 0;
1795 real->segment_char_offset = 0;
1797 /* Find first segments in new line */
1798 real->any_segment = real->line->segments;
1799 real->segment = real->any_segment;
1800 while (real->segment->char_count == 0)
1801 real->segment = real->segment->next;
1807 /* There is no way to move forward a line; we were already at
1808 * the line containing the end iterator.
1809 * However we may not be at the end iterator itself.
1817 /* The return value of this indicates WHETHER WE MOVED.
1818 * The return value of public functions indicates
1819 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1822 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1824 GtkTextLine *new_line;
1826 new_line = _gtk_text_line_previous (real->line);
1828 g_assert (new_line != real->line);
1830 if (new_line != NULL)
1832 real->line = new_line;
1834 real->line_byte_offset = 0;
1835 real->line_char_offset = 0;
1837 real->segment_byte_offset = 0;
1838 real->segment_char_offset = 0;
1840 /* Find first segments in new line */
1841 real->any_segment = real->line->segments;
1842 real->segment = real->any_segment;
1843 while (real->segment->char_count == 0)
1844 real->segment = real->segment->next;
1850 /* There is no way to move backward; we were already
1851 at the first line. */
1853 /* We leave real->line as-is */
1855 /* Note that we didn't clamp to the start of the first line. */
1861 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1865 forward_char (GtkTextRealIter *real)
1867 GtkTextIter *iter = (GtkTextIter*)real;
1869 check_invariants ((GtkTextIter*)real);
1871 ensure_char_offsets (real);
1873 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1875 /* Need to move to the next segment; if no next segment,
1876 need to move to next line. */
1877 return _gtk_text_iter_forward_indexable_segment (iter);
1881 /* Just moving within a segment. Keep byte count
1882 up-to-date, if it was already up-to-date. */
1884 g_assert (real->segment->type == >k_text_char_type);
1886 if (real->line_byte_offset >= 0)
1889 const char * start =
1890 real->segment->body.chars + real->segment_byte_offset;
1892 bytes = g_utf8_next_char (start) - start;
1894 real->line_byte_offset += bytes;
1895 real->segment_byte_offset += bytes;
1897 g_assert (real->segment_byte_offset < real->segment->byte_count);
1900 real->line_char_offset += 1;
1901 real->segment_char_offset += 1;
1903 adjust_char_index (real, 1);
1905 g_assert (real->segment_char_offset < real->segment->char_count);
1907 /* We moved into the middle of a segment, so the any_segment
1908 must now be the segment we're in the middle of. */
1909 real->any_segment = real->segment;
1911 check_invariants ((GtkTextIter*)real);
1913 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1921 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1923 /* Need to move to the next segment; if no next segment,
1924 need to move to next line. */
1925 GtkTextLineSegment *seg;
1926 GtkTextLineSegment *any_seg;
1927 GtkTextRealIter *real;
1931 g_return_val_if_fail (iter != NULL, FALSE);
1933 real = gtk_text_iter_make_real (iter);
1938 check_invariants (iter);
1940 if (real->line_char_offset >= 0)
1942 chars_skipped = real->segment->char_count - real->segment_char_offset;
1943 g_assert (chars_skipped > 0);
1948 if (real->line_byte_offset >= 0)
1950 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1951 g_assert (bytes_skipped > 0);
1956 /* Get first segment of any kind */
1957 any_seg = real->segment->next;
1958 /* skip non-indexable segments, if any */
1960 while (seg != NULL && seg->char_count == 0)
1965 real->any_segment = any_seg;
1966 real->segment = seg;
1968 if (real->line_byte_offset >= 0)
1970 g_assert (bytes_skipped > 0);
1971 real->segment_byte_offset = 0;
1972 real->line_byte_offset += bytes_skipped;
1975 if (real->line_char_offset >= 0)
1977 g_assert (chars_skipped > 0);
1978 real->segment_char_offset = 0;
1979 real->line_char_offset += chars_skipped;
1980 adjust_char_index (real, chars_skipped);
1983 check_invariants (iter);
1985 return !gtk_text_iter_is_end (iter);
1989 /* End of the line */
1990 if (forward_line_leaving_caches_unmodified (real))
1992 adjust_line_number (real, 1);
1993 if (real->line_char_offset >= 0)
1994 adjust_char_index (real, chars_skipped);
1996 g_assert (real->line_byte_offset == 0);
1997 g_assert (real->line_char_offset == 0);
1998 g_assert (real->segment_byte_offset == 0);
1999 g_assert (real->segment_char_offset == 0);
2000 g_assert (gtk_text_iter_starts_line (iter));
2002 check_invariants (iter);
2004 return !gtk_text_iter_is_end (iter);
2010 check_invariants (iter);
2012 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2013 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2014 if (!gtk_text_iter_is_end (iter))
2015 _gtk_text_btree_spew (_gtk_text_iter_get_btree (iter));
2016 g_assert (gtk_text_iter_is_end (iter));
2024 at_last_indexable_segment (GtkTextRealIter *real)
2026 GtkTextLineSegment *seg;
2028 /* Return TRUE if there are no indexable segments after
2032 seg = real->segment->next;
2035 if (seg->char_count > 0)
2042 /* Goes back to the start of the next segment, even if
2043 * we're not at the start of the current segment (always
2044 * ends up on a different segment if it returns TRUE)
2047 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2049 /* Move to the start of the previous segment; if no previous
2050 * segment, to the last segment in the previous line. This is
2051 * inherently a bit inefficient due to the singly-linked list and
2052 * tree nodes, but we can't afford the RAM for doubly-linked.
2054 GtkTextRealIter *real;
2055 GtkTextLineSegment *seg;
2056 GtkTextLineSegment *any_seg;
2057 GtkTextLineSegment *prev_seg;
2058 GtkTextLineSegment *prev_any_seg;
2062 g_return_val_if_fail (iter != NULL, FALSE);
2064 real = gtk_text_iter_make_real (iter);
2069 check_invariants (iter);
2071 /* Find first segments in line */
2072 any_seg = real->line->segments;
2074 while (seg->char_count == 0)
2077 if (seg == real->segment)
2079 /* Could probably do this case faster by hand-coding the
2083 /* We were already at the start of a line;
2084 * go back to the previous line.
2086 if (gtk_text_iter_backward_line (iter))
2088 /* Go forward to last indexable segment in line. */
2089 while (!at_last_indexable_segment (real))
2090 _gtk_text_iter_forward_indexable_segment (iter);
2092 check_invariants (iter);
2097 return FALSE; /* We were at the start of the first line. */
2100 /* We must be in the middle of a line; so find the indexable
2101 * segment just before our current segment.
2103 g_assert (seg != real->segment);
2104 while (seg != real->segment)
2107 prev_any_seg = any_seg;
2109 any_seg = seg->next;
2111 while (seg->char_count == 0)
2115 g_assert (prev_seg != NULL);
2116 g_assert (prev_any_seg != NULL);
2117 g_assert (prev_seg->char_count > 0);
2119 /* We skipped the entire previous segment, plus any
2120 * chars we were into the current segment.
2122 if (real->segment_byte_offset >= 0)
2123 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2127 if (real->segment_char_offset >= 0)
2128 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2132 real->segment = prev_seg;
2133 real->any_segment = prev_any_seg;
2134 real->segment_byte_offset = 0;
2135 real->segment_char_offset = 0;
2137 if (bytes_skipped >= 0)
2139 if (real->line_byte_offset >= 0)
2141 real->line_byte_offset -= bytes_skipped;
2142 g_assert (real->line_byte_offset >= 0);
2146 real->line_byte_offset = -1;
2148 if (chars_skipped >= 0)
2150 if (real->line_char_offset >= 0)
2152 real->line_char_offset -= chars_skipped;
2153 g_assert (real->line_char_offset >= 0);
2156 if (real->cached_char_index >= 0)
2158 real->cached_char_index -= chars_skipped;
2159 g_assert (real->cached_char_index >= 0);
2164 real->line_char_offset = -1;
2165 real->cached_char_index = -1;
2168 /* line number is unchanged. */
2170 check_invariants (iter);
2176 * gtk_text_iter_forward_char:
2177 * @iter: an iterator
2179 * Moves @iter forward by one character offset. Note that images
2180 * embedded in the buffer occupy 1 character slot, so
2181 * gtk_text_iter_forward_char () may actually move onto an image instead
2182 * of a character, if you have images in your buffer. If @iter is the
2183 * end iterator or one character before it, @iter will now point at
2184 * the end iterator, and gtk_text_iter_forward_char () returns FALSE for
2185 * convenience when writing loops.
2187 * Return value: whether the new position is the end iterator
2190 gtk_text_iter_forward_char (GtkTextIter *iter)
2192 GtkTextRealIter *real;
2194 g_return_val_if_fail (iter != NULL, FALSE);
2196 real = gtk_text_iter_make_real (iter);
2202 check_invariants (iter);
2203 return forward_char (real);
2208 * gtk_text_iter_backward_char:
2209 * @iter: an iterator
2211 * Moves backward by one character offset. Returns TRUE if movement
2212 * was possible; if @iter was the first in the buffer (character
2213 * offset 0), gtk_text_iter_backward_char () returns FALSE for convenience when
2216 * Return value: whether movement was possible
2219 gtk_text_iter_backward_char (GtkTextIter *iter)
2221 g_return_val_if_fail (iter != NULL, FALSE);
2223 check_invariants (iter);
2225 return gtk_text_iter_backward_chars (iter, 1);
2229 Definitely we should try to linear scan as often as possible for
2230 movement within a single line, because we can't use the BTree to
2231 speed within-line searches up; for movement between lines, we would
2232 like to avoid the linear scan probably.
2234 Instead of using this constant, it might be nice to cache the line
2235 length in the iterator and linear scan if motion is within a single
2238 I guess you'd have to profile the various approaches.
2240 #define MAX_LINEAR_SCAN 150
2244 * gtk_text_iter_forward_chars:
2245 * @iter: an iterator
2246 * @count: number of characters to move, may be negative
2248 * Moves @count characters if possible (if @count would move past the
2249 * start or end of the buffer, moves to the start or end of the
2250 * buffer). The return value indicates whether the new position of
2251 * @iter is different from its original position, and dereferenceable
2252 * (the last iterator in the buffer is not dereferenceable). If @count
2253 * is 0, the function does nothing and returns FALSE.
2255 * Return value: whether @iter moved and is dereferenceable
2258 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2260 GtkTextRealIter *real;
2262 g_return_val_if_fail (iter != NULL, FALSE);
2264 FIX_OVERFLOWS (count);
2266 real = gtk_text_iter_make_real (iter);
2270 else if (count == 0)
2273 return gtk_text_iter_backward_chars (iter, 0 - count);
2274 else if (count < MAX_LINEAR_SCAN)
2276 check_invariants (iter);
2280 if (!forward_char (real))
2285 return forward_char (real);
2289 gint current_char_index;
2290 gint new_char_index;
2292 check_invariants (iter);
2294 current_char_index = gtk_text_iter_get_offset (iter);
2296 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2297 return FALSE; /* can't move forward */
2299 new_char_index = current_char_index + count;
2300 gtk_text_iter_set_offset (iter, new_char_index);
2302 check_invariants (iter);
2304 /* Return FALSE if we're on the non-dereferenceable end
2307 if (gtk_text_iter_is_end (iter))
2315 * gtk_text_iter_backward_chars:
2316 * @iter: an iterator
2317 * @count: number of characters to move
2319 * Moves @count characters backward, if possible (if @count would move
2320 * past the start or end of the buffer, moves to the start or end of
2321 * the buffer). The return value indicates whether the iterator moved
2322 * onto a dereferenceable position; if the iterator didn't move, or
2323 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2324 * the function does nothing and returns FALSE.
2326 * Return value: whether @iter moved and is dereferenceable
2330 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2332 GtkTextRealIter *real;
2334 g_return_val_if_fail (iter != NULL, FALSE);
2336 FIX_OVERFLOWS (count);
2338 real = gtk_text_iter_make_real (iter);
2342 else if (count == 0)
2345 return gtk_text_iter_forward_chars (iter, 0 - count);
2347 ensure_char_offsets (real);
2348 check_invariants (iter);
2350 if (count <= real->segment_char_offset)
2352 /* Optimize the within-segment case */
2353 g_assert (real->segment->char_count > 0);
2354 g_assert (real->segment->type == >k_text_char_type);
2356 real->segment_char_offset -= count;
2357 g_assert (real->segment_char_offset >= 0);
2359 if (real->line_byte_offset >= 0)
2361 gint new_byte_offset;
2364 new_byte_offset = 0;
2366 while (i < real->segment_char_offset)
2368 const char * start = real->segment->body.chars + new_byte_offset;
2369 new_byte_offset += g_utf8_next_char (start) - start;
2374 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2375 real->segment_byte_offset = new_byte_offset;
2378 real->line_char_offset -= count;
2380 adjust_char_index (real, 0 - count);
2382 check_invariants (iter);
2388 /* We need to go back into previous segments. For now,
2389 * just keep this really simple. FIXME
2390 * use backward_indexable_segment.
2392 if (TRUE || count > MAX_LINEAR_SCAN)
2394 gint current_char_index;
2395 gint new_char_index;
2397 current_char_index = gtk_text_iter_get_offset (iter);
2399 if (current_char_index == 0)
2400 return FALSE; /* can't move backward */
2402 new_char_index = current_char_index - count;
2403 if (new_char_index < 0)
2405 gtk_text_iter_set_offset (iter, new_char_index);
2407 check_invariants (iter);
2413 /* FIXME backward_indexable_segment here */
2422 /* These two can't be implemented efficiently (always have to use
2423 * a linear scan, since that's the only way to find all the non-text
2428 * gtk_text_iter_forward_text_chars:
2429 * @iter: a #GtkTextIter
2430 * @count: number of chars to move
2432 * Moves forward by @count text characters (pixbufs, widgets,
2433 * etc. do not count as characters for this). Equivalent to moving
2434 * through the results of gtk_text_iter_get_text (), rather than
2435 * gtk_text_iter_get_slice ().
2437 * Return value: whether @iter moved and is dereferenceable
2440 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2449 * gtk_text_iter_forward_text_chars:
2450 * @iter: a #GtkTextIter
2451 * @count: number of chars to move
2453 * Moves backward by @count text characters (pixbufs, widgets,
2454 * etc. do not count as characters for this). Equivalent to moving
2455 * through the results of gtk_text_iter_get_text (), rather than
2456 * gtk_text_iter_get_slice ().
2458 * Return value: whether @iter moved and is dereferenceable
2461 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2470 * gtk_text_iter_forward_line:
2471 * @iter: an iterator
2473 * Moves @iter to the start of the next line. Returns TRUE if there
2474 * was a next line to move to, and FALSE if @iter was simply moved to
2475 * the end of the buffer and is now not dereferenceable, or if @iter was
2476 * already at the end of the buffer.
2478 * Return value: whether @iter can be dereferenced
2481 gtk_text_iter_forward_line (GtkTextIter *iter)
2483 GtkTextRealIter *real;
2485 g_return_val_if_fail (iter != NULL, FALSE);
2487 real = gtk_text_iter_make_real (iter);
2492 check_invariants (iter);
2494 if (forward_line_leaving_caches_unmodified (real))
2496 invalidate_char_index (real);
2497 adjust_line_number (real, 1);
2499 check_invariants (iter);
2501 if (gtk_text_iter_is_end (iter))
2508 /* On the last line, move to end of it */
2510 if (!gtk_text_iter_is_end (iter))
2511 gtk_text_iter_forward_to_end (iter);
2513 check_invariants (iter);
2519 * gtk_text_iter_backward_line:
2520 * @iter: an iterator
2522 * Moves @iter to the start of the previous line. Returns TRUE if
2523 * @iter could be moved; i.e. if @iter was at character offset 0, this
2524 * function returns FALSE. Therefore if @iter was already on line 0,
2525 * but not at the start of the line, @iter is snapped to the start of
2526 * the line and the function returns TRUE. (Note that this implies that
2527 * in a loop calling this function, the line number may not change on
2528 * every iteration, if your first iteration is on line 0.)
2530 * Return value: whether @iter moved
2533 gtk_text_iter_backward_line (GtkTextIter *iter)
2535 GtkTextLine *new_line;
2536 GtkTextRealIter *real;
2537 gboolean offset_will_change;
2540 g_return_val_if_fail (iter != NULL, FALSE);
2542 real = gtk_text_iter_make_real (iter);
2547 check_invariants (iter);
2549 new_line = _gtk_text_line_previous (real->line);
2551 offset_will_change = FALSE;
2552 if (real->line_char_offset > 0)
2553 offset_will_change = TRUE;
2555 if (new_line != NULL)
2557 real->line = new_line;
2559 adjust_line_number (real, -1);
2563 if (!offset_will_change)
2567 invalidate_char_index (real);
2569 real->line_byte_offset = 0;
2570 real->line_char_offset = 0;
2572 real->segment_byte_offset = 0;
2573 real->segment_char_offset = 0;
2575 /* Find first segment in line */
2576 real->any_segment = real->line->segments;
2577 real->segment = _gtk_text_line_byte_to_segment (real->line,
2580 g_assert (offset == 0);
2582 /* Note that if we are on the first line, we snap to the start of
2583 * the first line and return TRUE, so TRUE means the iterator
2584 * changed, not that the line changed; this is maybe a bit
2585 * weird. I'm not sure there's an obvious right thing to do though.
2588 check_invariants (iter);
2595 * gtk_text_iter_forward_lines:
2596 * @iter: a #GtkTextIter
2597 * @count: number of lines to move forward
2599 * Moves @count lines forward, if possible (if @count would move
2600 * past the start or end of the buffer, moves to the start or end of
2601 * the buffer). The return value indicates whether the iterator moved
2602 * onto a dereferenceable position; if the iterator didn't move, or
2603 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2604 * the function does nothing and returns FALSE. If @count is negative,
2605 * moves backward by 0 - @count lines.
2607 * Return value: whether @iter moved and is dereferenceable
2610 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2612 FIX_OVERFLOWS (count);
2615 return gtk_text_iter_backward_lines (iter, 0 - count);
2616 else if (count == 0)
2618 else if (count == 1)
2620 check_invariants (iter);
2621 return gtk_text_iter_forward_line (iter);
2627 if (gtk_text_iter_is_end (iter))
2630 old_line = gtk_text_iter_get_line (iter);
2632 gtk_text_iter_set_line (iter, old_line + count);
2634 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2636 /* count went past the last line, so move to end of last line */
2637 if (!gtk_text_iter_is_end (iter))
2638 gtk_text_iter_forward_to_end (iter);
2641 return !gtk_text_iter_is_end (iter);
2646 * gtk_text_iter_backward_lines:
2647 * @iter: a #GtkTextIter
2648 * @count: number of lines to move backward
2650 * Moves @count lines backward, if possible (if @count would move
2651 * past the start or end of the buffer, moves to the start or end of
2652 * the buffer). The return value indicates whether the iterator moved
2653 * onto a dereferenceable position; if the iterator didn't move, or
2654 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2655 * the function does nothing and returns FALSE. If @count is negative,
2656 * moves forward by 0 - @count lines.
2658 * Return value: whether @iter moved and is dereferenceable
2661 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2663 FIX_OVERFLOWS (count);
2666 return gtk_text_iter_forward_lines (iter, 0 - count);
2667 else if (count == 0)
2669 else if (count == 1)
2671 return gtk_text_iter_backward_line (iter);
2677 old_line = gtk_text_iter_get_line (iter);
2679 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2681 return (gtk_text_iter_get_line (iter) != old_line);
2685 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2690 gboolean already_moved_initially);
2692 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2700 find_word_end_func (const PangoLogAttr *attrs,
2705 gboolean already_moved_initially)
2707 if (!already_moved_initially)
2710 /* Find end of next word */
2711 while (offset < min_offset + len &&
2712 !attrs[offset].is_word_end)
2715 *found_offset = offset;
2717 return offset < min_offset + len;
2721 is_word_end_func (const PangoLogAttr *attrs,
2726 return attrs[offset].is_word_end;
2730 find_word_start_func (const PangoLogAttr *attrs,
2735 gboolean already_moved_initially)
2737 if (!already_moved_initially)
2740 /* Find start of prev word */
2741 while (offset >= min_offset &&
2742 !attrs[offset].is_word_start)
2745 *found_offset = offset;
2747 return offset >= min_offset;
2751 is_word_start_func (const PangoLogAttr *attrs,
2756 return attrs[offset].is_word_start;
2760 inside_word_func (const PangoLogAttr *attrs,
2765 /* Find next word start or end */
2766 while (offset >= min_offset &&
2767 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2770 return attrs[offset].is_word_start;
2773 /* Sentence funcs */
2776 find_sentence_end_func (const PangoLogAttr *attrs,
2781 gboolean already_moved_initially)
2783 if (!already_moved_initially)
2786 /* Find end of next sentence */
2787 while (offset < min_offset + len &&
2788 !attrs[offset].is_sentence_end)
2791 *found_offset = offset;
2793 return offset < min_offset + len;
2797 is_sentence_end_func (const PangoLogAttr *attrs,
2802 return attrs[offset].is_sentence_end;
2806 find_sentence_start_func (const PangoLogAttr *attrs,
2811 gboolean already_moved_initially)
2813 if (!already_moved_initially)
2816 /* Find start of prev sentence */
2817 while (offset >= min_offset &&
2818 !attrs[offset].is_sentence_start)
2821 *found_offset = offset;
2823 return offset >= min_offset;
2827 is_sentence_start_func (const PangoLogAttr *attrs,
2832 return attrs[offset].is_sentence_start;
2836 inside_sentence_func (const PangoLogAttr *attrs,
2841 /* Find next sentence start or end */
2842 while (offset >= min_offset &&
2843 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2846 return attrs[offset].is_sentence_start;
2850 test_log_attrs (const GtkTextIter *iter,
2851 TestLogAttrFunc func)
2854 const PangoLogAttr *attrs;
2856 gboolean result = FALSE;
2858 g_return_val_if_fail (iter != NULL, FALSE);
2860 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2863 offset = gtk_text_iter_get_line_offset (iter);
2865 /* char_len may be 0 and attrs will be NULL if so, if
2866 * iter is the end iter and the last line is empty.
2868 * offset may be equal to char_len, since attrs contains an entry
2869 * for one past the end
2872 if (offset <= char_len)
2873 result = (* func) (attrs, offset, 0, char_len);
2879 find_line_log_attrs (const GtkTextIter *iter,
2880 FindLogAttrFunc func,
2882 gboolean already_moved_initially)
2885 const PangoLogAttr *attrs;
2887 gboolean result = FALSE;
2889 g_return_val_if_fail (iter != NULL, FALSE);
2891 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2894 offset = gtk_text_iter_get_line_offset (iter);
2896 /* char_len may be 0 and attrs will be NULL if so, if
2897 * iter is the end iter and the last line is empty
2901 result = (* func) (attrs, offset, 0, char_len, found_offset,
2902 already_moved_initially);
2907 /* FIXME this function is very, very gratuitously slow */
2909 find_by_log_attrs (GtkTextIter *iter,
2910 FindLogAttrFunc func,
2912 gboolean already_moved_initially)
2916 gboolean found = FALSE;
2918 g_return_val_if_fail (iter != NULL, FALSE);
2922 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2928 if (gtk_text_iter_forward_line (iter))
2929 return find_by_log_attrs (iter, func, forward,
2936 /* go to end of previous line. need to check that
2937 * line is > 0 because backward_line snaps to start of
2938 * line 0 if it's on line 0
2940 if (gtk_text_iter_get_line (iter) > 0 &&
2941 gtk_text_iter_backward_line (iter))
2943 if (!gtk_text_iter_ends_line (iter))
2944 gtk_text_iter_forward_to_line_end (iter);
2946 return find_by_log_attrs (iter, func, forward,
2955 gtk_text_iter_set_line_offset (iter, offset);
2958 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2959 !gtk_text_iter_is_end (iter);
2964 * gtk_text_iter_forward_word_end:
2965 * @iter: a #GtkTextIter
2967 * Moves forward to the next word end. (If @iter is currently on a
2968 * word end, moves forward to the next one after that.) Word breaks
2969 * are determined by Pango and should be correct for nearly any
2970 * language (if not, the correct fix would be to the Pango word break
2973 * Return value: %TRUE if @iter moved and is not the end iterator
2976 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2978 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2982 * gtk_text_iter_backward_word_start:
2983 * @iter: a #GtkTextIter
2985 * Moves backward to the next word start. (If @iter is currently on a
2986 * word start, moves backward to the next one after that.) Word breaks
2987 * are determined by Pango and should be correct for nearly any
2988 * language (if not, the correct fix would be to the Pango word break
2991 * Return value: %TRUE if @iter moved and is not the end iterator
2994 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2996 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2999 /* FIXME a loop around a truly slow function means
3000 * a truly spectacularly slow function.
3004 * gtk_text_iter_forward_word_ends:
3005 * @iter: a #GtkTextIter
3006 * @count: number of times to move
3008 * Calls gtk_text_iter_forward_word_end() up to @count times.
3010 * Return value: %TRUE if @iter moved and is not the end iterator
3013 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3016 g_return_val_if_fail (iter != NULL, FALSE);
3018 FIX_OVERFLOWS (count);
3024 return gtk_text_iter_backward_word_starts (iter, -count);
3026 if (!gtk_text_iter_forward_word_end (iter))
3032 if (!gtk_text_iter_forward_word_end (iter))
3040 * gtk_text_iter_backward_word_starts
3041 * @iter: a #GtkTextIter
3042 * @count: number of times to move
3044 * Calls gtk_text_iter_backward_word_starts() up to @count times.
3046 * Return value: %TRUE if @iter moved and is not the end iterator
3049 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3052 g_return_val_if_fail (iter != NULL, FALSE);
3054 FIX_OVERFLOWS (count);
3057 return gtk_text_iter_forward_word_ends (iter, -count);
3059 if (!gtk_text_iter_backward_word_start (iter))
3065 if (!gtk_text_iter_backward_word_start (iter))
3073 * gtk_text_iter_starts_word:
3074 * @iter: a #GtkTextIter
3076 * Determines whether @iter begins a natural-language word. Word
3077 * breaks are determined by Pango and should be correct for nearly any
3078 * language (if not, the correct fix would be to the Pango word break
3081 * Return value: %TRUE if @iter is at the start of a word
3084 gtk_text_iter_starts_word (const GtkTextIter *iter)
3086 return test_log_attrs (iter, is_word_start_func);
3090 * gtk_text_iter_ends_word:
3091 * @iter: a #GtkTextIter
3093 * Determines whether @iter ends a natural-language word. Word breaks
3094 * are determined by Pango and should be correct for nearly any
3095 * language (if not, the correct fix would be to the Pango word break
3098 * Return value: %TRUE if @iter is at the end of a word
3101 gtk_text_iter_ends_word (const GtkTextIter *iter)
3103 return test_log_attrs (iter, is_word_end_func);
3107 * gtk_text_iter_inside_word:
3108 * @iter: a #GtkTextIter
3110 * Determines whether @iter is inside a natural-language word (as
3111 * opposed to say inside some whitespace). Word breaks are determined
3112 * by Pango and should be correct for nearly any language (if not, the
3113 * correct fix would be to the Pango word break algorithms).
3115 * Return value: %TRUE if @iter is inside a word
3118 gtk_text_iter_inside_word (const GtkTextIter *iter)
3120 return test_log_attrs (iter, inside_word_func);
3124 * gtk_text_iter_starts_sentence:
3125 * @iter: a #GtkTextIter
3127 * Determines whether @iter begins a sentence. Sentence boundaries are
3128 * determined by Pango and should be correct for nearly any language
3129 * (if not, the correct fix would be to the Pango text boundary
3132 * Return value: %TRUE if @iter is at the start of a sentence.
3135 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3137 return test_log_attrs (iter, is_sentence_start_func);
3141 * gtk_text_iter_ends_sentence:
3142 * @iter: a #GtkTextIter
3144 * Determines whether @iter ends a sentence. Sentence boundaries are
3145 * determined by Pango and should be correct for nearly any language
3146 * (if not, the correct fix would be to the Pango text boundary
3149 * Return value: %TRUE if @iter is at the end of a sentence.
3152 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3154 return test_log_attrs (iter, is_sentence_end_func);
3158 * gtk_text_iter_inside_sentence:
3159 * @iter: a #GtkTextIter
3161 * Determines whether @iter is inside a sentence (as opposed to in
3162 * between two sentences, e.g. after a period and before the first
3163 * letter of the next sentence). Sentence boundaries are determined
3164 * by Pango and should be correct for nearly any language (if not, the
3165 * correct fix would be to the Pango text boundary algorithms).
3167 * Return value: %TRUE if @iter is inside a sentence.
3170 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3172 return test_log_attrs (iter, inside_sentence_func);
3176 * gtk_text_iter_forward_sentence_end:
3177 * @iter: a #GtkTextIter
3179 * Moves forward to the next sentence end. (If @iter is at the end of
3180 * a sentence, moves to the next end of sentence.) Sentence
3181 * boundaries are determined by Pango and should be correct for nearly
3182 * any language (if not, the correct fix would be to the Pango text
3183 * boundary algorithms).
3185 * Return value: %TRUE if @iter moved and is not the end iterator
3188 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3190 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3194 * gtk_text_iter_backward_sentence_start:
3195 * @iter: a #GtkTextIter
3197 * Moves backward to the next sentence start; if @iter is already at
3198 * the start of a sentence, moves backward to the next one. Sentence
3199 * boundaries are determined by Pango and should be correct for nearly
3200 * any language (if not, the correct fix would be to the Pango text
3201 * boundary algorithms).
3203 * Return value: %TRUE if @iter moved and is not the end iterator
3206 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3208 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3211 /* FIXME a loop around a truly slow function means
3212 * a truly spectacularly slow function.
3215 * gtk_text_iter_forward_sentence_ends:
3216 * @iter: a #GtkTextIter
3217 * @count: number of sentences to move
3219 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3220 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3221 * negative, moves backward instead of forward.
3223 * Return value: %TRUE if @iter moved and is not the end iterator
3226 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3229 g_return_val_if_fail (iter != NULL, FALSE);
3235 return gtk_text_iter_backward_sentence_starts (iter, -count);
3237 if (!gtk_text_iter_forward_sentence_end (iter))
3243 if (!gtk_text_iter_forward_sentence_end (iter))
3251 * gtk_text_iter_backward_sentence_starts:
3252 * @iter: a #GtkTextIter
3253 * @count: number of sentences to move
3255 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3256 * or until it returns %FALSE. If @count is negative, moves forward
3257 * instead of backward.
3259 * Return value: %TRUE if @iter moved and is not the end iterator
3262 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3265 g_return_val_if_fail (iter != NULL, FALSE);
3268 return gtk_text_iter_forward_sentence_ends (iter, -count);
3270 if (!gtk_text_iter_backward_sentence_start (iter))
3276 if (!gtk_text_iter_backward_sentence_start (iter))
3284 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3289 gboolean already_moved_initially)
3291 if (!already_moved_initially)
3294 while (offset < (min_offset + len) &&
3295 !attrs[offset].is_cursor_position)
3298 *found_offset = offset;
3300 return offset < (min_offset + len);
3304 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3309 gboolean already_moved_initially)
3311 if (!already_moved_initially)
3314 while (offset > min_offset &&
3315 !attrs[offset].is_cursor_position)
3318 *found_offset = offset;
3320 return offset >= min_offset;
3324 is_cursor_pos_func (const PangoLogAttr *attrs,
3329 return attrs[offset].is_cursor_position;
3333 * gtk_text_iter_forward_cursor_position:
3334 * @iter: a #GtkTextIter
3336 * Moves @iter forward by a single cursor position. Cursor positions
3337 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3338 * surprisingly, there may not be a cursor position between all
3339 * characters. The most common example for European languages would be
3340 * a carriage return/newline sequence. For some Unicode characters,
3341 * the equivalent of say the letter "a" with an accent mark will be
3342 * represented as two characters, first the letter then a "combining
3343 * mark" that causes the accent to be rendered; so the cursor can't go
3344 * between those two characters. See also the #PangoLogAttr structure and
3345 * pango_break() function.
3347 * Return value: %TRUE if we moved and the new position is dereferenceable
3350 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3352 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3356 * gtk_text_iter_backward_cursor_position:
3357 * @iter: a #GtkTextIter
3359 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3361 * Return value: %TRUE if we moved and the new position is dereferenceable
3364 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3366 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3370 * gtk_text_iter_forward_cursor_positions:
3371 * @iter: a #GtkTextIter
3372 * @count: number of positions to move
3374 * Moves up to @count cursor positions. See
3375 * gtk_text_iter_forward_cursor_position() for details.
3377 * Return value: %TRUE if we moved and the new position is dereferenceable
3380 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3383 g_return_val_if_fail (iter != NULL, FALSE);
3385 FIX_OVERFLOWS (count);
3391 return gtk_text_iter_backward_cursor_positions (iter, -count);
3393 if (!gtk_text_iter_forward_cursor_position (iter))
3399 if (!gtk_text_iter_forward_cursor_position (iter))
3407 * gtk_text_iter_backward_cursor_positions:
3408 * @iter: a #GtkTextIter
3409 * @count: number of positions to move
3411 * Moves up to @count cursor positions. See
3412 * gtk_text_iter_forward_cursor_position() for details.
3414 * Return value: %TRUE if we moved and the new position is dereferenceable
3417 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3420 g_return_val_if_fail (iter != NULL, FALSE);
3422 FIX_OVERFLOWS (count);
3428 return gtk_text_iter_forward_cursor_positions (iter, -count);
3430 if (!gtk_text_iter_backward_cursor_position (iter))
3436 if (!gtk_text_iter_backward_cursor_position (iter))
3444 * gtk_text_iter_is_cursor_position:
3445 * @iter: a #GtkTextIter
3447 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3448 * pango_break() for details on what a cursor position is.
3450 * Return value: %TRUE if the cursor can be placed at @iter
3453 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3455 return test_log_attrs (iter, is_cursor_pos_func);
3459 * gtk_text_iter_set_line_offset:
3460 * @iter: a #GtkTextIter
3461 * @char_on_line: a character offset relative to the start of @iter's current line
3463 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3464 * (not byte) offset. The given character offset must be less than or
3465 * equal to the number of characters in the line; if equal, @iter
3466 * moves to the start of the next line. See
3467 * gtk_text_iter_set_line_index() if you have a byte index rather than
3468 * a character offset.
3472 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3475 GtkTextRealIter *real;
3478 g_return_if_fail (iter != NULL);
3480 real = gtk_text_iter_make_surreal (iter);
3485 check_invariants (iter);
3487 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3489 g_return_if_fail (char_on_line <= chars_in_line);
3491 if (char_on_line < chars_in_line)
3492 iter_set_from_char_offset (real, real->line, char_on_line);
3494 gtk_text_iter_forward_line (iter); /* set to start of next line */
3496 check_invariants (iter);
3500 * gtk_text_iter_set_line_index:
3501 * @iter: a #GtkTextIter
3502 * @byte_on_line: a byte index relative to the start of @iter's current line
3504 * Same as gtk_text_iter_set_line_offset(), but works with a
3505 * <emphasis>byte</emphasis> index. The given byte index must be at
3506 * the start of a character, it can't be in the middle of a UTF-8
3507 * encoded character.
3511 gtk_text_iter_set_line_index (GtkTextIter *iter,
3514 GtkTextRealIter *real;
3517 g_return_if_fail (iter != NULL);
3519 real = gtk_text_iter_make_surreal (iter);
3524 check_invariants (iter);
3526 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3528 g_return_if_fail (byte_on_line <= bytes_in_line);
3530 if (byte_on_line < bytes_in_line)
3531 iter_set_from_byte_offset (real, real->line, byte_on_line);
3533 gtk_text_iter_forward_line (iter);
3535 if (real->segment->type == >k_text_char_type &&
3536 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3537 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3538 "character; this will crash the text buffer. "
3539 "Byte indexes must refer to the start of a character.",
3540 G_STRLOC, byte_on_line);
3542 check_invariants (iter);
3547 * gtk_text_iter_set_visible_line_offset:
3548 * @iter: a #GtkTextIter
3549 * @char_on_line: a character offset
3551 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3552 * characters, i.e. text with a tag making it invisible is not
3553 * counted in the offset.
3556 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3559 gint chars_seen = 0;
3562 g_return_if_fail (iter != NULL);
3566 /* For now we use a ludicrously slow implementation */
3567 while (chars_seen < char_on_line)
3569 if (!_gtk_text_btree_char_is_invisible (&pos))
3572 if (!gtk_text_iter_forward_char (&pos))
3575 if (chars_seen == char_on_line)
3579 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3582 gtk_text_iter_forward_line (iter);
3586 bytes_in_char (GtkTextIter *iter)
3588 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3592 * gtk_text_iter_set_visible_line_index:
3593 * @iter: a #GtkTextIter
3594 * @byte_on_line: a byte index
3596 * Like gtk_text_iter_set_line_index(), but the index is in visible
3597 * bytes, i.e. text with a tag making it invisible is not counted
3601 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3604 gint bytes_seen = 0;
3607 g_return_if_fail (iter != NULL);
3611 /* For now we use a ludicrously slow implementation */
3612 while (bytes_seen < byte_on_line)
3614 if (!_gtk_text_btree_char_is_invisible (&pos))
3615 bytes_seen += bytes_in_char (&pos);
3617 if (!gtk_text_iter_forward_char (&pos))
3620 if (bytes_seen >= byte_on_line)
3624 if (bytes_seen > byte_on_line)
3625 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3626 "character; this will crash the text buffer. "
3627 "Byte indexes must refer to the start of a character.",
3628 G_STRLOC, byte_on_line);
3630 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3633 gtk_text_iter_forward_line (iter);
3637 * gtk_text_iter_set_line:
3638 * @iter: a #GtkTextIter
3639 * @line_number: line number (counted from 0)
3641 * Moves iterator @iter to the start of the line @line_number. If
3642 * @line_number is negative or larger than the number of lines in the
3643 * buffer, moves @iter to the start of the last line in the buffer.
3647 gtk_text_iter_set_line (GtkTextIter *iter,
3652 GtkTextRealIter *real;
3654 g_return_if_fail (iter != NULL);
3656 real = gtk_text_iter_make_surreal (iter);
3661 check_invariants (iter);
3663 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3665 iter_set_from_char_offset (real, line, 0);
3667 /* We might as well cache this, since we know it. */
3668 real->cached_line_number = real_line;
3670 check_invariants (iter);
3674 * gtk_text_iter_set_offset:
3675 * @iter: a #GtkTextIter
3676 * @char_offset: a character number
3678 * Sets @iter to point to @char_offset. @char_offset counts from the start
3679 * of the entire text buffer, starting with 0.
3683 gtk_text_iter_set_offset (GtkTextIter *iter,
3687 GtkTextRealIter *real;
3689 gint real_char_index;
3691 g_return_if_fail (iter != NULL);
3693 real = gtk_text_iter_make_surreal (iter);
3698 check_invariants (iter);
3700 if (real->cached_char_index >= 0 &&
3701 real->cached_char_index == char_offset)
3704 line = _gtk_text_btree_get_line_at_char (real->tree,
3709 iter_set_from_char_offset (real, line, real_char_index - line_start);
3711 /* Go ahead and cache this since we have it. */
3712 real->cached_char_index = real_char_index;
3714 check_invariants (iter);
3718 * gtk_text_iter_forward_to_end:
3719 * @iter: a #GtkTextIter
3721 * Moves @iter forward to the "end iterator," which points one past the last
3722 * valid character in the buffer. gtk_text_iter_get_char() called on the
3723 * end iterator returns 0, which is convenient for writing loops.
3727 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3729 GtkTextBuffer *buffer;
3730 GtkTextRealIter *real;
3732 g_return_if_fail (iter != NULL);
3734 real = gtk_text_iter_make_surreal (iter);
3739 buffer = _gtk_text_btree_get_buffer (real->tree);
3741 gtk_text_buffer_get_end_iter (buffer, iter);
3744 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3745 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3746 * If all else fails we could cache the para delimiter pos in the iter.
3747 * I think forward_to_line_end() actually gets called fairly often.
3750 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3755 /* if we aren't on the last line, go forward to start of next line, then scan
3756 * back for the delimiters on the previous line
3758 if (gtk_text_iter_forward_line (&end))
3760 gtk_text_iter_backward_char (&end);
3761 while (!gtk_text_iter_ends_line (&end))
3762 gtk_text_iter_backward_char (&end);
3765 return gtk_text_iter_get_line_offset (&end);
3769 * gtk_text_iter_forward_to_line_end:
3770 * @iter: a #GtkTextIter
3772 * Moves the iterator to point to the paragraph delimiter characters,
3773 * which will be either a newline, a carriage return, a carriage
3774 * return/newline in sequence, or the Unicode paragraph separator
3775 * character. If the iterator is already at the paragraph delimiter
3776 * characters, moves to the paragraph delimiter characters for the
3777 * next line. If @iter is on the last line in the buffer, which does
3778 * not end in paragraph delimiters, moves to the end iterator (end of
3779 * the last line), and returns %FALSE.
3781 * Return value: %TRUE if we moved and the new location is not the end iterator
3784 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3786 gint current_offset;
3790 g_return_val_if_fail (iter != NULL, FALSE);
3792 current_offset = gtk_text_iter_get_line_offset (iter);
3793 new_offset = find_paragraph_delimiter_for_line (iter);
3795 if (current_offset < new_offset)
3797 /* Move to end of this line. */
3798 gtk_text_iter_set_line_offset (iter, new_offset);
3803 /* Move to end of next line. */
3804 if (gtk_text_iter_forward_line (iter))
3806 /* We don't want to move past all
3809 if (!gtk_text_iter_ends_line (iter))
3810 gtk_text_iter_forward_to_line_end (iter);
3819 * gtk_text_iter_forward_to_tag_toggle:
3820 * @iter: a #GtkTextIter
3821 * @tag: a #GtkTextTag, or NULL
3823 * Moves forward to the next toggle (on or off) of the
3824 * #GtkTextTag @tag, or to the next toggle of any tag if
3825 * @tag is NULL. If no matching tag toggles are found,
3826 * returns FALSE, otherwise TRUE. Does not return toggles
3827 * located at @iter, only toggles after @iter. Sets @iter to
3828 * the location of the toggle, or to the end of the buffer
3829 * if no toggle is found.
3831 * Return value: whether we found a tag toggle after @iter
3834 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3837 GtkTextLine *next_line;
3838 GtkTextLine *current_line;
3839 GtkTextRealIter *real;
3841 g_return_val_if_fail (iter != NULL, FALSE);
3843 real = gtk_text_iter_make_real (iter);
3848 check_invariants (iter);
3850 current_line = real->line;
3851 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3854 while (_gtk_text_iter_forward_indexable_segment (iter))
3856 /* If we went forward to a line that couldn't contain a toggle
3857 for the tag, then skip forward to a line that could contain
3858 it. This potentially skips huge hunks of the tree, so we
3859 aren't a purely linear search. */
3860 if (real->line != current_line)
3862 if (next_line == NULL)
3864 /* End of search. Set to end of buffer. */
3865 _gtk_text_btree_get_end_iter (real->tree, iter);
3869 if (real->line != next_line)
3870 iter_set_from_byte_offset (real, next_line, 0);
3872 current_line = real->line;
3873 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3878 if (gtk_text_iter_toggles_tag (iter, tag))
3880 /* If there's a toggle here, it isn't indexable so
3881 any_segment can't be the indexable segment. */
3882 g_assert (real->any_segment != real->segment);
3887 /* Check end iterator for tags */
3888 if (gtk_text_iter_toggles_tag (iter, tag))
3890 /* If there's a toggle here, it isn't indexable so
3891 any_segment can't be the indexable segment. */
3892 g_assert (real->any_segment != real->segment);
3896 /* Reached end of buffer */
3901 * gtk_text_iter_backward_to_tag_toggle:
3902 * @iter: a #GtkTextIter
3903 * @tag: a #GtkTextTag, or NULL
3905 * Moves backward to the next toggle (on or off) of the
3906 * #GtkTextTag @tag, or to the next toggle of any tag if
3907 * @tag is NULL. If no matching tag toggles are found,
3908 * returns FALSE, otherwise TRUE. Does not return toggles
3909 * located at @iter, only toggles before @iter. Sets @iter
3910 * to the location of the toggle, or the start of the buffer
3911 * if no toggle is found.
3913 * Return value: whether we found a tag toggle before @iter
3916 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3919 GtkTextLine *prev_line;
3920 GtkTextLine *current_line;
3921 GtkTextRealIter *real;
3923 g_return_val_if_fail (iter != NULL, FALSE);
3925 real = gtk_text_iter_make_real (iter);
3930 check_invariants (iter);
3932 current_line = real->line;
3933 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3937 /* If we're at segment start, go to the previous segment;
3938 * if mid-segment, snap to start of current segment.
3940 if (is_segment_start (real))
3942 if (!_gtk_text_iter_backward_indexable_segment (iter))
3947 ensure_char_offsets (real);
3949 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3955 /* If we went backward to a line that couldn't contain a toggle
3956 * for the tag, then skip backward further to a line that
3957 * could contain it. This potentially skips huge hunks of the
3958 * tree, so we aren't a purely linear search.
3960 if (real->line != current_line)
3962 if (prev_line == NULL)
3964 /* End of search. Set to start of buffer. */
3965 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3969 if (real->line != prev_line)
3971 /* Set to last segment in prev_line (could do this
3974 iter_set_from_byte_offset (real, prev_line, 0);
3976 while (!at_last_indexable_segment (real))
3977 _gtk_text_iter_forward_indexable_segment (iter);
3980 current_line = real->line;
3981 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3986 if (gtk_text_iter_toggles_tag (iter, tag))
3988 /* If there's a toggle here, it isn't indexable so
3989 * any_segment can't be the indexable segment.
3991 g_assert (real->any_segment != real->segment);
3995 while (_gtk_text_iter_backward_indexable_segment (iter));
3997 /* Reached front of buffer */
4002 matches_pred (GtkTextIter *iter,
4003 GtkTextCharPredicate pred,
4008 ch = gtk_text_iter_get_char (iter);
4010 return (*pred) (ch, user_data);
4014 * gtk_text_iter_forward_find_char:
4015 * @iter: a #GtkTextIter
4016 * @pred: a function to be called on each character
4017 * @user_data: user data for @pred
4018 * @limit: search limit, or %NULL for none
4020 * Advances @iter, calling @pred on each character. If
4021 * @pred returns %TRUE, returns %TRUE and stops scanning.
4022 * If @pred never returns %TRUE, @iter is set to @limit if
4023 * @limit is non-%NULL, otherwise to the end iterator.
4025 * Return value: whether a match was found
4028 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4029 GtkTextCharPredicate pred,
4031 const GtkTextIter *limit)
4033 g_return_val_if_fail (iter != NULL, FALSE);
4034 g_return_val_if_fail (pred != NULL, FALSE);
4037 gtk_text_iter_compare (iter, limit) >= 0)
4040 while ((limit == NULL ||
4041 !gtk_text_iter_equal (limit, iter)) &&
4042 gtk_text_iter_forward_char (iter))
4044 if (matches_pred (iter, pred, user_data))
4052 * gtk_text_iter_backward_find_char:
4053 * @iter: a #GtkTextIter
4054 * @pred: function to be called on each character
4055 * @user_data: user data for @pred
4056 * @limit: search limit, or %NULL for none
4058 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4060 * Return value: whether a match was found
4063 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4064 GtkTextCharPredicate pred,
4066 const GtkTextIter *limit)
4068 g_return_val_if_fail (iter != NULL, FALSE);
4069 g_return_val_if_fail (pred != NULL, FALSE);
4072 gtk_text_iter_compare (iter, limit) <= 0)
4075 while ((limit == NULL ||
4076 !gtk_text_iter_equal (limit, iter)) &&
4077 gtk_text_iter_backward_char (iter))
4079 if (matches_pred (iter, pred, user_data))
4087 forward_chars_with_skipping (GtkTextIter *iter,
4089 gboolean skip_invisible,
4090 gboolean skip_nontext)
4095 g_return_if_fail (count >= 0);
4101 gboolean ignored = FALSE;
4104 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4109 _gtk_text_btree_char_is_invisible (iter))
4112 gtk_text_iter_forward_char (iter);
4120 lines_match (const GtkTextIter *start,
4121 const gchar **lines,
4122 gboolean visible_only,
4124 GtkTextIter *match_start,
4125 GtkTextIter *match_end)
4132 if (*lines == NULL || **lines == '\0')
4135 *match_start = *start;
4138 *match_end = *start;
4143 gtk_text_iter_forward_line (&next);
4145 /* No more text in buffer, but *lines is nonempty */
4146 if (gtk_text_iter_equal (start, &next))
4154 line_text = gtk_text_iter_get_visible_slice (start, &next);
4156 line_text = gtk_text_iter_get_slice (start, &next);
4161 line_text = gtk_text_iter_get_visible_text (start, &next);
4163 line_text = gtk_text_iter_get_text (start, &next);
4166 if (match_start) /* if this is the first line we're matching */
4167 found = strstr (line_text, *lines);
4170 /* If it's not the first line, we have to match from the
4171 * start of the line.
4173 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4185 /* Get offset to start of search string */
4186 offset = g_utf8_strlen (line_text, found - line_text);
4190 /* If match start needs to be returned, set it to the
4191 * start of the search string.
4195 *match_start = next;
4197 forward_chars_with_skipping (match_start, offset,
4198 visible_only, !slice);
4201 /* Go to end of search string */
4202 offset += g_utf8_strlen (*lines, -1);
4204 forward_chars_with_skipping (&next, offset,
4205 visible_only, !slice);
4214 /* pass NULL for match_start, since we don't need to find the
4217 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4220 /* strsplit () that retains the delimiter as part of the string. */
4222 strbreakup (const char *string,
4223 const char *delimiter,
4226 GSList *string_list = NULL, *slist;
4227 gchar **str_array, *s;
4230 g_return_val_if_fail (string != NULL, NULL);
4231 g_return_val_if_fail (delimiter != NULL, NULL);
4234 max_tokens = G_MAXINT;
4236 s = strstr (string, delimiter);
4239 guint delimiter_len = strlen (delimiter);
4246 len = s - string + delimiter_len;
4247 new_string = g_new (gchar, len + 1);
4248 strncpy (new_string, string, len);
4249 new_string[len] = 0;
4250 string_list = g_slist_prepend (string_list, new_string);
4252 string = s + delimiter_len;
4253 s = strstr (string, delimiter);
4255 while (--max_tokens && s);
4260 string_list = g_slist_prepend (string_list, g_strdup (string));
4263 str_array = g_new (gchar*, n);
4267 str_array[i--] = NULL;
4268 for (slist = string_list; slist; slist = slist->next)
4269 str_array[i--] = slist->data;
4271 g_slist_free (string_list);
4277 * gtk_text_iter_forward_search:
4278 * @iter: start of search
4279 * @str: a search string
4280 * @flags: flags affecting how the search is done
4281 * @match_start: return location for start of match, or %NULL
4282 * @match_end: return location for end of match, or %NULL
4283 * @limit: bound for the search, or %NULL for the end of the buffer
4285 * Searches forward for @str. Any match is returned as the range
4286 * @match_start, @match_end. The search will not continue past
4287 * @limit. Note that a search is a linear or O(n) operation, so you
4288 * may wish to use @limit to avoid locking up your UI on large
4291 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4292 * have invisible text interspersed in @str. i.e. @str will be a
4293 * possibly-noncontiguous subsequence of the matched range. similarly,
4294 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4295 * pixbufs or child widgets mixed inside the matched range. If these
4296 * flags are not given, the match must be exact; the special 0xFFFC
4297 * character in @str will match embedded pixbufs or child widgets.
4299 * Return value: whether a match was found
4302 gtk_text_iter_forward_search (const GtkTextIter *iter,
4304 GtkTextSearchFlags flags,
4305 GtkTextIter *match_start,
4306 GtkTextIter *match_end,
4307 const GtkTextIter *limit)
4309 gchar **lines = NULL;
4311 gboolean retval = FALSE;
4313 gboolean visible_only;
4316 g_return_val_if_fail (iter != NULL, FALSE);
4317 g_return_val_if_fail (str != NULL, FALSE);
4320 gtk_text_iter_compare (iter, limit) >= 0)
4325 /* If we can move one char, return the empty string there */
4328 if (gtk_text_iter_forward_char (&match))
4331 gtk_text_iter_equal (&match, limit))
4335 *match_start = match;
4344 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4345 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4347 /* locate all lines */
4349 lines = strbreakup (str, "\n", -1);
4355 /* This loop has an inefficient worst-case, where
4356 * gtk_text_iter_get_text () is called repeatedly on
4362 gtk_text_iter_compare (&search, limit) >= 0)
4365 if (lines_match (&search, (const gchar**)lines,
4366 visible_only, slice, &match, &end))
4368 if (limit == NULL ||
4370 gtk_text_iter_compare (&end, limit) < 0))
4375 *match_start = match;
4384 while (gtk_text_iter_forward_line (&search));
4386 g_strfreev ((gchar**)lines);
4392 vectors_equal_ignoring_trailing (gchar **vec1,
4395 /* Ignores trailing chars in vec2's last line */
4404 if (strcmp (*i1, *i2) != 0)
4406 if (*(i2 + 1) == NULL) /* if this is the last line */
4408 gint len1 = strlen (*i1);
4409 gint len2 = strlen (*i2);
4412 strncmp (*i1, *i2, len1) == 0)
4414 /* We matched ignoring the trailing stuff in vec2 */
4439 typedef struct _LinesWindow LinesWindow;
4445 GtkTextIter first_line_start;
4446 GtkTextIter first_line_end;
4448 gboolean visible_only;
4452 lines_window_init (LinesWindow *win,
4453 const GtkTextIter *start)
4456 GtkTextIter line_start;
4457 GtkTextIter line_end;
4459 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4462 if (gtk_text_iter_is_start (start) ||
4463 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4465 /* Already at the end, or not enough lines to match */
4466 win->lines = g_new0 (gchar*, 1);
4471 line_start = *start;
4474 /* Move to start iter to start of line */
4475 gtk_text_iter_set_line_offset (&line_start, 0);
4477 if (gtk_text_iter_equal (&line_start, &line_end))
4479 /* we were already at the start; so go back one line */
4480 gtk_text_iter_backward_line (&line_start);
4483 win->first_line_start = line_start;
4484 win->first_line_end = line_end;
4486 win->lines = g_new0 (gchar*, win->n_lines + 1);
4488 i = win->n_lines - 1;
4495 if (win->visible_only)
4496 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4498 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4502 if (win->visible_only)
4503 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4505 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4508 win->lines[i] = line_text;
4510 line_end = line_start;
4511 gtk_text_iter_backward_line (&line_start);
4518 lines_window_back (LinesWindow *win)
4520 GtkTextIter new_start;
4523 new_start = win->first_line_start;
4525 if (!gtk_text_iter_backward_line (&new_start))
4529 win->first_line_start = new_start;
4530 win->first_line_end = new_start;
4532 gtk_text_iter_forward_line (&win->first_line_end);
4537 if (win->visible_only)
4538 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4539 &win->first_line_end);
4541 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4542 &win->first_line_end);
4546 if (win->visible_only)
4547 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4548 &win->first_line_end);
4550 line_text = gtk_text_iter_get_text (&win->first_line_start,
4551 &win->first_line_end);
4554 /* Move lines to make room for first line. */
4555 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4557 *win->lines = line_text;
4559 /* Free old last line and NULL-terminate */
4560 g_free (win->lines[win->n_lines]);
4561 win->lines[win->n_lines] = NULL;
4567 lines_window_free (LinesWindow *win)
4569 g_strfreev (win->lines);
4573 my_strrstr (const gchar *haystack,
4574 const gchar *needle)
4576 /* FIXME GLib should have a nice implementation in it, this
4580 gint haystack_len = strlen (haystack);
4581 gint needle_len = strlen (needle);
4582 const gchar *needle_end = needle + needle_len;
4583 const gchar *haystack_rend = haystack - 1;
4584 const gchar *needle_rend = needle - 1;
4587 p = haystack + haystack_len;
4588 while (p != haystack)
4590 const gchar *n = needle_end - 1;
4591 const gchar *s = p - 1;
4592 while (s != haystack_rend &&
4600 if (n == needle_rend)
4610 * gtk_text_iter_backward_search:
4611 * @iter: a #GtkTextIter where the search begins
4612 * @str: search string
4613 * @flags: bitmask of flags affecting the search
4614 * @match_start: return location for start of match, or %NULL
4615 * @match_end: return location for end of match, or %NULL
4616 * @limit: location of last possible @match_start, or %NULL for start of buffer
4618 * Same as gtk_text_iter_forward_search(), but moves backward.
4620 * Return value: whether a match was found
4623 gtk_text_iter_backward_search (const GtkTextIter *iter,
4625 GtkTextSearchFlags flags,
4626 GtkTextIter *match_start,
4627 GtkTextIter *match_end,
4628 const GtkTextIter *limit)
4630 gchar **lines = NULL;
4634 gboolean retval = FALSE;
4635 gboolean visible_only;
4638 g_return_val_if_fail (iter != NULL, FALSE);
4639 g_return_val_if_fail (str != NULL, FALSE);
4642 gtk_text_iter_compare (limit, iter) > 0)
4647 /* If we can move one char, return the empty string there */
4648 GtkTextIter match = *iter;
4650 if (limit && gtk_text_iter_equal (limit, &match))
4653 if (gtk_text_iter_backward_char (&match))
4656 *match_start = match;
4665 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4666 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4668 /* locate all lines */
4670 lines = strbreakup (str, "\n", -1);
4680 win.n_lines = n_lines;
4682 win.visible_only = visible_only;
4684 lines_window_init (&win, iter);
4686 if (*win.lines == NULL)
4691 gchar *first_line_match;
4694 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4696 /* We're now before the search limit, abort. */
4700 /* If there are multiple lines, the first line will
4701 * end in '\n', so this will only match at the
4702 * end of the first line, which is correct.
4704 first_line_match = my_strrstr (*win.lines, *lines);
4706 if (first_line_match &&
4707 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4712 GtkTextIter start_tmp;
4714 /* Offset to start of search string */
4715 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4717 next = win.first_line_start;
4719 forward_chars_with_skipping (&start_tmp, offset,
4720 visible_only, !slice);
4723 gtk_text_iter_compare (limit, &start_tmp) > 0)
4724 goto out; /* match was bogus */
4727 *match_start = start_tmp;
4729 /* Go to end of search string */
4733 offset += g_utf8_strlen (*l, -1);
4737 forward_chars_with_skipping (&next, offset,
4738 visible_only, !slice);
4747 while (lines_window_back (&win));
4750 lines_window_free (&win);
4761 * gtk_text_iter_equal:
4762 * @lhs: a #GtkTextIter
4763 * @rhs: another #GtkTextIter
4765 * Tests whether two iterators are equal, using the fastest possible
4766 * mechanism. This function is very fast; you can expect it to perform
4767 * better than e.g. getting the character offset for each iterator and
4768 * comparing the offsets yourself. Also, it's a bit faster than
4769 * gtk_text_iter_compare().
4771 * Return value: %TRUE if the iterators point to the same place in the buffer
4774 gtk_text_iter_equal (const GtkTextIter *lhs,
4775 const GtkTextIter *rhs)
4777 GtkTextRealIter *real_lhs;
4778 GtkTextRealIter *real_rhs;
4780 real_lhs = (GtkTextRealIter*)lhs;
4781 real_rhs = (GtkTextRealIter*)rhs;
4783 check_invariants (lhs);
4784 check_invariants (rhs);
4786 if (real_lhs->line != real_rhs->line)
4788 else if (real_lhs->line_byte_offset >= 0 &&
4789 real_rhs->line_byte_offset >= 0)
4790 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4793 /* the ensure_char_offsets () calls do nothing if the char offsets
4794 are already up-to-date. */
4795 ensure_char_offsets (real_lhs);
4796 ensure_char_offsets (real_rhs);
4797 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4802 * gtk_text_iter_compare:
4803 * @lhs: a #GtkTextIter
4804 * @rhs: another #GtkTextIter
4806 * A qsort()-style function that returns negative if @lhs is less than
4807 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4808 * Ordering is in character offset order, i.e. the first character in the buffer
4809 * is less than the second character in the buffer.
4811 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4814 gtk_text_iter_compare (const GtkTextIter *lhs,
4815 const GtkTextIter *rhs)
4817 GtkTextRealIter *real_lhs;
4818 GtkTextRealIter *real_rhs;
4820 real_lhs = gtk_text_iter_make_surreal (lhs);
4821 real_rhs = gtk_text_iter_make_surreal (rhs);
4823 if (real_lhs == NULL ||
4825 return -1; /* why not */
4827 check_invariants (lhs);
4828 check_invariants (rhs);
4830 if (real_lhs->line == real_rhs->line)
4832 gint left_index, right_index;
4834 if (real_lhs->line_byte_offset >= 0 &&
4835 real_rhs->line_byte_offset >= 0)
4837 left_index = real_lhs->line_byte_offset;
4838 right_index = real_rhs->line_byte_offset;
4842 /* the ensure_char_offsets () calls do nothing if
4843 the offsets are already up-to-date. */
4844 ensure_char_offsets (real_lhs);
4845 ensure_char_offsets (real_rhs);
4846 left_index = real_lhs->line_char_offset;
4847 right_index = real_rhs->line_char_offset;
4850 if (left_index < right_index)
4852 else if (left_index > right_index)
4861 line1 = gtk_text_iter_get_line (lhs);
4862 line2 = gtk_text_iter_get_line (rhs);
4865 else if (line1 > line2)
4873 * gtk_text_iter_in_range:
4874 * @iter: a #GtkTextIter
4875 * @start: start of range
4876 * @end: end of range
4878 * Checks whether @iter falls in the range [@start, @end).
4879 * @start and @end must be in ascending order.
4881 * Return value: %TRUE if @iter is in the range
4884 gtk_text_iter_in_range (const GtkTextIter *iter,
4885 const GtkTextIter *start,
4886 const GtkTextIter *end)
4888 g_return_val_if_fail (iter != NULL, FALSE);
4889 g_return_val_if_fail (start != NULL, FALSE);
4890 g_return_val_if_fail (end != NULL, FALSE);
4891 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4893 return gtk_text_iter_compare (iter, start) >= 0 &&
4894 gtk_text_iter_compare (iter, end) < 0;
4898 * gtk_text_iter_order:
4899 * @first: a #GtkTextIter
4900 * @second: another #GtkTextIter
4902 * Swaps the value of @first and @second if @second comes before
4903 * @first in the buffer. That is, ensures that @first and @second are
4904 * in sequence. Most text buffer functions that take a range call this
4905 * automatically on your behalf, so there's no real reason to call it yourself
4906 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4907 * that expect a pre-sorted range.
4911 gtk_text_iter_order (GtkTextIter *first,
4912 GtkTextIter *second)
4914 g_return_if_fail (first != NULL);
4915 g_return_if_fail (second != NULL);
4917 if (gtk_text_iter_compare (first, second) > 0)
4928 * Init iterators from the BTree
4932 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4936 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4937 gint real_char_index;
4941 g_return_if_fail (iter != NULL);
4942 g_return_if_fail (tree != NULL);
4944 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4945 &line_start, &real_char_index);
4947 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4949 real->cached_char_index = real_char_index;
4951 check_invariants (iter);
4955 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4960 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4964 g_return_if_fail (iter != NULL);
4965 g_return_if_fail (tree != NULL);
4967 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
4969 iter_init_from_char_offset (iter, tree, line, char_on_line);
4971 /* We might as well cache this, since we know it. */
4972 real->cached_line_number = real_line;
4974 check_invariants (iter);
4978 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4983 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4987 g_return_if_fail (iter != NULL);
4988 g_return_if_fail (tree != NULL);
4990 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
4992 iter_init_from_byte_offset (iter, tree, line, byte_index);
4994 /* We might as well cache this, since we know it. */
4995 real->cached_line_number = real_line;
4997 check_invariants (iter);
5001 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5006 g_return_if_fail (iter != NULL);
5007 g_return_if_fail (tree != NULL);
5008 g_return_if_fail (line != NULL);
5010 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5012 check_invariants (iter);
5016 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5022 g_return_val_if_fail (iter != NULL, FALSE);
5023 g_return_val_if_fail (tree != NULL, FALSE);
5025 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5029 /* Set iter to last in tree */
5030 _gtk_text_btree_get_end_iter (tree, iter);
5031 check_invariants (iter);
5036 iter_init_from_byte_offset (iter, tree, line, 0);
5037 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5038 check_invariants (iter);
5044 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5048 g_return_val_if_fail (iter != NULL, FALSE);
5049 g_return_val_if_fail (tree != NULL, FALSE);
5051 _gtk_text_btree_get_end_iter (tree, iter);
5052 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5053 check_invariants (iter);
5059 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5061 const gchar *mark_name)
5065 g_return_val_if_fail (iter != NULL, FALSE);
5066 g_return_val_if_fail (tree != NULL, FALSE);
5068 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5074 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5075 check_invariants (iter);
5081 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5085 GtkTextLineSegment *seg;
5087 g_return_if_fail (iter != NULL);
5088 g_return_if_fail (tree != NULL);
5089 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5091 seg = mark->segment;
5093 iter_init_from_segment (iter, tree,
5094 seg->body.mark.line, seg);
5095 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5096 check_invariants (iter);
5100 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5102 GtkTextChildAnchor *anchor)
5104 GtkTextLineSegment *seg;
5106 g_return_if_fail (iter != NULL);
5107 g_return_if_fail (tree != NULL);
5108 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5110 seg = anchor->segment;
5112 iter_init_from_segment (iter, tree,
5113 seg->body.child.line, seg);
5114 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5115 check_invariants (iter);
5119 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5122 g_return_if_fail (iter != NULL);
5123 g_return_if_fail (tree != NULL);
5125 _gtk_text_btree_get_iter_at_char (tree,
5127 _gtk_text_btree_char_count (tree));
5128 check_invariants (iter);
5132 _gtk_text_iter_check (const GtkTextIter *iter)
5134 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5135 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5136 GtkTextLineSegment *byte_segment = NULL;
5137 GtkTextLineSegment *byte_any_segment = NULL;
5138 GtkTextLineSegment *char_segment = NULL;
5139 GtkTextLineSegment *char_any_segment = NULL;
5140 gboolean segments_updated;
5142 /* This function checks our class invariants for the Iter class. */
5144 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5146 if (real->chars_changed_stamp !=
5147 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5148 g_error ("iterator check failed: invalid iterator");
5150 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5151 g_error ("iterator check failed: both char and byte offsets are invalid");
5153 segments_updated = (real->segments_changed_stamp ==
5154 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5157 printf ("checking iter, segments %s updated, byte %d char %d\n",
5158 segments_updated ? "are" : "aren't",
5159 real->line_byte_offset,
5160 real->line_char_offset);
5163 if (segments_updated)
5165 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5166 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5168 if (real->segment->char_count == 0)
5169 g_error ("iterator check failed: segment is not indexable.");
5171 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5172 g_error ("segment char offset is not properly up-to-date");
5174 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5175 g_error ("segment byte offset is not properly up-to-date");
5177 if (real->segment_byte_offset >= 0 &&
5178 real->segment_byte_offset >= real->segment->byte_count)
5179 g_error ("segment byte offset is too large.");
5181 if (real->segment_char_offset >= 0 &&
5182 real->segment_char_offset >= real->segment->char_count)
5183 g_error ("segment char offset is too large.");
5186 if (real->line_byte_offset >= 0)
5188 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5189 &byte_segment, &byte_any_segment,
5190 &seg_byte_offset, &line_byte_offset);
5192 if (line_byte_offset != real->line_byte_offset)
5193 g_error ("wrong byte offset was stored in iterator");
5195 if (segments_updated)
5197 if (real->segment != byte_segment)
5198 g_error ("wrong segment was stored in iterator");
5200 if (real->any_segment != byte_any_segment)
5201 g_error ("wrong any_segment was stored in iterator");
5203 if (seg_byte_offset != real->segment_byte_offset)
5204 g_error ("wrong segment byte offset was stored in iterator");
5206 if (byte_segment->type == >k_text_char_type)
5209 p = byte_segment->body.chars + seg_byte_offset;
5211 if (!gtk_text_byte_begins_utf8_char (p))
5212 g_error ("broken iterator byte index pointed into the middle of a character");
5217 if (real->line_char_offset >= 0)
5219 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5220 &char_segment, &char_any_segment,
5221 &seg_char_offset, &line_char_offset);
5223 if (line_char_offset != real->line_char_offset)
5224 g_error ("wrong char offset was stored in iterator");
5226 if (segments_updated)
5228 if (real->segment != char_segment)
5229 g_error ("wrong segment was stored in iterator");
5231 if (real->any_segment != char_any_segment)
5232 g_error ("wrong any_segment was stored in iterator");
5234 if (seg_char_offset != real->segment_char_offset)
5235 g_error ("wrong segment char offset was stored in iterator");
5237 if (char_segment->type == >k_text_char_type)
5240 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5243 /* hmm, not likely to happen eh */
5244 if (!gtk_text_byte_begins_utf8_char (p))
5245 g_error ("broken iterator char offset pointed into the middle of a character");
5250 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5252 if (byte_segment != char_segment)
5253 g_error ("char and byte offsets did not point to the same segment");
5255 if (byte_any_segment != char_any_segment)
5256 g_error ("char and byte offsets did not point to the same any segment");
5258 /* Make sure the segment offsets are equivalent, if it's a char
5260 if (char_segment->type == >k_text_char_type)
5262 gint byte_offset = 0;
5263 gint char_offset = 0;
5264 while (char_offset < seg_char_offset)
5266 const char * start = char_segment->body.chars + byte_offset;
5267 byte_offset += g_utf8_next_char (start) - start;
5271 if (byte_offset != seg_byte_offset)
5272 g_error ("byte offset did not correspond to char offset");
5275 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5277 if (char_offset != seg_char_offset)
5278 g_error ("char offset did not correspond to byte offset");
5280 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5281 g_error ("byte index for iterator does not index the start of a character");
5285 if (real->cached_line_number >= 0)
5289 should_be = _gtk_text_line_get_number (real->line);
5290 if (real->cached_line_number != should_be)
5291 g_error ("wrong line number was cached");
5294 if (real->cached_char_index >= 0)
5296 if (real->line_char_offset >= 0) /* only way we can check it
5297 efficiently, not a real
5302 char_index = _gtk_text_line_char_index (real->line);
5303 char_index += real->line_char_offset;
5305 if (real->cached_char_index != char_index)
5306 g_error ("wrong char index was cached");
5310 if (_gtk_text_line_is_last (real->line, real->tree))
5311 g_error ("Iterator was on last line (past the end iterator)");