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 /* <, not <=, because if count == segment_char_offset
2351 * we're going to the front of the segment and the any_segment
2354 if (count < real->segment_char_offset)
2356 /* Optimize the within-segment case */
2357 g_assert (real->segment->char_count > 0);
2358 g_assert (real->segment->type == >k_text_char_type);
2360 real->segment_char_offset -= count;
2361 g_assert (real->segment_char_offset >= 0);
2363 if (real->line_byte_offset >= 0)
2365 gint new_byte_offset;
2368 new_byte_offset = 0;
2370 while (i < real->segment_char_offset)
2372 const char * start = real->segment->body.chars + new_byte_offset;
2373 new_byte_offset += g_utf8_next_char (start) - start;
2378 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2379 real->segment_byte_offset = new_byte_offset;
2382 real->line_char_offset -= count;
2384 adjust_char_index (real, 0 - count);
2386 check_invariants (iter);
2392 /* We need to go back into previous segments. For now,
2393 * just keep this really simple. FIXME
2394 * use backward_indexable_segment.
2396 if (TRUE || count > MAX_LINEAR_SCAN)
2398 gint current_char_index;
2399 gint new_char_index;
2401 current_char_index = gtk_text_iter_get_offset (iter);
2403 if (current_char_index == 0)
2404 return FALSE; /* can't move backward */
2406 new_char_index = current_char_index - count;
2407 if (new_char_index < 0)
2410 gtk_text_iter_set_offset (iter, new_char_index);
2412 check_invariants (iter);
2418 /* FIXME backward_indexable_segment here */
2427 /* These two can't be implemented efficiently (always have to use
2428 * a linear scan, since that's the only way to find all the non-text
2433 * gtk_text_iter_forward_text_chars:
2434 * @iter: a #GtkTextIter
2435 * @count: number of chars to move
2437 * Moves forward by @count text characters (pixbufs, widgets,
2438 * etc. do not count as characters for this). Equivalent to moving
2439 * through the results of gtk_text_iter_get_text (), rather than
2440 * gtk_text_iter_get_slice ().
2442 * Return value: whether @iter moved and is dereferenceable
2445 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2454 * gtk_text_iter_forward_text_chars:
2455 * @iter: a #GtkTextIter
2456 * @count: number of chars to move
2458 * Moves backward by @count text characters (pixbufs, widgets,
2459 * etc. do not count as characters for this). Equivalent to moving
2460 * through the results of gtk_text_iter_get_text (), rather than
2461 * gtk_text_iter_get_slice ().
2463 * Return value: whether @iter moved and is dereferenceable
2466 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2475 * gtk_text_iter_forward_line:
2476 * @iter: an iterator
2478 * Moves @iter to the start of the next line. Returns TRUE if there
2479 * was a next line to move to, and FALSE if @iter was simply moved to
2480 * the end of the buffer and is now not dereferenceable, or if @iter was
2481 * already at the end of the buffer.
2483 * Return value: whether @iter can be dereferenced
2486 gtk_text_iter_forward_line (GtkTextIter *iter)
2488 GtkTextRealIter *real;
2490 g_return_val_if_fail (iter != NULL, FALSE);
2492 real = gtk_text_iter_make_real (iter);
2497 check_invariants (iter);
2499 if (forward_line_leaving_caches_unmodified (real))
2501 invalidate_char_index (real);
2502 adjust_line_number (real, 1);
2504 check_invariants (iter);
2506 if (gtk_text_iter_is_end (iter))
2513 /* On the last line, move to end of it */
2515 if (!gtk_text_iter_is_end (iter))
2516 gtk_text_iter_forward_to_end (iter);
2518 check_invariants (iter);
2524 * gtk_text_iter_backward_line:
2525 * @iter: an iterator
2527 * Moves @iter to the start of the previous line. Returns TRUE if
2528 * @iter could be moved; i.e. if @iter was at character offset 0, this
2529 * function returns FALSE. Therefore if @iter was already on line 0,
2530 * but not at the start of the line, @iter is snapped to the start of
2531 * the line and the function returns TRUE. (Note that this implies that
2532 * in a loop calling this function, the line number may not change on
2533 * every iteration, if your first iteration is on line 0.)
2535 * Return value: whether @iter moved
2538 gtk_text_iter_backward_line (GtkTextIter *iter)
2540 GtkTextLine *new_line;
2541 GtkTextRealIter *real;
2542 gboolean offset_will_change;
2545 g_return_val_if_fail (iter != NULL, FALSE);
2547 real = gtk_text_iter_make_real (iter);
2552 check_invariants (iter);
2554 new_line = _gtk_text_line_previous (real->line);
2556 offset_will_change = FALSE;
2557 if (real->line_char_offset > 0)
2558 offset_will_change = TRUE;
2560 if (new_line != NULL)
2562 real->line = new_line;
2564 adjust_line_number (real, -1);
2568 if (!offset_will_change)
2572 invalidate_char_index (real);
2574 real->line_byte_offset = 0;
2575 real->line_char_offset = 0;
2577 real->segment_byte_offset = 0;
2578 real->segment_char_offset = 0;
2580 /* Find first segment in line */
2581 real->any_segment = real->line->segments;
2582 real->segment = _gtk_text_line_byte_to_segment (real->line,
2585 g_assert (offset == 0);
2587 /* Note that if we are on the first line, we snap to the start of
2588 * the first line and return TRUE, so TRUE means the iterator
2589 * changed, not that the line changed; this is maybe a bit
2590 * weird. I'm not sure there's an obvious right thing to do though.
2593 check_invariants (iter);
2600 * gtk_text_iter_forward_lines:
2601 * @iter: a #GtkTextIter
2602 * @count: number of lines to move forward
2604 * Moves @count lines forward, if possible (if @count would move
2605 * past the start or end of the buffer, moves to the start or end of
2606 * the buffer). The return value indicates whether the iterator moved
2607 * onto a dereferenceable position; if the iterator didn't move, or
2608 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2609 * the function does nothing and returns FALSE. If @count is negative,
2610 * moves backward by 0 - @count lines.
2612 * Return value: whether @iter moved and is dereferenceable
2615 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2617 FIX_OVERFLOWS (count);
2620 return gtk_text_iter_backward_lines (iter, 0 - count);
2621 else if (count == 0)
2623 else if (count == 1)
2625 check_invariants (iter);
2626 return gtk_text_iter_forward_line (iter);
2632 if (gtk_text_iter_is_end (iter))
2635 old_line = gtk_text_iter_get_line (iter);
2637 gtk_text_iter_set_line (iter, old_line + count);
2639 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2641 /* count went past the last line, so move to end of last line */
2642 if (!gtk_text_iter_is_end (iter))
2643 gtk_text_iter_forward_to_end (iter);
2646 return !gtk_text_iter_is_end (iter);
2651 * gtk_text_iter_backward_lines:
2652 * @iter: a #GtkTextIter
2653 * @count: number of lines to move backward
2655 * Moves @count lines backward, if possible (if @count would move
2656 * past the start or end of the buffer, moves to the start or end of
2657 * the buffer). The return value indicates whether the iterator moved
2658 * onto a dereferenceable position; if the iterator didn't move, or
2659 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2660 * the function does nothing and returns FALSE. If @count is negative,
2661 * moves forward by 0 - @count lines.
2663 * Return value: whether @iter moved and is dereferenceable
2666 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2668 FIX_OVERFLOWS (count);
2671 return gtk_text_iter_forward_lines (iter, 0 - count);
2672 else if (count == 0)
2674 else if (count == 1)
2676 return gtk_text_iter_backward_line (iter);
2682 old_line = gtk_text_iter_get_line (iter);
2684 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2686 return (gtk_text_iter_get_line (iter) != old_line);
2690 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2695 gboolean already_moved_initially);
2697 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2705 find_word_end_func (const PangoLogAttr *attrs,
2710 gboolean already_moved_initially)
2712 if (!already_moved_initially)
2715 /* Find end of next word */
2716 while (offset < min_offset + len &&
2717 !attrs[offset].is_word_end)
2720 *found_offset = offset;
2722 return offset < min_offset + len;
2726 is_word_end_func (const PangoLogAttr *attrs,
2731 return attrs[offset].is_word_end;
2735 find_word_start_func (const PangoLogAttr *attrs,
2740 gboolean already_moved_initially)
2742 if (!already_moved_initially)
2745 /* Find start of prev word */
2746 while (offset >= min_offset &&
2747 !attrs[offset].is_word_start)
2750 *found_offset = offset;
2752 return offset >= min_offset;
2756 is_word_start_func (const PangoLogAttr *attrs,
2761 return attrs[offset].is_word_start;
2765 inside_word_func (const PangoLogAttr *attrs,
2770 /* Find next word start or end */
2771 while (offset >= min_offset &&
2772 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2775 return attrs[offset].is_word_start;
2778 /* Sentence funcs */
2781 find_sentence_end_func (const PangoLogAttr *attrs,
2786 gboolean already_moved_initially)
2788 if (!already_moved_initially)
2791 /* Find end of next sentence */
2792 while (offset < min_offset + len &&
2793 !attrs[offset].is_sentence_end)
2796 *found_offset = offset;
2798 return offset < min_offset + len;
2802 is_sentence_end_func (const PangoLogAttr *attrs,
2807 return attrs[offset].is_sentence_end;
2811 find_sentence_start_func (const PangoLogAttr *attrs,
2816 gboolean already_moved_initially)
2818 if (!already_moved_initially)
2821 /* Find start of prev sentence */
2822 while (offset >= min_offset &&
2823 !attrs[offset].is_sentence_start)
2826 *found_offset = offset;
2828 return offset >= min_offset;
2832 is_sentence_start_func (const PangoLogAttr *attrs,
2837 return attrs[offset].is_sentence_start;
2841 inside_sentence_func (const PangoLogAttr *attrs,
2846 /* Find next sentence start or end */
2847 while (offset >= min_offset &&
2848 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2851 return attrs[offset].is_sentence_start;
2855 test_log_attrs (const GtkTextIter *iter,
2856 TestLogAttrFunc func)
2859 const PangoLogAttr *attrs;
2861 gboolean result = FALSE;
2863 g_return_val_if_fail (iter != NULL, FALSE);
2865 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2868 offset = gtk_text_iter_get_line_offset (iter);
2870 /* char_len may be 0 and attrs will be NULL if so, if
2871 * iter is the end iter and the last line is empty.
2873 * offset may be equal to char_len, since attrs contains an entry
2874 * for one past the end
2877 if (attrs && offset <= char_len)
2878 result = (* func) (attrs, offset, 0, char_len);
2884 find_line_log_attrs (const GtkTextIter *iter,
2885 FindLogAttrFunc func,
2887 gboolean already_moved_initially)
2890 const PangoLogAttr *attrs;
2892 gboolean result = FALSE;
2894 g_return_val_if_fail (iter != NULL, FALSE);
2896 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2899 offset = gtk_text_iter_get_line_offset (iter);
2901 /* char_len may be 0 and attrs will be NULL if so, if
2902 * iter is the end iter and the last line is empty
2906 result = (* func) (attrs, offset, 0, char_len, found_offset,
2907 already_moved_initially);
2912 /* FIXME this function is very, very gratuitously slow */
2914 find_by_log_attrs (GtkTextIter *iter,
2915 FindLogAttrFunc func,
2917 gboolean already_moved_initially)
2921 gboolean found = FALSE;
2923 g_return_val_if_fail (iter != NULL, FALSE);
2927 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2933 if (gtk_text_iter_forward_line (iter))
2934 return find_by_log_attrs (iter, func, forward,
2941 /* go to end of previous line. need to check that
2942 * line is > 0 because backward_line snaps to start of
2943 * line 0 if it's on line 0
2945 if (gtk_text_iter_get_line (iter) > 0 &&
2946 gtk_text_iter_backward_line (iter))
2948 if (!gtk_text_iter_ends_line (iter))
2949 gtk_text_iter_forward_to_line_end (iter);
2951 return find_by_log_attrs (iter, func, forward,
2960 gtk_text_iter_set_line_offset (iter, offset);
2963 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2964 !gtk_text_iter_is_end (iter);
2969 * gtk_text_iter_forward_word_end:
2970 * @iter: a #GtkTextIter
2972 * Moves forward to the next word end. (If @iter is currently on a
2973 * word end, moves forward to the next one after that.) Word breaks
2974 * are determined by Pango and should be correct for nearly any
2975 * language (if not, the correct fix would be to the Pango word break
2978 * Return value: %TRUE if @iter moved and is not the end iterator
2981 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2983 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2987 * gtk_text_iter_backward_word_start:
2988 * @iter: a #GtkTextIter
2990 * Moves backward to the next word start. (If @iter is currently on a
2991 * word start, moves backward to the next one after that.) Word breaks
2992 * are determined by Pango and should be correct for nearly any
2993 * language (if not, the correct fix would be to the Pango word break
2996 * Return value: %TRUE if @iter moved and is not the end iterator
2999 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3001 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3004 /* FIXME a loop around a truly slow function means
3005 * a truly spectacularly slow function.
3009 * gtk_text_iter_forward_word_ends:
3010 * @iter: a #GtkTextIter
3011 * @count: number of times to move
3013 * Calls gtk_text_iter_forward_word_end() up to @count times.
3015 * Return value: %TRUE if @iter moved and is not the end iterator
3018 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3021 g_return_val_if_fail (iter != NULL, FALSE);
3023 FIX_OVERFLOWS (count);
3029 return gtk_text_iter_backward_word_starts (iter, -count);
3031 if (!gtk_text_iter_forward_word_end (iter))
3037 if (!gtk_text_iter_forward_word_end (iter))
3042 return !gtk_text_iter_is_end (iter);
3046 * gtk_text_iter_backward_word_starts
3047 * @iter: a #GtkTextIter
3048 * @count: number of times to move
3050 * Calls gtk_text_iter_backward_word_starts() up to @count times.
3052 * Return value: %TRUE if @iter moved and is not the end iterator
3055 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3058 g_return_val_if_fail (iter != NULL, FALSE);
3060 FIX_OVERFLOWS (count);
3063 return gtk_text_iter_forward_word_ends (iter, -count);
3065 if (!gtk_text_iter_backward_word_start (iter))
3071 if (!gtk_text_iter_backward_word_start (iter))
3076 return !gtk_text_iter_is_end (iter);
3080 * gtk_text_iter_starts_word:
3081 * @iter: a #GtkTextIter
3083 * Determines whether @iter begins a natural-language word. Word
3084 * breaks are determined by Pango and should be correct for nearly any
3085 * language (if not, the correct fix would be to the Pango word break
3088 * Return value: %TRUE if @iter is at the start of a word
3091 gtk_text_iter_starts_word (const GtkTextIter *iter)
3093 return test_log_attrs (iter, is_word_start_func);
3097 * gtk_text_iter_ends_word:
3098 * @iter: a #GtkTextIter
3100 * Determines whether @iter ends a natural-language word. Word breaks
3101 * are determined by Pango and should be correct for nearly any
3102 * language (if not, the correct fix would be to the Pango word break
3105 * Return value: %TRUE if @iter is at the end of a word
3108 gtk_text_iter_ends_word (const GtkTextIter *iter)
3110 return test_log_attrs (iter, is_word_end_func);
3114 * gtk_text_iter_inside_word:
3115 * @iter: a #GtkTextIter
3117 * Determines whether @iter is inside a natural-language word (as
3118 * opposed to say inside some whitespace). Word breaks are determined
3119 * by Pango and should be correct for nearly any language (if not, the
3120 * correct fix would be to the Pango word break algorithms).
3122 * Return value: %TRUE if @iter is inside a word
3125 gtk_text_iter_inside_word (const GtkTextIter *iter)
3127 return test_log_attrs (iter, inside_word_func);
3131 * gtk_text_iter_starts_sentence:
3132 * @iter: a #GtkTextIter
3134 * Determines whether @iter begins a sentence. Sentence boundaries are
3135 * determined by Pango and should be correct for nearly any language
3136 * (if not, the correct fix would be to the Pango text boundary
3139 * Return value: %TRUE if @iter is at the start of a sentence.
3142 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3144 return test_log_attrs (iter, is_sentence_start_func);
3148 * gtk_text_iter_ends_sentence:
3149 * @iter: a #GtkTextIter
3151 * Determines whether @iter ends a sentence. Sentence boundaries are
3152 * determined by Pango and should be correct for nearly any language
3153 * (if not, the correct fix would be to the Pango text boundary
3156 * Return value: %TRUE if @iter is at the end of a sentence.
3159 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3161 return test_log_attrs (iter, is_sentence_end_func);
3165 * gtk_text_iter_inside_sentence:
3166 * @iter: a #GtkTextIter
3168 * Determines whether @iter is inside a sentence (as opposed to in
3169 * between two sentences, e.g. after a period and before the first
3170 * letter of the next sentence). Sentence boundaries are determined
3171 * by Pango and should be correct for nearly any language (if not, the
3172 * correct fix would be to the Pango text boundary algorithms).
3174 * Return value: %TRUE if @iter is inside a sentence.
3177 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3179 return test_log_attrs (iter, inside_sentence_func);
3183 * gtk_text_iter_forward_sentence_end:
3184 * @iter: a #GtkTextIter
3186 * Moves forward to the next sentence end. (If @iter is at the end of
3187 * a sentence, moves to the next end of sentence.) Sentence
3188 * boundaries are determined by Pango and should be correct for nearly
3189 * any language (if not, the correct fix would be to the Pango text
3190 * boundary algorithms).
3192 * Return value: %TRUE if @iter moved and is not the end iterator
3195 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3197 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3201 * gtk_text_iter_backward_sentence_start:
3202 * @iter: a #GtkTextIter
3204 * Moves backward to the next sentence start; if @iter is already at
3205 * the start of a sentence, moves backward to the next one. Sentence
3206 * boundaries are determined by Pango and should be correct for nearly
3207 * any language (if not, the correct fix would be to the Pango text
3208 * boundary algorithms).
3210 * Return value: %TRUE if @iter moved and is not the end iterator
3213 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3215 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3218 /* FIXME a loop around a truly slow function means
3219 * a truly spectacularly slow function.
3222 * gtk_text_iter_forward_sentence_ends:
3223 * @iter: a #GtkTextIter
3224 * @count: number of sentences to move
3226 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3227 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3228 * negative, moves backward instead of forward.
3230 * Return value: %TRUE if @iter moved and is not the end iterator
3233 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3236 g_return_val_if_fail (iter != NULL, FALSE);
3242 return gtk_text_iter_backward_sentence_starts (iter, -count);
3244 if (!gtk_text_iter_forward_sentence_end (iter))
3250 if (!gtk_text_iter_forward_sentence_end (iter))
3255 return !gtk_text_iter_is_end (iter);
3259 * gtk_text_iter_backward_sentence_starts:
3260 * @iter: a #GtkTextIter
3261 * @count: number of sentences to move
3263 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3264 * or until it returns %FALSE. If @count is negative, moves forward
3265 * instead of backward.
3267 * Return value: %TRUE if @iter moved and is not the end iterator
3270 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3273 g_return_val_if_fail (iter != NULL, FALSE);
3276 return gtk_text_iter_forward_sentence_ends (iter, -count);
3278 if (!gtk_text_iter_backward_sentence_start (iter))
3284 if (!gtk_text_iter_backward_sentence_start (iter))
3289 return !gtk_text_iter_is_end (iter);
3293 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3298 gboolean already_moved_initially)
3300 if (!already_moved_initially)
3303 while (offset < (min_offset + len) &&
3304 !attrs[offset].is_cursor_position)
3307 *found_offset = offset;
3309 return offset < (min_offset + len);
3313 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3318 gboolean already_moved_initially)
3320 if (!already_moved_initially)
3323 while (offset > min_offset &&
3324 !attrs[offset].is_cursor_position)
3327 *found_offset = offset;
3329 return offset >= min_offset;
3333 is_cursor_pos_func (const PangoLogAttr *attrs,
3338 return attrs[offset].is_cursor_position;
3342 * gtk_text_iter_forward_cursor_position:
3343 * @iter: a #GtkTextIter
3345 * Moves @iter forward by a single cursor position. Cursor positions
3346 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3347 * surprisingly, there may not be a cursor position between all
3348 * characters. The most common example for European languages would be
3349 * a carriage return/newline sequence. For some Unicode characters,
3350 * the equivalent of say the letter "a" with an accent mark will be
3351 * represented as two characters, first the letter then a "combining
3352 * mark" that causes the accent to be rendered; so the cursor can't go
3353 * between those two characters. See also the #PangoLogAttr structure and
3354 * pango_break() function.
3356 * Return value: %TRUE if we moved and the new position is dereferenceable
3359 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3361 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3365 * gtk_text_iter_backward_cursor_position:
3366 * @iter: a #GtkTextIter
3368 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3370 * Return value: %TRUE if we moved and the new position is dereferenceable
3373 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3375 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3379 * gtk_text_iter_forward_cursor_positions:
3380 * @iter: a #GtkTextIter
3381 * @count: number of positions to move
3383 * Moves up to @count cursor positions. See
3384 * gtk_text_iter_forward_cursor_position() for details.
3386 * Return value: %TRUE if we moved and the new position is dereferenceable
3389 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3392 g_return_val_if_fail (iter != NULL, FALSE);
3394 FIX_OVERFLOWS (count);
3400 return gtk_text_iter_backward_cursor_positions (iter, -count);
3402 if (!gtk_text_iter_forward_cursor_position (iter))
3408 if (!gtk_text_iter_forward_cursor_position (iter))
3413 return !gtk_text_iter_is_end (iter);
3417 * gtk_text_iter_backward_cursor_positions:
3418 * @iter: a #GtkTextIter
3419 * @count: number of positions to move
3421 * Moves up to @count cursor positions. See
3422 * gtk_text_iter_forward_cursor_position() for details.
3424 * Return value: %TRUE if we moved and the new position is dereferenceable
3427 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3430 g_return_val_if_fail (iter != NULL, FALSE);
3432 FIX_OVERFLOWS (count);
3438 return gtk_text_iter_forward_cursor_positions (iter, -count);
3440 if (!gtk_text_iter_backward_cursor_position (iter))
3446 if (!gtk_text_iter_backward_cursor_position (iter))
3451 return !gtk_text_iter_is_end (iter);
3455 * gtk_text_iter_is_cursor_position:
3456 * @iter: a #GtkTextIter
3458 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3459 * pango_break() for details on what a cursor position is.
3461 * Return value: %TRUE if the cursor can be placed at @iter
3464 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3466 return test_log_attrs (iter, is_cursor_pos_func);
3470 * gtk_text_iter_set_line_offset:
3471 * @iter: a #GtkTextIter
3472 * @char_on_line: a character offset relative to the start of @iter's current line
3474 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3475 * (not byte) offset. The given character offset must be less than or
3476 * equal to the number of characters in the line; if equal, @iter
3477 * moves to the start of the next line. See
3478 * gtk_text_iter_set_line_index() if you have a byte index rather than
3479 * a character offset.
3483 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3486 GtkTextRealIter *real;
3489 g_return_if_fail (iter != NULL);
3491 real = gtk_text_iter_make_surreal (iter);
3496 check_invariants (iter);
3498 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3500 g_return_if_fail (char_on_line <= chars_in_line);
3502 if (char_on_line < chars_in_line)
3503 iter_set_from_char_offset (real, real->line, char_on_line);
3505 gtk_text_iter_forward_line (iter); /* set to start of next line */
3507 check_invariants (iter);
3511 * gtk_text_iter_set_line_index:
3512 * @iter: a #GtkTextIter
3513 * @byte_on_line: a byte index relative to the start of @iter's current line
3515 * Same as gtk_text_iter_set_line_offset(), but works with a
3516 * <emphasis>byte</emphasis> index. The given byte index must be at
3517 * the start of a character, it can't be in the middle of a UTF-8
3518 * encoded character.
3522 gtk_text_iter_set_line_index (GtkTextIter *iter,
3525 GtkTextRealIter *real;
3528 g_return_if_fail (iter != NULL);
3530 real = gtk_text_iter_make_surreal (iter);
3535 check_invariants (iter);
3537 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3539 g_return_if_fail (byte_on_line <= bytes_in_line);
3541 if (byte_on_line < bytes_in_line)
3542 iter_set_from_byte_offset (real, real->line, byte_on_line);
3544 gtk_text_iter_forward_line (iter);
3546 if (real->segment->type == >k_text_char_type &&
3547 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3548 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3549 "character; this will crash the text buffer. "
3550 "Byte indexes must refer to the start of a character.",
3551 G_STRLOC, byte_on_line);
3553 check_invariants (iter);
3558 * gtk_text_iter_set_visible_line_offset:
3559 * @iter: a #GtkTextIter
3560 * @char_on_line: a character offset
3562 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3563 * characters, i.e. text with a tag making it invisible is not
3564 * counted in the offset.
3567 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3570 gint chars_seen = 0;
3573 g_return_if_fail (iter != NULL);
3577 /* For now we use a ludicrously slow implementation */
3578 while (chars_seen < char_on_line)
3580 if (!_gtk_text_btree_char_is_invisible (&pos))
3583 if (!gtk_text_iter_forward_char (&pos))
3586 if (chars_seen == char_on_line)
3590 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3593 gtk_text_iter_forward_line (iter);
3597 bytes_in_char (GtkTextIter *iter)
3599 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3603 * gtk_text_iter_set_visible_line_index:
3604 * @iter: a #GtkTextIter
3605 * @byte_on_line: a byte index
3607 * Like gtk_text_iter_set_line_index(), but the index is in visible
3608 * bytes, i.e. text with a tag making it invisible is not counted
3612 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3615 gint bytes_seen = 0;
3618 g_return_if_fail (iter != NULL);
3622 /* For now we use a ludicrously slow implementation */
3623 while (bytes_seen < byte_on_line)
3625 if (!_gtk_text_btree_char_is_invisible (&pos))
3626 bytes_seen += bytes_in_char (&pos);
3628 if (!gtk_text_iter_forward_char (&pos))
3631 if (bytes_seen >= byte_on_line)
3635 if (bytes_seen > byte_on_line)
3636 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3637 "character; this will crash the text buffer. "
3638 "Byte indexes must refer to the start of a character.",
3639 G_STRLOC, byte_on_line);
3641 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3644 gtk_text_iter_forward_line (iter);
3648 * gtk_text_iter_set_line:
3649 * @iter: a #GtkTextIter
3650 * @line_number: line number (counted from 0)
3652 * Moves iterator @iter to the start of the line @line_number. If
3653 * @line_number is negative or larger than the number of lines in the
3654 * buffer, moves @iter to the start of the last line in the buffer.
3658 gtk_text_iter_set_line (GtkTextIter *iter,
3663 GtkTextRealIter *real;
3665 g_return_if_fail (iter != NULL);
3667 real = gtk_text_iter_make_surreal (iter);
3672 check_invariants (iter);
3674 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3676 iter_set_from_char_offset (real, line, 0);
3678 /* We might as well cache this, since we know it. */
3679 real->cached_line_number = real_line;
3681 check_invariants (iter);
3685 * gtk_text_iter_set_offset:
3686 * @iter: a #GtkTextIter
3687 * @char_offset: a character number
3689 * Sets @iter to point to @char_offset. @char_offset counts from the start
3690 * of the entire text buffer, starting with 0.
3694 gtk_text_iter_set_offset (GtkTextIter *iter,
3698 GtkTextRealIter *real;
3700 gint real_char_index;
3702 g_return_if_fail (iter != NULL);
3704 real = gtk_text_iter_make_surreal (iter);
3709 check_invariants (iter);
3711 if (real->cached_char_index >= 0 &&
3712 real->cached_char_index == char_offset)
3715 line = _gtk_text_btree_get_line_at_char (real->tree,
3720 iter_set_from_char_offset (real, line, real_char_index - line_start);
3722 /* Go ahead and cache this since we have it. */
3723 real->cached_char_index = real_char_index;
3725 check_invariants (iter);
3729 * gtk_text_iter_forward_to_end:
3730 * @iter: a #GtkTextIter
3732 * Moves @iter forward to the "end iterator," which points one past the last
3733 * valid character in the buffer. gtk_text_iter_get_char() called on the
3734 * end iterator returns 0, which is convenient for writing loops.
3738 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3740 GtkTextBuffer *buffer;
3741 GtkTextRealIter *real;
3743 g_return_if_fail (iter != NULL);
3745 real = gtk_text_iter_make_surreal (iter);
3750 buffer = _gtk_text_btree_get_buffer (real->tree);
3752 gtk_text_buffer_get_end_iter (buffer, iter);
3755 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3756 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3757 * If all else fails we could cache the para delimiter pos in the iter.
3758 * I think forward_to_line_end() actually gets called fairly often.
3761 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3766 /* if we aren't on the last line, go forward to start of next line, then scan
3767 * back for the delimiters on the previous line
3769 if (gtk_text_iter_forward_line (&end))
3771 gtk_text_iter_backward_char (&end);
3772 while (!gtk_text_iter_ends_line (&end))
3773 gtk_text_iter_backward_char (&end);
3776 return gtk_text_iter_get_line_offset (&end);
3780 * gtk_text_iter_forward_to_line_end:
3781 * @iter: a #GtkTextIter
3783 * Moves the iterator to point to the paragraph delimiter characters,
3784 * which will be either a newline, a carriage return, a carriage
3785 * return/newline in sequence, or the Unicode paragraph separator
3786 * character. If the iterator is already at the paragraph delimiter
3787 * characters, moves to the paragraph delimiter characters for the
3788 * next line. If @iter is on the last line in the buffer, which does
3789 * not end in paragraph delimiters, moves to the end iterator (end of
3790 * the last line), and returns %FALSE.
3792 * Return value: %TRUE if we moved and the new location is not the end iterator
3795 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3797 gint current_offset;
3801 g_return_val_if_fail (iter != NULL, FALSE);
3803 current_offset = gtk_text_iter_get_line_offset (iter);
3804 new_offset = find_paragraph_delimiter_for_line (iter);
3806 if (current_offset < new_offset)
3808 /* Move to end of this line. */
3809 gtk_text_iter_set_line_offset (iter, new_offset);
3814 /* Move to end of next line. */
3815 if (gtk_text_iter_forward_line (iter))
3817 /* We don't want to move past all
3820 if (!gtk_text_iter_ends_line (iter))
3821 gtk_text_iter_forward_to_line_end (iter);
3830 * gtk_text_iter_forward_to_tag_toggle:
3831 * @iter: a #GtkTextIter
3832 * @tag: a #GtkTextTag, or NULL
3834 * Moves forward to the next toggle (on or off) of the
3835 * #GtkTextTag @tag, or to the next toggle of any tag if
3836 * @tag is NULL. If no matching tag toggles are found,
3837 * returns FALSE, otherwise TRUE. Does not return toggles
3838 * located at @iter, only toggles after @iter. Sets @iter to
3839 * the location of the toggle, or to the end of the buffer
3840 * if no toggle is found.
3842 * Return value: whether we found a tag toggle after @iter
3845 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3848 GtkTextLine *next_line;
3849 GtkTextLine *current_line;
3850 GtkTextRealIter *real;
3852 g_return_val_if_fail (iter != NULL, FALSE);
3854 real = gtk_text_iter_make_real (iter);
3859 check_invariants (iter);
3861 current_line = real->line;
3862 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3865 while (_gtk_text_iter_forward_indexable_segment (iter))
3867 /* If we went forward to a line that couldn't contain a toggle
3868 for the tag, then skip forward to a line that could contain
3869 it. This potentially skips huge hunks of the tree, so we
3870 aren't a purely linear search. */
3871 if (real->line != current_line)
3873 if (next_line == NULL)
3875 /* End of search. Set to end of buffer. */
3876 _gtk_text_btree_get_end_iter (real->tree, iter);
3880 if (real->line != next_line)
3881 iter_set_from_byte_offset (real, next_line, 0);
3883 current_line = real->line;
3884 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3889 if (gtk_text_iter_toggles_tag (iter, tag))
3891 /* If there's a toggle here, it isn't indexable so
3892 any_segment can't be the indexable segment. */
3893 g_assert (real->any_segment != real->segment);
3898 /* Check end iterator for tags */
3899 if (gtk_text_iter_toggles_tag (iter, tag))
3901 /* If there's a toggle here, it isn't indexable so
3902 any_segment can't be the indexable segment. */
3903 g_assert (real->any_segment != real->segment);
3907 /* Reached end of buffer */
3912 * gtk_text_iter_backward_to_tag_toggle:
3913 * @iter: a #GtkTextIter
3914 * @tag: a #GtkTextTag, or NULL
3916 * Moves backward to the next toggle (on or off) of the
3917 * #GtkTextTag @tag, or to the next toggle of any tag if
3918 * @tag is NULL. If no matching tag toggles are found,
3919 * returns FALSE, otherwise TRUE. Does not return toggles
3920 * located at @iter, only toggles before @iter. Sets @iter
3921 * to the location of the toggle, or the start of the buffer
3922 * if no toggle is found.
3924 * Return value: whether we found a tag toggle before @iter
3927 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3930 GtkTextLine *prev_line;
3931 GtkTextLine *current_line;
3932 GtkTextRealIter *real;
3934 g_return_val_if_fail (iter != NULL, FALSE);
3936 real = gtk_text_iter_make_real (iter);
3941 check_invariants (iter);
3943 current_line = real->line;
3944 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3948 /* If we're at segment start, go to the previous segment;
3949 * if mid-segment, snap to start of current segment.
3951 if (is_segment_start (real))
3953 if (!_gtk_text_iter_backward_indexable_segment (iter))
3958 ensure_char_offsets (real);
3960 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3966 /* If we went backward to a line that couldn't contain a toggle
3967 * for the tag, then skip backward further to a line that
3968 * could contain it. This potentially skips huge hunks of the
3969 * tree, so we aren't a purely linear search.
3971 if (real->line != current_line)
3973 if (prev_line == NULL)
3975 /* End of search. Set to start of buffer. */
3976 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3980 if (real->line != prev_line)
3982 /* Set to last segment in prev_line (could do this
3985 iter_set_from_byte_offset (real, prev_line, 0);
3987 while (!at_last_indexable_segment (real))
3988 _gtk_text_iter_forward_indexable_segment (iter);
3991 current_line = real->line;
3992 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3997 if (gtk_text_iter_toggles_tag (iter, tag))
3999 /* If there's a toggle here, it isn't indexable so
4000 * any_segment can't be the indexable segment.
4002 g_assert (real->any_segment != real->segment);
4006 while (_gtk_text_iter_backward_indexable_segment (iter));
4008 /* Reached front of buffer */
4013 matches_pred (GtkTextIter *iter,
4014 GtkTextCharPredicate pred,
4019 ch = gtk_text_iter_get_char (iter);
4021 return (*pred) (ch, user_data);
4025 * gtk_text_iter_forward_find_char:
4026 * @iter: a #GtkTextIter
4027 * @pred: a function to be called on each character
4028 * @user_data: user data for @pred
4029 * @limit: search limit, or %NULL for none
4031 * Advances @iter, calling @pred on each character. If
4032 * @pred returns %TRUE, returns %TRUE and stops scanning.
4033 * If @pred never returns %TRUE, @iter is set to @limit if
4034 * @limit is non-%NULL, otherwise to the end iterator.
4036 * Return value: whether a match was found
4039 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4040 GtkTextCharPredicate pred,
4042 const GtkTextIter *limit)
4044 g_return_val_if_fail (iter != NULL, FALSE);
4045 g_return_val_if_fail (pred != NULL, FALSE);
4048 gtk_text_iter_compare (iter, limit) >= 0)
4051 while ((limit == NULL ||
4052 !gtk_text_iter_equal (limit, iter)) &&
4053 gtk_text_iter_forward_char (iter))
4055 if (matches_pred (iter, pred, user_data))
4063 * gtk_text_iter_backward_find_char:
4064 * @iter: a #GtkTextIter
4065 * @pred: function to be called on each character
4066 * @user_data: user data for @pred
4067 * @limit: search limit, or %NULL for none
4069 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4071 * Return value: whether a match was found
4074 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4075 GtkTextCharPredicate pred,
4077 const GtkTextIter *limit)
4079 g_return_val_if_fail (iter != NULL, FALSE);
4080 g_return_val_if_fail (pred != NULL, FALSE);
4083 gtk_text_iter_compare (iter, limit) <= 0)
4086 while ((limit == NULL ||
4087 !gtk_text_iter_equal (limit, iter)) &&
4088 gtk_text_iter_backward_char (iter))
4090 if (matches_pred (iter, pred, user_data))
4098 forward_chars_with_skipping (GtkTextIter *iter,
4100 gboolean skip_invisible,
4101 gboolean skip_nontext)
4106 g_return_if_fail (count >= 0);
4112 gboolean ignored = FALSE;
4115 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4120 _gtk_text_btree_char_is_invisible (iter))
4123 gtk_text_iter_forward_char (iter);
4131 lines_match (const GtkTextIter *start,
4132 const gchar **lines,
4133 gboolean visible_only,
4135 GtkTextIter *match_start,
4136 GtkTextIter *match_end)
4143 if (*lines == NULL || **lines == '\0')
4146 *match_start = *start;
4149 *match_end = *start;
4154 gtk_text_iter_forward_line (&next);
4156 /* No more text in buffer, but *lines is nonempty */
4157 if (gtk_text_iter_equal (start, &next))
4165 line_text = gtk_text_iter_get_visible_slice (start, &next);
4167 line_text = gtk_text_iter_get_slice (start, &next);
4172 line_text = gtk_text_iter_get_visible_text (start, &next);
4174 line_text = gtk_text_iter_get_text (start, &next);
4177 if (match_start) /* if this is the first line we're matching */
4178 found = strstr (line_text, *lines);
4181 /* If it's not the first line, we have to match from the
4182 * start of the line.
4184 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4196 /* Get offset to start of search string */
4197 offset = g_utf8_strlen (line_text, found - line_text);
4201 /* If match start needs to be returned, set it to the
4202 * start of the search string.
4206 *match_start = next;
4208 forward_chars_with_skipping (match_start, offset,
4209 visible_only, !slice);
4212 /* Go to end of search string */
4213 offset += g_utf8_strlen (*lines, -1);
4215 forward_chars_with_skipping (&next, offset,
4216 visible_only, !slice);
4225 /* pass NULL for match_start, since we don't need to find the
4228 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4231 /* strsplit () that retains the delimiter as part of the string. */
4233 strbreakup (const char *string,
4234 const char *delimiter,
4237 GSList *string_list = NULL, *slist;
4238 gchar **str_array, *s;
4241 g_return_val_if_fail (string != NULL, NULL);
4242 g_return_val_if_fail (delimiter != NULL, NULL);
4245 max_tokens = G_MAXINT;
4247 s = strstr (string, delimiter);
4250 guint delimiter_len = strlen (delimiter);
4257 len = s - string + delimiter_len;
4258 new_string = g_new (gchar, len + 1);
4259 strncpy (new_string, string, len);
4260 new_string[len] = 0;
4261 string_list = g_slist_prepend (string_list, new_string);
4263 string = s + delimiter_len;
4264 s = strstr (string, delimiter);
4266 while (--max_tokens && s);
4271 string_list = g_slist_prepend (string_list, g_strdup (string));
4274 str_array = g_new (gchar*, n);
4278 str_array[i--] = NULL;
4279 for (slist = string_list; slist; slist = slist->next)
4280 str_array[i--] = slist->data;
4282 g_slist_free (string_list);
4288 * gtk_text_iter_forward_search:
4289 * @iter: start of search
4290 * @str: a search string
4291 * @flags: flags affecting how the search is done
4292 * @match_start: return location for start of match, or %NULL
4293 * @match_end: return location for end of match, or %NULL
4294 * @limit: bound for the search, or %NULL for the end of the buffer
4296 * Searches forward for @str. Any match is returned as the range
4297 * @match_start, @match_end. The search will not continue past
4298 * @limit. Note that a search is a linear or O(n) operation, so you
4299 * may wish to use @limit to avoid locking up your UI on large
4302 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4303 * have invisible text interspersed in @str. i.e. @str will be a
4304 * possibly-noncontiguous subsequence of the matched range. similarly,
4305 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4306 * pixbufs or child widgets mixed inside the matched range. If these
4307 * flags are not given, the match must be exact; the special 0xFFFC
4308 * character in @str will match embedded pixbufs or child widgets.
4310 * Return value: whether a match was found
4313 gtk_text_iter_forward_search (const GtkTextIter *iter,
4315 GtkTextSearchFlags flags,
4316 GtkTextIter *match_start,
4317 GtkTextIter *match_end,
4318 const GtkTextIter *limit)
4320 gchar **lines = NULL;
4322 gboolean retval = FALSE;
4324 gboolean visible_only;
4327 g_return_val_if_fail (iter != NULL, FALSE);
4328 g_return_val_if_fail (str != NULL, FALSE);
4331 gtk_text_iter_compare (iter, limit) >= 0)
4336 /* If we can move one char, return the empty string there */
4339 if (gtk_text_iter_forward_char (&match))
4342 gtk_text_iter_equal (&match, limit))
4346 *match_start = match;
4355 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4356 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4358 /* locate all lines */
4360 lines = strbreakup (str, "\n", -1);
4366 /* This loop has an inefficient worst-case, where
4367 * gtk_text_iter_get_text () is called repeatedly on
4373 gtk_text_iter_compare (&search, limit) >= 0)
4376 if (lines_match (&search, (const gchar**)lines,
4377 visible_only, slice, &match, &end))
4379 if (limit == NULL ||
4381 gtk_text_iter_compare (&end, limit) < 0))
4386 *match_start = match;
4395 while (gtk_text_iter_forward_line (&search));
4397 g_strfreev ((gchar**)lines);
4403 vectors_equal_ignoring_trailing (gchar **vec1,
4406 /* Ignores trailing chars in vec2's last line */
4415 if (strcmp (*i1, *i2) != 0)
4417 if (*(i2 + 1) == NULL) /* if this is the last line */
4419 gint len1 = strlen (*i1);
4420 gint len2 = strlen (*i2);
4423 strncmp (*i1, *i2, len1) == 0)
4425 /* We matched ignoring the trailing stuff in vec2 */
4450 typedef struct _LinesWindow LinesWindow;
4456 GtkTextIter first_line_start;
4457 GtkTextIter first_line_end;
4459 gboolean visible_only;
4463 lines_window_init (LinesWindow *win,
4464 const GtkTextIter *start)
4467 GtkTextIter line_start;
4468 GtkTextIter line_end;
4470 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4473 if (gtk_text_iter_is_start (start) ||
4474 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4476 /* Already at the end, or not enough lines to match */
4477 win->lines = g_new0 (gchar*, 1);
4482 line_start = *start;
4485 /* Move to start iter to start of line */
4486 gtk_text_iter_set_line_offset (&line_start, 0);
4488 if (gtk_text_iter_equal (&line_start, &line_end))
4490 /* we were already at the start; so go back one line */
4491 gtk_text_iter_backward_line (&line_start);
4494 win->first_line_start = line_start;
4495 win->first_line_end = line_end;
4497 win->lines = g_new0 (gchar*, win->n_lines + 1);
4499 i = win->n_lines - 1;
4506 if (win->visible_only)
4507 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4509 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4513 if (win->visible_only)
4514 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4516 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4519 win->lines[i] = line_text;
4521 line_end = line_start;
4522 gtk_text_iter_backward_line (&line_start);
4529 lines_window_back (LinesWindow *win)
4531 GtkTextIter new_start;
4534 new_start = win->first_line_start;
4536 if (!gtk_text_iter_backward_line (&new_start))
4540 win->first_line_start = new_start;
4541 win->first_line_end = new_start;
4543 gtk_text_iter_forward_line (&win->first_line_end);
4548 if (win->visible_only)
4549 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4550 &win->first_line_end);
4552 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4553 &win->first_line_end);
4557 if (win->visible_only)
4558 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4559 &win->first_line_end);
4561 line_text = gtk_text_iter_get_text (&win->first_line_start,
4562 &win->first_line_end);
4565 /* Move lines to make room for first line. */
4566 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4568 *win->lines = line_text;
4570 /* Free old last line and NULL-terminate */
4571 g_free (win->lines[win->n_lines]);
4572 win->lines[win->n_lines] = NULL;
4578 lines_window_free (LinesWindow *win)
4580 g_strfreev (win->lines);
4584 my_strrstr (const gchar *haystack,
4585 const gchar *needle)
4587 /* FIXME GLib should have a nice implementation in it, this
4591 gint haystack_len = strlen (haystack);
4592 gint needle_len = strlen (needle);
4593 const gchar *needle_end = needle + needle_len;
4594 const gchar *haystack_rend = haystack - 1;
4595 const gchar *needle_rend = needle - 1;
4598 p = haystack + haystack_len;
4599 while (p != haystack)
4601 const gchar *n = needle_end - 1;
4602 const gchar *s = p - 1;
4603 while (s != haystack_rend &&
4611 if (n == needle_rend)
4621 * gtk_text_iter_backward_search:
4622 * @iter: a #GtkTextIter where the search begins
4623 * @str: search string
4624 * @flags: bitmask of flags affecting the search
4625 * @match_start: return location for start of match, or %NULL
4626 * @match_end: return location for end of match, or %NULL
4627 * @limit: location of last possible @match_start, or %NULL for start of buffer
4629 * Same as gtk_text_iter_forward_search(), but moves backward.
4631 * Return value: whether a match was found
4634 gtk_text_iter_backward_search (const GtkTextIter *iter,
4636 GtkTextSearchFlags flags,
4637 GtkTextIter *match_start,
4638 GtkTextIter *match_end,
4639 const GtkTextIter *limit)
4641 gchar **lines = NULL;
4645 gboolean retval = FALSE;
4646 gboolean visible_only;
4649 g_return_val_if_fail (iter != NULL, FALSE);
4650 g_return_val_if_fail (str != NULL, FALSE);
4653 gtk_text_iter_compare (limit, iter) > 0)
4658 /* If we can move one char, return the empty string there */
4659 GtkTextIter match = *iter;
4661 if (limit && gtk_text_iter_equal (limit, &match))
4664 if (gtk_text_iter_backward_char (&match))
4667 *match_start = match;
4676 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4677 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4679 /* locate all lines */
4681 lines = strbreakup (str, "\n", -1);
4691 win.n_lines = n_lines;
4693 win.visible_only = visible_only;
4695 lines_window_init (&win, iter);
4697 if (*win.lines == NULL)
4702 gchar *first_line_match;
4705 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4707 /* We're now before the search limit, abort. */
4711 /* If there are multiple lines, the first line will
4712 * end in '\n', so this will only match at the
4713 * end of the first line, which is correct.
4715 first_line_match = my_strrstr (*win.lines, *lines);
4717 if (first_line_match &&
4718 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4723 GtkTextIter start_tmp;
4725 /* Offset to start of search string */
4726 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4728 next = win.first_line_start;
4730 forward_chars_with_skipping (&start_tmp, offset,
4731 visible_only, !slice);
4734 gtk_text_iter_compare (limit, &start_tmp) > 0)
4735 goto out; /* match was bogus */
4738 *match_start = start_tmp;
4740 /* Go to end of search string */
4744 offset += g_utf8_strlen (*l, -1);
4748 forward_chars_with_skipping (&next, offset,
4749 visible_only, !slice);
4758 while (lines_window_back (&win));
4761 lines_window_free (&win);
4772 * gtk_text_iter_equal:
4773 * @lhs: a #GtkTextIter
4774 * @rhs: another #GtkTextIter
4776 * Tests whether two iterators are equal, using the fastest possible
4777 * mechanism. This function is very fast; you can expect it to perform
4778 * better than e.g. getting the character offset for each iterator and
4779 * comparing the offsets yourself. Also, it's a bit faster than
4780 * gtk_text_iter_compare().
4782 * Return value: %TRUE if the iterators point to the same place in the buffer
4785 gtk_text_iter_equal (const GtkTextIter *lhs,
4786 const GtkTextIter *rhs)
4788 GtkTextRealIter *real_lhs;
4789 GtkTextRealIter *real_rhs;
4791 real_lhs = (GtkTextRealIter*)lhs;
4792 real_rhs = (GtkTextRealIter*)rhs;
4794 check_invariants (lhs);
4795 check_invariants (rhs);
4797 if (real_lhs->line != real_rhs->line)
4799 else if (real_lhs->line_byte_offset >= 0 &&
4800 real_rhs->line_byte_offset >= 0)
4801 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4804 /* the ensure_char_offsets () calls do nothing if the char offsets
4805 are already up-to-date. */
4806 ensure_char_offsets (real_lhs);
4807 ensure_char_offsets (real_rhs);
4808 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4813 * gtk_text_iter_compare:
4814 * @lhs: a #GtkTextIter
4815 * @rhs: another #GtkTextIter
4817 * A qsort()-style function that returns negative if @lhs is less than
4818 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4819 * Ordering is in character offset order, i.e. the first character in the buffer
4820 * is less than the second character in the buffer.
4822 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4825 gtk_text_iter_compare (const GtkTextIter *lhs,
4826 const GtkTextIter *rhs)
4828 GtkTextRealIter *real_lhs;
4829 GtkTextRealIter *real_rhs;
4831 real_lhs = gtk_text_iter_make_surreal (lhs);
4832 real_rhs = gtk_text_iter_make_surreal (rhs);
4834 if (real_lhs == NULL ||
4836 return -1; /* why not */
4838 check_invariants (lhs);
4839 check_invariants (rhs);
4841 if (real_lhs->line == real_rhs->line)
4843 gint left_index, right_index;
4845 if (real_lhs->line_byte_offset >= 0 &&
4846 real_rhs->line_byte_offset >= 0)
4848 left_index = real_lhs->line_byte_offset;
4849 right_index = real_rhs->line_byte_offset;
4853 /* the ensure_char_offsets () calls do nothing if
4854 the offsets are already up-to-date. */
4855 ensure_char_offsets (real_lhs);
4856 ensure_char_offsets (real_rhs);
4857 left_index = real_lhs->line_char_offset;
4858 right_index = real_rhs->line_char_offset;
4861 if (left_index < right_index)
4863 else if (left_index > right_index)
4872 line1 = gtk_text_iter_get_line (lhs);
4873 line2 = gtk_text_iter_get_line (rhs);
4876 else if (line1 > line2)
4884 * gtk_text_iter_in_range:
4885 * @iter: a #GtkTextIter
4886 * @start: start of range
4887 * @end: end of range
4889 * Checks whether @iter falls in the range [@start, @end).
4890 * @start and @end must be in ascending order.
4892 * Return value: %TRUE if @iter is in the range
4895 gtk_text_iter_in_range (const GtkTextIter *iter,
4896 const GtkTextIter *start,
4897 const GtkTextIter *end)
4899 g_return_val_if_fail (iter != NULL, FALSE);
4900 g_return_val_if_fail (start != NULL, FALSE);
4901 g_return_val_if_fail (end != NULL, FALSE);
4902 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4904 return gtk_text_iter_compare (iter, start) >= 0 &&
4905 gtk_text_iter_compare (iter, end) < 0;
4909 * gtk_text_iter_order:
4910 * @first: a #GtkTextIter
4911 * @second: another #GtkTextIter
4913 * Swaps the value of @first and @second if @second comes before
4914 * @first in the buffer. That is, ensures that @first and @second are
4915 * in sequence. Most text buffer functions that take a range call this
4916 * automatically on your behalf, so there's no real reason to call it yourself
4917 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4918 * that expect a pre-sorted range.
4922 gtk_text_iter_order (GtkTextIter *first,
4923 GtkTextIter *second)
4925 g_return_if_fail (first != NULL);
4926 g_return_if_fail (second != NULL);
4928 if (gtk_text_iter_compare (first, second) > 0)
4939 * Init iterators from the BTree
4943 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4947 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4948 gint real_char_index;
4952 g_return_if_fail (iter != NULL);
4953 g_return_if_fail (tree != NULL);
4955 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4956 &line_start, &real_char_index);
4958 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4960 real->cached_char_index = real_char_index;
4962 check_invariants (iter);
4966 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4971 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4975 g_return_if_fail (iter != NULL);
4976 g_return_if_fail (tree != NULL);
4978 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
4980 iter_init_from_char_offset (iter, tree, line, char_on_line);
4982 /* We might as well cache this, since we know it. */
4983 real->cached_line_number = real_line;
4985 check_invariants (iter);
4989 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4994 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4998 g_return_if_fail (iter != NULL);
4999 g_return_if_fail (tree != NULL);
5001 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5003 iter_init_from_byte_offset (iter, tree, line, byte_index);
5005 /* We might as well cache this, since we know it. */
5006 real->cached_line_number = real_line;
5008 check_invariants (iter);
5012 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5017 g_return_if_fail (iter != NULL);
5018 g_return_if_fail (tree != NULL);
5019 g_return_if_fail (line != NULL);
5021 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5023 check_invariants (iter);
5027 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5033 g_return_val_if_fail (iter != NULL, FALSE);
5034 g_return_val_if_fail (tree != NULL, FALSE);
5036 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5040 /* Set iter to last in tree */
5041 _gtk_text_btree_get_end_iter (tree, iter);
5042 check_invariants (iter);
5047 iter_init_from_byte_offset (iter, tree, line, 0);
5048 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5049 check_invariants (iter);
5055 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5059 g_return_val_if_fail (iter != NULL, FALSE);
5060 g_return_val_if_fail (tree != NULL, FALSE);
5062 _gtk_text_btree_get_end_iter (tree, iter);
5063 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5064 check_invariants (iter);
5070 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5072 const gchar *mark_name)
5076 g_return_val_if_fail (iter != NULL, FALSE);
5077 g_return_val_if_fail (tree != NULL, FALSE);
5079 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5085 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5086 check_invariants (iter);
5092 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5096 GtkTextLineSegment *seg;
5098 g_return_if_fail (iter != NULL);
5099 g_return_if_fail (tree != NULL);
5100 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5102 seg = mark->segment;
5104 iter_init_from_segment (iter, tree,
5105 seg->body.mark.line, seg);
5106 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5107 check_invariants (iter);
5111 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5113 GtkTextChildAnchor *anchor)
5115 GtkTextLineSegment *seg;
5117 g_return_if_fail (iter != NULL);
5118 g_return_if_fail (tree != NULL);
5119 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5121 seg = anchor->segment;
5123 iter_init_from_segment (iter, tree,
5124 seg->body.child.line, seg);
5125 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5126 check_invariants (iter);
5130 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5133 g_return_if_fail (iter != NULL);
5134 g_return_if_fail (tree != NULL);
5136 _gtk_text_btree_get_iter_at_char (tree,
5138 _gtk_text_btree_char_count (tree));
5139 check_invariants (iter);
5143 _gtk_text_iter_check (const GtkTextIter *iter)
5145 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5146 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5147 GtkTextLineSegment *byte_segment = NULL;
5148 GtkTextLineSegment *byte_any_segment = NULL;
5149 GtkTextLineSegment *char_segment = NULL;
5150 GtkTextLineSegment *char_any_segment = NULL;
5151 gboolean segments_updated;
5153 /* This function checks our class invariants for the Iter class. */
5155 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5157 if (real->chars_changed_stamp !=
5158 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5159 g_error ("iterator check failed: invalid iterator");
5161 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5162 g_error ("iterator check failed: both char and byte offsets are invalid");
5164 segments_updated = (real->segments_changed_stamp ==
5165 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5168 printf ("checking iter, segments %s updated, byte %d char %d\n",
5169 segments_updated ? "are" : "aren't",
5170 real->line_byte_offset,
5171 real->line_char_offset);
5174 if (segments_updated)
5176 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5177 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5179 if (real->segment->char_count == 0)
5180 g_error ("iterator check failed: segment is not indexable.");
5182 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5183 g_error ("segment char offset is not properly up-to-date");
5185 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5186 g_error ("segment byte offset is not properly up-to-date");
5188 if (real->segment_byte_offset >= 0 &&
5189 real->segment_byte_offset >= real->segment->byte_count)
5190 g_error ("segment byte offset is too large.");
5192 if (real->segment_char_offset >= 0 &&
5193 real->segment_char_offset >= real->segment->char_count)
5194 g_error ("segment char offset is too large.");
5197 if (real->line_byte_offset >= 0)
5199 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5200 &byte_segment, &byte_any_segment,
5201 &seg_byte_offset, &line_byte_offset);
5203 if (line_byte_offset != real->line_byte_offset)
5204 g_error ("wrong byte offset was stored in iterator");
5206 if (segments_updated)
5208 if (real->segment != byte_segment)
5209 g_error ("wrong segment was stored in iterator");
5211 if (real->any_segment != byte_any_segment)
5212 g_error ("wrong any_segment was stored in iterator");
5214 if (seg_byte_offset != real->segment_byte_offset)
5215 g_error ("wrong segment byte offset was stored in iterator");
5217 if (byte_segment->type == >k_text_char_type)
5220 p = byte_segment->body.chars + seg_byte_offset;
5222 if (!gtk_text_byte_begins_utf8_char (p))
5223 g_error ("broken iterator byte index pointed into the middle of a character");
5228 if (real->line_char_offset >= 0)
5230 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5231 &char_segment, &char_any_segment,
5232 &seg_char_offset, &line_char_offset);
5234 if (line_char_offset != real->line_char_offset)
5235 g_error ("wrong char offset was stored in iterator");
5237 if (segments_updated)
5239 if (real->segment != char_segment)
5240 g_error ("wrong segment was stored in iterator");
5242 if (real->any_segment != char_any_segment)
5243 g_error ("wrong any_segment was stored in iterator");
5245 if (seg_char_offset != real->segment_char_offset)
5246 g_error ("wrong segment char offset was stored in iterator");
5248 if (char_segment->type == >k_text_char_type)
5251 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5254 /* hmm, not likely to happen eh */
5255 if (!gtk_text_byte_begins_utf8_char (p))
5256 g_error ("broken iterator char offset pointed into the middle of a character");
5261 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5263 if (byte_segment != char_segment)
5264 g_error ("char and byte offsets did not point to the same segment");
5266 if (byte_any_segment != char_any_segment)
5267 g_error ("char and byte offsets did not point to the same any segment");
5269 /* Make sure the segment offsets are equivalent, if it's a char
5271 if (char_segment->type == >k_text_char_type)
5273 gint byte_offset = 0;
5274 gint char_offset = 0;
5275 while (char_offset < seg_char_offset)
5277 const char * start = char_segment->body.chars + byte_offset;
5278 byte_offset += g_utf8_next_char (start) - start;
5282 if (byte_offset != seg_byte_offset)
5283 g_error ("byte offset did not correspond to char offset");
5286 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5288 if (char_offset != seg_char_offset)
5289 g_error ("char offset did not correspond to byte offset");
5291 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5292 g_error ("byte index for iterator does not index the start of a character");
5296 if (real->cached_line_number >= 0)
5300 should_be = _gtk_text_line_get_number (real->line);
5301 if (real->cached_line_number != should_be)
5302 g_error ("wrong line number was cached");
5305 if (real->cached_char_index >= 0)
5307 if (real->line_char_offset >= 0) /* only way we can check it
5308 efficiently, not a real
5313 char_index = _gtk_text_line_char_index (real->line);
5314 char_index += real->line_char_offset;
5316 if (real->cached_char_index != char_index)
5317 g_error ("wrong char index was cached");
5321 if (_gtk_text_line_is_last (real->line, real->tree))
5322 g_error ("Iterator was on last line (past the end iterator)");