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 #include "gtktextiter.h"
28 #include "gtktextbtree.h"
29 #include "gtktextiterprivate.h"
34 typedef struct _GtkTextRealIter GtkTextRealIter;
36 struct _GtkTextRealIter
38 /* Always-valid information */
41 /* At least one of these is always valid;
42 if invalid, they are -1.
44 If the line byte offset is valid, so is the segment byte offset;
45 and ditto for char offsets. */
46 gint line_byte_offset;
47 gint line_char_offset;
48 /* These two are valid if >= 0 */
49 gint cached_char_index;
50 gint cached_line_number;
51 /* Stamps to detect the buffer changing under us */
52 gint chars_changed_stamp;
53 gint segments_changed_stamp;
54 /* Valid if the segments_changed_stamp is up-to-date */
55 GtkTextLineSegment *segment; /* indexable segment we index */
56 GtkTextLineSegment *any_segment; /* first segment in our location,
57 maybe same as "segment" */
58 /* One of these will always be valid if segments_changed_stamp is
59 up-to-date. If invalid, they are -1.
61 If the line byte offset is valid, so is the segment byte offset;
62 and ditto for char offsets. */
63 gint segment_byte_offset;
64 gint segment_char_offset;
67 /* These "set" functions should not assume any fields
68 other than the char stamp and the tree are valid.
71 iter_set_common (GtkTextRealIter *iter,
74 /* Update segments stamp */
75 iter->segments_changed_stamp =
76 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
80 iter->line_byte_offset = -1;
81 iter->line_char_offset = -1;
82 iter->segment_byte_offset = -1;
83 iter->segment_char_offset = -1;
84 iter->cached_char_index = -1;
85 iter->cached_line_number = -1;
89 iter_set_from_byte_offset (GtkTextRealIter *iter,
93 iter_set_common (iter, line);
95 if (!_gtk_text_line_byte_locate (iter->line,
99 &iter->segment_byte_offset,
100 &iter->line_byte_offset))
101 g_error ("Byte index %d is off the end of the line",
106 iter_set_from_char_offset (GtkTextRealIter *iter,
110 iter_set_common (iter, line);
112 if (!_gtk_text_line_char_locate (iter->line,
116 &iter->segment_char_offset,
117 &iter->line_char_offset))
118 g_error ("Char offset %d is off the end of the line",
123 iter_set_from_segment (GtkTextRealIter *iter,
125 GtkTextLineSegment *segment)
127 GtkTextLineSegment *seg;
130 /* This could theoretically be optimized by computing all the iter
131 fields in this same loop, but I'm skipping it for now. */
133 seg = line->segments;
134 while (seg != segment)
136 byte_offset += seg->byte_count;
140 iter_set_from_byte_offset (iter, line, byte_offset);
143 /* This function ensures that the segment-dependent information is
144 truly computed lazily; often we don't need to do the full make_real
145 work. This ensures the btree and line are valid, but doesn't
146 update the segments. */
147 static GtkTextRealIter*
148 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
150 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
152 if (iter->chars_changed_stamp !=
153 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
155 g_warning ("Invalid text buffer iterator: either the iterator "
156 "is uninitialized, or the characters/pixbufs/widgets "
157 "in the buffer have been modified since the iterator "
158 "was created.\nYou must use marks, character numbers, "
159 "or line numbers to preserve a position across buffer "
160 "modifications.\nYou can apply tags and insert marks "
161 "without invalidating your iterators,\n"
162 "but any mutation that affects 'indexable' buffer contents "
163 "(contents that can be referred to by character offset)\n"
164 "will invalidate all outstanding iterators");
168 /* We don't update the segments information since we are becoming
169 only surreal. However we do invalidate the segments information
170 if appropriate, to be sure we segfault if we try to use it and we
171 should have used make_real. */
173 if (iter->segments_changed_stamp !=
174 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
176 iter->segment = NULL;
177 iter->any_segment = NULL;
178 /* set to segfault-causing values. */
179 iter->segment_byte_offset = -10000;
180 iter->segment_char_offset = -10000;
186 static GtkTextRealIter*
187 gtk_text_iter_make_real (const GtkTextIter *_iter)
189 GtkTextRealIter *iter;
191 iter = gtk_text_iter_make_surreal (_iter);
193 if (iter->segments_changed_stamp !=
194 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
196 if (iter->line_byte_offset >= 0)
198 iter_set_from_byte_offset (iter,
200 iter->line_byte_offset);
204 g_assert (iter->line_char_offset >= 0);
206 iter_set_from_char_offset (iter,
208 iter->line_char_offset);
212 g_assert (iter->segment != NULL);
213 g_assert (iter->any_segment != NULL);
214 g_assert (iter->segment->char_count > 0);
219 static GtkTextRealIter*
220 iter_init_common (GtkTextIter *_iter,
223 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
225 g_return_val_if_fail (iter != NULL, NULL);
226 g_return_val_if_fail (tree != NULL, NULL);
230 iter->chars_changed_stamp =
231 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
236 static GtkTextRealIter*
237 iter_init_from_segment (GtkTextIter *iter,
240 GtkTextLineSegment *segment)
242 GtkTextRealIter *real;
244 g_return_val_if_fail (line != NULL, NULL);
246 real = iter_init_common (iter, tree);
248 iter_set_from_segment (real, line, segment);
253 static GtkTextRealIter*
254 iter_init_from_byte_offset (GtkTextIter *iter,
257 gint line_byte_offset)
259 GtkTextRealIter *real;
261 g_return_val_if_fail (line != NULL, NULL);
263 real = iter_init_common (iter, tree);
265 iter_set_from_byte_offset (real, line, line_byte_offset);
270 static GtkTextRealIter*
271 iter_init_from_char_offset (GtkTextIter *iter,
274 gint line_char_offset)
276 GtkTextRealIter *real;
278 g_return_val_if_fail (line != NULL, NULL);
280 real = iter_init_common (iter, tree);
282 iter_set_from_char_offset (real, line, line_char_offset);
288 invalidate_segment (GtkTextRealIter *iter)
290 iter->segments_changed_stamp -= 1;
294 invalidate_char_index (GtkTextRealIter *iter)
296 iter->cached_char_index = -1;
300 invalidate_line_number (GtkTextRealIter *iter)
302 iter->cached_line_number = -1;
306 adjust_char_index (GtkTextRealIter *iter, gint count)
308 if (iter->cached_char_index >= 0)
309 iter->cached_char_index += count;
313 adjust_line_number (GtkTextRealIter *iter, gint count)
315 if (iter->cached_line_number >= 0)
316 iter->cached_line_number += count;
320 adjust_char_offsets (GtkTextRealIter *iter, gint count)
322 if (iter->line_char_offset >= 0)
324 iter->line_char_offset += count;
325 g_assert (iter->segment_char_offset >= 0);
326 iter->segment_char_offset += count;
331 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
333 if (iter->line_byte_offset >= 0)
335 iter->line_byte_offset += count;
336 g_assert (iter->segment_byte_offset >= 0);
337 iter->segment_byte_offset += count;
342 ensure_char_offsets (GtkTextRealIter *iter)
344 if (iter->line_char_offset < 0)
346 g_assert (iter->line_byte_offset >= 0);
348 _gtk_text_line_byte_to_char_offsets (iter->line,
349 iter->line_byte_offset,
350 &iter->line_char_offset,
351 &iter->segment_char_offset);
356 ensure_byte_offsets (GtkTextRealIter *iter)
358 if (iter->line_byte_offset < 0)
360 g_assert (iter->line_char_offset >= 0);
362 _gtk_text_line_char_to_byte_offsets (iter->line,
363 iter->line_char_offset,
364 &iter->line_byte_offset,
365 &iter->segment_byte_offset);
369 static inline gboolean
370 is_segment_start (GtkTextRealIter *real)
372 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
377 check_invariants (const GtkTextIter *iter)
379 if (gtk_debug_flags & GTK_DEBUG_TEXT)
380 _gtk_text_iter_check (iter);
383 #define check_invariants (x)
387 * gtk_text_iter_get_buffer:
390 * Return the #GtkTextBuffer this iterator is associated with
392 * Return value: the buffer
395 gtk_text_iter_get_buffer (const GtkTextIter *iter)
397 GtkTextRealIter *real;
399 g_return_val_if_fail (iter != NULL, NULL);
401 real = gtk_text_iter_make_surreal (iter);
406 check_invariants (iter);
408 return _gtk_text_btree_get_buffer (real->tree);
412 * gtk_text_iter_copy:
415 * Create a dynamically-allocated copy of an iterator. This function
416 * is not useful in applications, because iterators can be copied with a
417 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
418 * function is used by language bindings.
420 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
423 gtk_text_iter_copy (const GtkTextIter *iter)
425 GtkTextIter *new_iter;
427 g_return_val_if_fail (iter != NULL, NULL);
429 new_iter = g_new (GtkTextIter, 1);
437 * gtk_text_iter_free:
438 * @iter: a dynamically-allocated iterator
440 * Free an iterator allocated on the heap. This function
441 * is intended for use in language bindings, and is not
442 * especially useful for applications, because iterators can
443 * simply be allocated on the stack.
447 gtk_text_iter_free (GtkTextIter *iter)
449 g_return_if_fail (iter != NULL);
455 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
457 GtkTextRealIter *real;
459 g_return_val_if_fail (iter != NULL, 0);
461 real = gtk_text_iter_make_real (iter);
466 check_invariants (iter);
468 g_assert (real->segment != NULL);
470 return real->segment;
474 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
476 GtkTextRealIter *real;
478 g_return_val_if_fail (iter != NULL, 0);
480 real = gtk_text_iter_make_real (iter);
485 check_invariants (iter);
487 g_assert (real->any_segment != NULL);
489 return real->any_segment;
493 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
495 GtkTextRealIter *real;
497 g_return_val_if_fail (iter != NULL, 0);
499 real = gtk_text_iter_make_real (iter);
504 ensure_byte_offsets (real);
506 check_invariants (iter);
508 return real->segment_byte_offset;
512 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
514 GtkTextRealIter *real;
516 g_return_val_if_fail (iter != NULL, 0);
518 real = gtk_text_iter_make_real (iter);
523 ensure_char_offsets (real);
525 check_invariants (iter);
527 return real->segment_char_offset;
530 /* This function does not require a still-valid
533 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
535 const GtkTextRealIter *real;
537 g_return_val_if_fail (iter != NULL, 0);
539 real = (const GtkTextRealIter*)iter;
544 /* This function does not require a still-valid
547 _gtk_text_iter_get_btree (const GtkTextIter *iter)
549 const GtkTextRealIter *real;
551 g_return_val_if_fail (iter != NULL, 0);
553 real = (const GtkTextRealIter*)iter;
563 * gtk_text_iter_get_offset:
566 * Returns the character offset of an iterator.
567 * Each character in a #GtkTextBuffer has an offset,
568 * starting with 0 for the first character in the buffer.
569 * Use gtk_text_buffer_get_iter_at_offset () to convert an
570 * offset back into an iterator.
572 * Return value: a character offset
575 gtk_text_iter_get_offset (const GtkTextIter *iter)
577 GtkTextRealIter *real;
579 g_return_val_if_fail (iter != NULL, 0);
581 real = gtk_text_iter_make_surreal (iter);
586 check_invariants (iter);
588 if (real->cached_char_index < 0)
590 ensure_char_offsets (real);
592 real->cached_char_index =
593 _gtk_text_line_char_index (real->line);
594 real->cached_char_index += real->line_char_offset;
597 check_invariants (iter);
599 return real->cached_char_index;
603 * gtk_text_iter_get_line:
606 * Returns the line number containing the iterator. Lines in
607 * a #GtkTextBuffer are numbered beginning with 0 for the first
608 * line in the buffer.
610 * Return value: a line number
613 gtk_text_iter_get_line (const GtkTextIter *iter)
615 GtkTextRealIter *real;
617 g_return_val_if_fail (iter != NULL, 0);
619 real = gtk_text_iter_make_surreal (iter);
624 if (real->cached_line_number < 0)
625 real->cached_line_number =
626 _gtk_text_line_get_number (real->line);
628 check_invariants (iter);
630 return real->cached_line_number;
634 * gtk_text_iter_get_line_offset:
637 * Returns the character offset of the iterator,
638 * counting from the start of a newline-terminated line.
639 * The first character on the line has offset 0.
641 * Return value: offset from start of line
644 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
647 GtkTextRealIter *real;
649 g_return_val_if_fail (iter != NULL, 0);
651 real = gtk_text_iter_make_surreal (iter);
656 ensure_char_offsets (real);
658 check_invariants (iter);
660 return real->line_char_offset;
664 * gtk_text_iter_get_line_index:
667 * Returns the byte index of the iterator, counting
668 * from the start of a newline-terminated line.
669 * Remember that #GtkTextBuffer encodes text in
670 * UTF-8, and that characters can require a variable
671 * number of bytes to represent.
673 * Return value: distance from start of line, in bytes
676 gtk_text_iter_get_line_index (const GtkTextIter *iter)
678 GtkTextRealIter *real;
680 g_return_val_if_fail (iter != NULL, 0);
682 real = gtk_text_iter_make_surreal (iter);
687 ensure_byte_offsets (real);
689 check_invariants (iter);
691 return real->line_byte_offset;
699 * gtk_text_iter_get_char:
702 * Returns the Unicode character at this iterator. (Equivalent to
703 * operator* on a C++ iterator.) If the iterator points at a
704 * non-character element, such as an image embedded in the buffer, the
705 * Unicode "unknown" character 0xFFFC is returned. If invoked on
706 * the end iterator, zero is returned; zero is not a valid Unicode character.
707 * So you can write a loop which ends when gtk_text_iter_get_char ()
710 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
713 gtk_text_iter_get_char (const GtkTextIter *iter)
715 GtkTextRealIter *real;
717 g_return_val_if_fail (iter != NULL, 0);
719 real = gtk_text_iter_make_real (iter);
724 check_invariants (iter);
726 if (gtk_text_iter_is_last (iter))
728 else if (real->segment->type == >k_text_char_type)
730 ensure_byte_offsets (real);
732 return g_utf8_get_char (real->segment->body.chars +
733 real->segment_byte_offset);
737 /* Unicode "unknown character" 0xFFFC */
738 return GTK_TEXT_UNKNOWN_CHAR;
743 * gtk_text_iter_get_slice:
744 * @start: iterator at start of a range
745 * @end: iterator at end of a range
747 * Returns the text in the given range. A "slice" is an array of
748 * characters encoded in UTF-8 format, including the Unicode "unknown"
749 * character 0xFFFC for iterable non-character elements in the buffer,
750 * such as images. Because images are encoded in the slice, byte and
751 * character offsets in the returned array will correspond to byte
752 * offsets in the text buffer. Note that 0xFFFC can occur in normal
753 * text as well, so it is not a reliable indicator that a pixbuf or
754 * widget is in the buffer.
756 * Return value: slice of text from the buffer
759 gtk_text_iter_get_slice (const GtkTextIter *start,
760 const GtkTextIter *end)
762 g_return_val_if_fail (start != NULL, NULL);
763 g_return_val_if_fail (end != NULL, NULL);
765 check_invariants (start);
766 check_invariants (end);
768 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
772 * gtk_text_iter_get_text:
773 * @start: iterator at start of a range
774 * @end: iterator at end of a range
776 * Returns <emphasis>text</emphasis> in the given range. If the range
777 * contains non-text elements such as images, the character and byte
778 * offsets in the returned string will not correspond to character and
779 * byte offsets in the buffer. If you want offsets to correspond, see
780 * gtk_text_iter_get_slice ().
782 * Return value: array of characters from the buffer
785 gtk_text_iter_get_text (const GtkTextIter *start,
786 const GtkTextIter *end)
788 g_return_val_if_fail (start != NULL, NULL);
789 g_return_val_if_fail (end != NULL, NULL);
791 check_invariants (start);
792 check_invariants (end);
794 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
798 * gtk_text_iter_get_visible_slice:
799 * @start: iterator at start of range
800 * @end: iterator at end of range
802 * Like gtk_text_iter_get_slice (), but invisible text is not included.
803 * Invisible text is usually invisible because a #GtkTextTag with the
804 * "invisible" attribute turned on has been applied to it.
806 * Return value: slice of text from the buffer
809 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
810 const GtkTextIter *end)
812 g_return_val_if_fail (start != NULL, NULL);
813 g_return_val_if_fail (end != NULL, NULL);
815 check_invariants (start);
816 check_invariants (end);
818 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
822 * gtk_text_iter_get_visible_text:
823 * @start: iterator at start of range
824 * @end: iterator at end of range
826 * Like gtk_text_iter_get_text (), but invisible text is not included.
827 * Invisible text is usually invisible because a #GtkTextTag with the
828 * "invisible" attribute turned on has been applied to it.
830 * Return value: string containing visible text in the range
833 gtk_text_iter_get_visible_text (const GtkTextIter *start,
834 const GtkTextIter *end)
836 g_return_val_if_fail (start != NULL, NULL);
837 g_return_val_if_fail (end != NULL, NULL);
839 check_invariants (start);
840 check_invariants (end);
842 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
846 * gtk_text_iter_get_pixbuf:
849 * If the location pointed to by @iter contains a pixbuf, the pixbuf
850 * is returned (with no new reference count added). Otherwise,
853 * Return value: the pixbuf at @iter
856 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
858 GtkTextRealIter *real;
860 g_return_val_if_fail (iter != NULL, NULL);
862 real = gtk_text_iter_make_real (iter);
867 check_invariants (iter);
869 if (real->segment->type != >k_text_pixbuf_type)
872 return real->segment->body.pixbuf.pixbuf;
876 * gtk_text_iter_get_child_anchor:
879 * If the location pointed to by @iter contains a child anchor, the
880 * anchor is returned (with no new reference count added). Otherwise,
883 * Return value: the anchor at @iter
886 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
888 GtkTextRealIter *real;
890 g_return_val_if_fail (iter != NULL, NULL);
892 real = gtk_text_iter_make_real (iter);
897 check_invariants (iter);
899 if (real->segment->type != >k_text_child_type)
902 return real->segment->body.child.obj;
906 * gtk_text_iter_get_marks:
909 * Returns a list of all #GtkTextMark at this location. Because marks
910 * are not iterable (they don't take up any "space" in the buffer,
911 * they are just marks in between iterable locations), multiple marks
912 * can exist in the same place. The returned list is not in any
915 * Return value: list of #GtkTextMark
918 gtk_text_iter_get_marks (const GtkTextIter *iter)
920 GtkTextRealIter *real;
921 GtkTextLineSegment *seg;
924 g_return_val_if_fail (iter != NULL, NULL);
926 real = gtk_text_iter_make_real (iter);
931 check_invariants (iter);
934 seg = real->any_segment;
935 while (seg != real->segment)
937 if (seg->type == >k_text_left_mark_type ||
938 seg->type == >k_text_right_mark_type)
939 retval = g_slist_prepend (retval, seg->body.mark.obj);
944 /* The returned list isn't guaranteed to be in any special order,
950 * gtk_text_iter_get_toggled_tags:
952 * @toggled_on: TRUE to get toggled-on tags
954 * Returns a list of #GtkTextTag that are toggled on or off at this
955 * point. (If @toggled_on is TRUE, the list contains tags that are
956 * toggled on.) If a tag is toggled on at @iter, then some non-empty
957 * range of characters following @iter has that tag applied to it. If
958 * a tag is toggled off, then some non-empty range following @iter
959 * does <emphasis>not</emphasis> have the tag applied to it.
961 * Return value: tags toggled at this point
964 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
967 GtkTextRealIter *real;
968 GtkTextLineSegment *seg;
971 g_return_val_if_fail (iter != NULL, NULL);
973 real = gtk_text_iter_make_real (iter);
978 check_invariants (iter);
981 seg = real->any_segment;
982 while (seg != real->segment)
986 if (seg->type == >k_text_toggle_on_type)
988 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
993 if (seg->type == >k_text_toggle_off_type)
995 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1002 /* The returned list isn't guaranteed to be in any special order,
1008 * gtk_text_iter_begins_tag:
1009 * @iter: an iterator
1010 * @tag: a #GtkTextTag, or NULL
1012 * Returns TRUE if @tag is toggled on at exactly this point. If @tag
1013 * is NULL, returns TRUE if any tag is toggled on at this point. Note
1014 * that the gtk_text_iter_begins_tag () returns TRUE if @iter is the
1015 * <emphasis>start</emphasis> of the tagged range;
1016 * gtk_text_iter_has_tag () tells you whether an iterator is
1017 * <emphasis>within</emphasis> a tagged range.
1019 * Return value: whether @iter is the start of a range tagged with @tag
1022 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1025 GtkTextRealIter *real;
1026 GtkTextLineSegment *seg;
1028 g_return_val_if_fail (iter != NULL, FALSE);
1030 real = gtk_text_iter_make_real (iter);
1035 check_invariants (iter);
1037 seg = real->any_segment;
1038 while (seg != real->segment)
1040 if (seg->type == >k_text_toggle_on_type)
1043 seg->body.toggle.info->tag == tag)
1054 * gtk_text_iter_ends_tag:
1055 * @iter: an iterator
1056 * @tag: a #GtkTextTag, or NULL
1058 * Returns TRUE if @tag is toggled off at exactly this point. If @tag
1059 * is NULL, returns TRUE if any tag is toggled off at this point. Note
1060 * that the gtk_text_iter_ends_tag () returns TRUE if @iter is the
1061 * <emphasis>end</emphasis> of the tagged range;
1062 * gtk_text_iter_has_tag () tells you whether an iterator is
1063 * <emphasis>within</emphasis> a tagged range.
1065 * Return value: whether @iter is the end of a range tagged with @tag
1069 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1072 GtkTextRealIter *real;
1073 GtkTextLineSegment *seg;
1075 g_return_val_if_fail (iter != NULL, FALSE);
1077 real = gtk_text_iter_make_real (iter);
1082 check_invariants (iter);
1084 seg = real->any_segment;
1085 while (seg != real->segment)
1087 if (seg->type == >k_text_toggle_off_type)
1090 seg->body.toggle.info->tag == tag)
1101 * gtk_text_iter_toggles_tag:
1102 * @iter: an iterator
1103 * @tag: a #GtkTextTag, or NULL
1105 * This is equivalent to (gtk_text_iter_begins_tag () ||
1106 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1107 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1109 * Return value: whether @tag is toggled on or off at @iter
1112 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1115 GtkTextRealIter *real;
1116 GtkTextLineSegment *seg;
1118 g_return_val_if_fail (iter != NULL, FALSE);
1120 real = gtk_text_iter_make_real (iter);
1125 check_invariants (iter);
1127 seg = real->any_segment;
1128 while (seg != real->segment)
1130 if ( (seg->type == >k_text_toggle_off_type ||
1131 seg->type == >k_text_toggle_on_type) &&
1133 seg->body.toggle.info->tag == tag) )
1143 * gtk_text_iter_has_tag:
1144 * @iter: an iterator
1145 * @tag: a #GtkTextTag
1147 * Returns TRUE if @iter is within a range tagged with @tag.
1149 * Return value: whether @iter is tagged with @tag
1152 gtk_text_iter_has_tag (const GtkTextIter *iter,
1155 GtkTextRealIter *real;
1157 g_return_val_if_fail (iter != NULL, FALSE);
1158 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1160 real = gtk_text_iter_make_surreal (iter);
1165 check_invariants (iter);
1167 if (real->line_byte_offset >= 0)
1169 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1170 real->line_byte_offset, tag);
1174 g_assert (real->line_char_offset >= 0);
1175 return _gtk_text_line_char_has_tag (real->line, real->tree,
1176 real->line_char_offset, tag);
1181 * gtk_text_iter_get_tags:
1182 * @iter: a #GtkTextIter
1184 * Returns a list of tags that apply to @iter, in ascending order of
1185 * priority (highest-priority tags are last). The #GtkTextTag in the
1186 * list don't have a reference added, but you have to free the list
1189 * Return value: list of #GtkTextTag
1192 gtk_text_iter_get_tags (const GtkTextIter *iter)
1199 g_return_val_if_fail (iter != NULL, NULL);
1201 /* Get the tags at this spot */
1202 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1204 /* No tags, use default style */
1205 if (tags == NULL || tag_count == 0)
1213 /* Sort tags in ascending order of priority */
1214 _gtk_text_tag_array_sort (tags, tag_count);
1218 while (i < tag_count)
1220 retval = g_slist_prepend (retval, tags[i]);
1226 /* Return tags in ascending order of priority */
1227 return g_slist_reverse (retval);
1231 * gtk_text_iter_editable:
1232 * @iter: an iterator
1233 * @default_setting: TRUE if text is editable by default
1235 * Returns whether @iter is within an editable region of text.
1236 * Non-editable text is "locked" and can't be changed by the user via
1237 * #GtkTextView. This function is simply a convenience wrapper around
1238 * gtk_text_iter_get_attributes (). If no tags applied to this text
1239 * affect editability, @default_setting will be returned.
1241 * Return value: whether @iter is inside an editable range
1244 gtk_text_iter_editable (const GtkTextIter *iter,
1245 gboolean default_setting)
1247 GtkTextAttributes *values;
1250 values = gtk_text_attributes_new ();
1252 values->editable = default_setting;
1254 gtk_text_iter_get_attributes (iter, values);
1256 retval = values->editable;
1258 gtk_text_attributes_unref (values);
1264 * gtk_text_iter_get_language:
1265 * @iter: an iterator
1267 * A convenience wrapper around gtk_text_iter_get_attributes (),
1268 * which returns the language in effect at @iter. If no tags affecting
1269 * language * apply to @iter, the return value is identical to that of
1270 * gtk_get_default_language ().
1272 * Return value: language in effect at @iter
1275 gtk_text_iter_get_language (const GtkTextIter *iter)
1277 GtkTextAttributes *values;
1280 values = gtk_text_attributes_new ();
1282 gtk_text_iter_get_attributes (iter, values);
1284 retval = g_strdup (values->language);
1286 gtk_text_attributes_unref (values);
1292 * gtk_text_iter_starts_line:
1293 * @iter: an iterator
1295 * Returns TRUE if @iter begins a paragraph,
1296 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1297 * However this function is potentially more efficient than
1298 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1299 * the offset, it just has to see whether it's 0.
1301 * Return value: whether @iter begins a line
1304 gtk_text_iter_starts_line (const GtkTextIter *iter)
1306 GtkTextRealIter *real;
1308 g_return_val_if_fail (iter != NULL, FALSE);
1310 real = gtk_text_iter_make_surreal (iter);
1315 check_invariants (iter);
1317 if (real->line_byte_offset >= 0)
1319 return (real->line_byte_offset == 0);
1323 g_assert (real->line_char_offset >= 0);
1324 return (real->line_char_offset == 0);
1329 * gtk_text_iter_ends_line:
1330 * @iter: an iterator
1332 * Returns TRUE if @iter points to the start of the paragraph delimiter
1333 * characters for a line (delimiters will be either a newline, a
1334 * carriage return, a carriage return followed by a newline, or a
1335 * Unicode paragraph separator character). Note that an iterator pointing
1336 * to the \n of a \r\n pair will not be counted as the end of a line,
1337 * the line ends before the \r.
1339 * Return value: whether @iter is at the end of a line
1342 gtk_text_iter_ends_line (const GtkTextIter *iter)
1344 GtkTextRealIter *real;
1347 g_return_val_if_fail (iter != NULL, FALSE);
1349 real = gtk_text_iter_make_real (iter);
1351 check_invariants (iter);
1353 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1354 * Unicode 3.0; update this if that changes.
1356 #define PARAGRAPH_SEPARATOR 0x2029
1358 wc = gtk_text_iter_get_char (iter);
1360 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR)
1362 else if (wc == '\n')
1364 /* need to determine if a \r precedes the \n, in which case
1365 * we aren't the end of the line
1367 GtkTextIter tmp = *iter;
1368 if (!gtk_text_iter_backward_char (&tmp))
1371 return gtk_text_iter_get_char (&tmp) != '\r';
1378 * gtk_text_iter_is_last:
1379 * @iter: an iterator
1381 * Returns TRUE if @iter is the end iterator, i.e. one past the last
1382 * dereferenceable iterator in the buffer. gtk_text_iter_is_last () is
1383 * the most efficient way to check whether an iterator is the end
1386 * Return value: whether @iter is the end iterator
1389 gtk_text_iter_is_last (const GtkTextIter *iter)
1391 GtkTextRealIter *real;
1393 g_return_val_if_fail (iter != NULL, FALSE);
1395 real = gtk_text_iter_make_surreal (iter);
1400 check_invariants (iter);
1402 return _gtk_text_line_is_last (real->line, real->tree);
1406 * gtk_text_iter_is_first:
1407 * @iter: an iterator
1409 * Returns TRUE if @iter is the first iterator in the buffer, that is
1410 * if @iter has a character offset of 0.
1412 * Return value: whether @iter is the first in the buffer
1415 gtk_text_iter_is_first (const GtkTextIter *iter)
1417 return gtk_text_iter_get_offset (iter) == 0;
1421 * gtk_text_iter_get_chars_in_line:
1422 * @iter: an iterator
1424 * Returns the number of characters in the line containing @iter,
1425 * including the paragraph delimiters.
1427 * Return value: number of characters in the line
1430 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1432 GtkTextRealIter *real;
1434 GtkTextLineSegment *seg;
1436 g_return_val_if_fail (iter != NULL, FALSE);
1438 real = gtk_text_iter_make_surreal (iter);
1443 check_invariants (iter);
1445 if (real->line_char_offset >= 0)
1447 /* We can start at the segments we've already found. */
1448 count = real->line_char_offset - real->segment_char_offset;
1449 seg = _gtk_text_iter_get_indexable_segment (iter);
1453 /* count whole line. */
1454 seg = real->line->segments;
1461 count += seg->char_count;
1470 * gtk_text_iter_get_bytes_in_line:
1471 * @iter: an iterator
1473 * Returns the number of bytes in the line containing @iter,
1474 * including the paragraph delimiters.
1476 * Return value: number of bytes in the line
1479 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1481 GtkTextRealIter *real;
1483 GtkTextLineSegment *seg;
1485 g_return_val_if_fail (iter != NULL, FALSE);
1487 real = gtk_text_iter_make_surreal (iter);
1492 check_invariants (iter);
1494 if (real->line_byte_offset >= 0)
1496 /* We can start at the segments we've already found. */
1497 count = real->line_byte_offset - real->segment_byte_offset;
1498 seg = _gtk_text_iter_get_indexable_segment (iter);
1502 /* count whole line. */
1503 seg = real->line->segments;
1509 count += seg->byte_count;
1518 * gtk_text_iter_get_attributes:
1519 * @iter: an iterator
1520 * @values: a #GtkTextAttributes to be filled in
1522 * Computes the effect of any tags applied to this spot in the
1523 * text. The @values parameter should be initialized to the default
1524 * settings you wish to use if no tags are in effect.
1525 * gtk_text_iter_get_attributes () will modify @values, applying the
1526 * effects of any tags present at @iter. If any tags affected @values,
1527 * the function returns TRUE.
1529 * Return value: TRUE if @values was modified
1532 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1533 GtkTextAttributes *values)
1538 /* Get the tags at this spot */
1539 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1541 /* No tags, use default style */
1542 if (tags == NULL || tag_count == 0)
1550 /* Sort tags in ascending order of priority */
1551 _gtk_text_tag_array_sort (tags, tag_count);
1553 _gtk_text_attributes_fill_from_tags (values,
1563 * Increments/decrements
1566 /* The return value of this indicates WHETHER WE MOVED.
1567 * The return value of public functions indicates
1568 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1571 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1573 GtkTextLine *new_line;
1575 new_line = _gtk_text_line_next (real->line);
1577 g_assert (new_line != real->line);
1579 if (new_line != NULL)
1581 real->line = new_line;
1583 real->line_byte_offset = 0;
1584 real->line_char_offset = 0;
1586 real->segment_byte_offset = 0;
1587 real->segment_char_offset = 0;
1589 /* Find first segments in new line */
1590 real->any_segment = real->line->segments;
1591 real->segment = real->any_segment;
1592 while (real->segment->char_count == 0)
1593 real->segment = real->segment->next;
1599 /* There is no way to move forward; we were already
1600 at the "end" index. (the end index is the last
1601 line pointer, segment_byte_offset of 0) */
1603 g_assert (real->line_char_offset == 0 ||
1604 real->line_byte_offset == 0);
1606 /* The only indexable segment allowed on the bogus
1607 line at the end is a single char segment containing
1609 if (real->segments_changed_stamp ==
1610 _gtk_text_btree_get_segments_changed_stamp (real->tree))
1612 g_assert (real->segment->type == >k_text_char_type);
1613 g_assert (real->segment->char_count == 1);
1615 /* We leave real->line as-is */
1622 /* The return value of this indicates WHETHER WE MOVED.
1623 * The return value of public functions indicates
1624 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1627 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1629 GtkTextLine *new_line;
1631 new_line = _gtk_text_line_previous (real->line);
1633 g_assert (new_line != real->line);
1635 if (new_line != NULL)
1637 real->line = new_line;
1639 real->line_byte_offset = 0;
1640 real->line_char_offset = 0;
1642 real->segment_byte_offset = 0;
1643 real->segment_char_offset = 0;
1645 /* Find first segments in new line */
1646 real->any_segment = real->line->segments;
1647 real->segment = real->any_segment;
1648 while (real->segment->char_count == 0)
1649 real->segment = real->segment->next;
1655 /* There is no way to move backward; we were already
1656 at the first line. */
1658 /* We leave real->line as-is */
1660 /* Note that we didn't clamp to the start of the first line. */
1666 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1670 forward_char (GtkTextRealIter *real)
1672 GtkTextIter *iter = (GtkTextIter*)real;
1674 check_invariants ((GtkTextIter*)real);
1676 ensure_char_offsets (real);
1678 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1680 /* Need to move to the next segment; if no next segment,
1681 need to move to next line. */
1682 return _gtk_text_iter_forward_indexable_segment (iter);
1686 /* Just moving within a segment. Keep byte count
1687 up-to-date, if it was already up-to-date. */
1689 g_assert (real->segment->type == >k_text_char_type);
1691 if (real->line_byte_offset >= 0)
1694 const char * start =
1695 real->segment->body.chars + real->segment_byte_offset;
1697 bytes = g_utf8_next_char (start) - start;
1699 real->line_byte_offset += bytes;
1700 real->segment_byte_offset += bytes;
1702 g_assert (real->segment_byte_offset < real->segment->byte_count);
1705 real->line_char_offset += 1;
1706 real->segment_char_offset += 1;
1708 adjust_char_index (real, 1);
1710 g_assert (real->segment_char_offset < real->segment->char_count);
1712 /* We moved into the middle of a segment, so the any_segment
1713 must now be the segment we're in the middle of. */
1714 real->any_segment = real->segment;
1716 check_invariants ((GtkTextIter*)real);
1718 if (gtk_text_iter_is_last ((GtkTextIter*)real))
1726 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1728 /* Need to move to the next segment; if no next segment,
1729 need to move to next line. */
1730 GtkTextLineSegment *seg;
1731 GtkTextLineSegment *any_seg;
1732 GtkTextRealIter *real;
1736 g_return_val_if_fail (iter != NULL, FALSE);
1738 real = gtk_text_iter_make_real (iter);
1743 check_invariants (iter);
1745 if (real->line_char_offset >= 0)
1747 chars_skipped = real->segment->char_count - real->segment_char_offset;
1748 g_assert (chars_skipped > 0);
1753 if (real->line_byte_offset >= 0)
1755 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1756 g_assert (bytes_skipped > 0);
1761 /* Get first segment of any kind */
1762 any_seg = real->segment->next;
1763 /* skip non-indexable segments, if any */
1765 while (seg != NULL && seg->char_count == 0)
1770 real->any_segment = any_seg;
1771 real->segment = seg;
1773 if (real->line_byte_offset >= 0)
1775 g_assert (bytes_skipped > 0);
1776 real->segment_byte_offset = 0;
1777 real->line_byte_offset += bytes_skipped;
1780 if (real->line_char_offset >= 0)
1782 g_assert (chars_skipped > 0);
1783 real->segment_char_offset = 0;
1784 real->line_char_offset += chars_skipped;
1785 adjust_char_index (real, chars_skipped);
1788 check_invariants (iter);
1794 /* End of the line */
1795 if (forward_line_leaving_caches_unmodified (real))
1797 adjust_line_number (real, 1);
1798 if (real->line_char_offset >= 0)
1799 adjust_char_index (real, chars_skipped);
1801 g_assert (real->line_byte_offset == 0);
1802 g_assert (real->line_char_offset == 0);
1803 g_assert (real->segment_byte_offset == 0);
1804 g_assert (real->segment_char_offset == 0);
1805 g_assert (gtk_text_iter_starts_line (iter));
1807 check_invariants (iter);
1809 if (gtk_text_iter_is_last (iter))
1818 check_invariants (iter);
1826 at_last_indexable_segment (GtkTextRealIter *real)
1828 GtkTextLineSegment *seg;
1830 /* Return TRUE if there are no indexable segments after
1834 seg = real->segment->next;
1837 if (seg->char_count > 0)
1844 /* Goes back to the start of the next segment, even if
1845 * we're not at the start of the current segment (always
1846 * ends up on a different segment if it returns TRUE)
1849 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
1851 /* Move to the start of the previous segment; if no previous
1852 * segment, to the last segment in the previous line. This is
1853 * inherently a bit inefficient due to the singly-linked list and
1854 * tree nodes, but we can't afford the RAM for doubly-linked.
1856 GtkTextRealIter *real;
1857 GtkTextLineSegment *seg;
1858 GtkTextLineSegment *any_seg;
1859 GtkTextLineSegment *prev_seg;
1860 GtkTextLineSegment *prev_any_seg;
1864 g_return_val_if_fail (iter != NULL, FALSE);
1866 real = gtk_text_iter_make_real (iter);
1871 check_invariants (iter);
1873 /* Find first segments in line */
1874 any_seg = real->line->segments;
1876 while (seg->char_count == 0)
1879 if (seg == real->segment)
1881 /* Could probably do this case faster by hand-coding the
1885 /* We were already at the start of a line;
1886 * go back to the previous line.
1888 if (gtk_text_iter_backward_line (iter))
1890 /* Go forward to last indexable segment in line. */
1891 while (!at_last_indexable_segment (real))
1892 _gtk_text_iter_forward_indexable_segment (iter);
1894 check_invariants (iter);
1899 return FALSE; /* We were at the start of the first line. */
1902 /* We must be in the middle of a line; so find the indexable
1903 * segment just before our current segment.
1905 g_assert (seg != real->segment);
1906 while (seg != real->segment)
1909 prev_any_seg = any_seg;
1911 any_seg = seg->next;
1913 while (seg->char_count == 0)
1917 g_assert (prev_seg != NULL);
1918 g_assert (prev_any_seg != NULL);
1919 g_assert (prev_seg->char_count > 0);
1921 /* We skipped the entire previous segment, plus any
1922 * chars we were into the current segment.
1924 if (real->segment_byte_offset >= 0)
1925 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
1929 if (real->segment_char_offset >= 0)
1930 chars_skipped = prev_seg->char_count + real->segment_char_offset;
1934 real->segment = prev_seg;
1935 real->any_segment = prev_any_seg;
1936 real->segment_byte_offset = 0;
1937 real->segment_char_offset = 0;
1939 if (bytes_skipped >= 0)
1941 if (real->line_byte_offset >= 0)
1943 real->line_byte_offset -= bytes_skipped;
1944 g_assert (real->line_byte_offset >= 0);
1948 real->line_byte_offset = -1;
1950 if (chars_skipped >= 0)
1952 if (real->line_char_offset >= 0)
1954 real->line_char_offset -= chars_skipped;
1955 g_assert (real->line_char_offset >= 0);
1958 if (real->cached_char_index >= 0)
1960 real->cached_char_index -= chars_skipped;
1961 g_assert (real->cached_char_index >= 0);
1966 real->line_char_offset = -1;
1967 real->cached_char_index = -1;
1970 /* line number is unchanged. */
1972 check_invariants (iter);
1978 * gtk_text_iter_forward_char:
1979 * @iter: an iterator
1981 * Moves @iter forward by one character offset. Note that images
1982 * embedded in the buffer occupy 1 character slot, so
1983 * gtk_text_iter_forward_char () may actually move onto an image instead
1984 * of a character, if you have images in your buffer. If @iter is the
1985 * end iterator or one character before it, @iter will now point at
1986 * the end iterator, and gtk_text_iter_forward_char () returns FALSE for
1987 * convenience when writing loops.
1989 * Return value: whether the new position is the end iterator
1992 gtk_text_iter_forward_char (GtkTextIter *iter)
1994 GtkTextRealIter *real;
1996 g_return_val_if_fail (iter != NULL, FALSE);
1998 real = gtk_text_iter_make_real (iter);
2004 check_invariants (iter);
2005 return forward_char (real);
2010 * gtk_text_iter_backward_char:
2011 * @iter: an iterator
2013 * Moves backward by one character offset. Returns TRUE if movement
2014 * was possible; if @iter was the first in the buffer (character
2015 * offset 0), gtk_text_iter_backward_char () returns FALSE for convenience when
2018 * Return value: whether movement was possible
2021 gtk_text_iter_backward_char (GtkTextIter *iter)
2023 g_return_val_if_fail (iter != NULL, FALSE);
2025 check_invariants (iter);
2027 return gtk_text_iter_backward_chars (iter, 1);
2031 Definitely we should try to linear scan as often as possible for
2032 movement within a single line, because we can't use the BTree to
2033 speed within-line searches up; for movement between lines, we would
2034 like to avoid the linear scan probably.
2036 Instead of using this constant, it might be nice to cache the line
2037 length in the iterator and linear scan if motion is within a single
2040 I guess you'd have to profile the various approaches.
2042 #define MAX_LINEAR_SCAN 150
2046 * gtk_text_iter_forward_chars:
2047 * @iter: an iterator
2048 * @count: number of characters to move, may be negative
2050 * Moves @count characters if possible (if @count would move past the
2051 * start or end of the buffer, moves to the start or end of the
2052 * buffer). The return value indicates whether the new position of
2053 * @iter is different from its original position, and dereferenceable
2054 * (the last iterator in the buffer is not dereferenceable). If @count
2055 * is 0, the function does nothing and returns FALSE.
2057 * Return value: whether @iter moved and is dereferenceable
2060 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2062 GtkTextRealIter *real;
2064 g_return_val_if_fail (iter != NULL, FALSE);
2066 real = gtk_text_iter_make_real (iter);
2070 else if (count == 0)
2073 return gtk_text_iter_backward_chars (iter, 0 - count);
2074 else if (count < MAX_LINEAR_SCAN)
2076 check_invariants (iter);
2080 if (!forward_char (real))
2085 return forward_char (real);
2089 gint current_char_index;
2090 gint new_char_index;
2092 check_invariants (iter);
2094 current_char_index = gtk_text_iter_get_offset (iter);
2096 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2097 return FALSE; /* can't move forward */
2099 new_char_index = current_char_index + count;
2100 gtk_text_iter_set_offset (iter, new_char_index);
2102 check_invariants (iter);
2104 /* Return FALSE if we're on the non-dereferenceable end
2107 if (gtk_text_iter_is_last (iter))
2115 * gtk_text_iter_backward_chars:
2116 * @iter: an iterator
2117 * @count: number of characters to move
2119 * Moves @count characters backward, if possible (if @count would move
2120 * past the start or end of the buffer, moves to the start or end of
2121 * the buffer). The return value indicates whether the iterator moved
2122 * onto a dereferenceable position; if the iterator didn't move, or
2123 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2124 * the function does nothing and returns FALSE.
2126 * Return value: whether @iter moved and is dereferenceable
2130 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2132 GtkTextRealIter *real;
2134 g_return_val_if_fail (iter != NULL, FALSE);
2136 real = gtk_text_iter_make_real (iter);
2140 else if (count == 0)
2143 return gtk_text_iter_forward_chars (iter, 0 - count);
2145 ensure_char_offsets (real);
2146 check_invariants (iter);
2148 if (count <= real->segment_char_offset)
2150 /* Optimize the within-segment case */
2151 g_assert (real->segment->char_count > 0);
2152 g_assert (real->segment->type == >k_text_char_type);
2154 real->segment_char_offset -= count;
2155 g_assert (real->segment_char_offset >= 0);
2157 if (real->line_byte_offset >= 0)
2159 gint new_byte_offset;
2162 new_byte_offset = 0;
2164 while (i < real->segment_char_offset)
2166 const char * start = real->segment->body.chars + new_byte_offset;
2167 new_byte_offset += g_utf8_next_char (start) - start;
2172 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2173 real->segment_byte_offset = new_byte_offset;
2176 real->line_char_offset -= count;
2178 adjust_char_index (real, 0 - count);
2180 check_invariants (iter);
2186 /* We need to go back into previous segments. For now,
2187 * just keep this really simple. FIXME
2188 * use backward_indexable_segment.
2190 if (TRUE || count > MAX_LINEAR_SCAN)
2192 gint current_char_index;
2193 gint new_char_index;
2195 current_char_index = gtk_text_iter_get_offset (iter);
2197 if (current_char_index == 0)
2198 return FALSE; /* can't move backward */
2200 new_char_index = current_char_index - count;
2201 if (new_char_index < 0)
2203 gtk_text_iter_set_offset (iter, new_char_index);
2205 check_invariants (iter);
2211 /* FIXME backward_indexable_segment here */
2220 /* These two can't be implemented efficiently (always have to use
2221 * a linear scan, since that's the only way to find all the non-text
2226 * gtk_text_iter_forward_text_chars:
2227 * @iter: a #GtkTextIter
2228 * @count: number of chars to move
2230 * Moves forward by @count text characters (pixbufs, widgets,
2231 * etc. do not count as characters for this). Equivalent to moving
2232 * through the results of gtk_text_iter_get_text (), rather than
2233 * gtk_text_iter_get_slice ().
2235 * Return value: whether @iter moved and is dereferenceable
2238 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2247 * gtk_text_iter_forward_text_chars:
2248 * @iter: a #GtkTextIter
2249 * @count: number of chars to move
2251 * Moves backward by @count text characters (pixbufs, widgets,
2252 * etc. do not count as characters for this). Equivalent to moving
2253 * through the results of gtk_text_iter_get_text (), rather than
2254 * gtk_text_iter_get_slice ().
2256 * Return value: whether @iter moved and is dereferenceable
2259 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2268 * gtk_text_iter_forward_line:
2269 * @iter: an iterator
2271 * Moves @iter to the start of the next line. Returns TRUE if there
2272 * was a next line to move to, and FALSE if @iter was simply moved to
2273 * the end of the buffer and is now not dereferenceable, or if @iter was
2274 * already at the end of the buffer.
2276 * Return value: whether @iter can be dereferenced
2279 gtk_text_iter_forward_line (GtkTextIter *iter)
2281 GtkTextRealIter *real;
2283 g_return_val_if_fail (iter != NULL, FALSE);
2285 real = gtk_text_iter_make_real (iter);
2290 check_invariants (iter);
2292 if (forward_line_leaving_caches_unmodified (real))
2294 invalidate_char_index (real);
2295 adjust_line_number (real, 1);
2297 check_invariants (iter);
2299 if (gtk_text_iter_is_last (iter))
2306 check_invariants (iter);
2312 * gtk_text_iter_backward_line:
2313 * @iter: an iterator
2315 * Moves @iter to the start of the previous line. Returns TRUE if
2316 * @iter could be moved; i.e. if @iter was at character offset 0, this
2317 * function returns FALSE. Therefore if @iter was already on line 0,
2318 * but not at the start of the line, @iter is snapped to the start of
2319 * the line and the function returns TRUE. (Note that this implies that
2320 * in a loop calling this function, the line number may not change on
2321 * every iteration, if your first iteration is on line 0.)
2323 * Return value: whether @iter moved
2326 gtk_text_iter_backward_line (GtkTextIter *iter)
2328 GtkTextLine *new_line;
2329 GtkTextRealIter *real;
2330 gboolean offset_will_change;
2333 g_return_val_if_fail (iter != NULL, FALSE);
2335 real = gtk_text_iter_make_real (iter);
2340 check_invariants (iter);
2342 new_line = _gtk_text_line_previous (real->line);
2344 offset_will_change = FALSE;
2345 if (real->line_char_offset > 0)
2346 offset_will_change = TRUE;
2348 if (new_line != NULL)
2350 real->line = new_line;
2352 adjust_line_number (real, -1);
2356 if (!offset_will_change)
2360 invalidate_char_index (real);
2362 real->line_byte_offset = 0;
2363 real->line_char_offset = 0;
2365 real->segment_byte_offset = 0;
2366 real->segment_char_offset = 0;
2368 /* Find first segment in line */
2369 real->any_segment = real->line->segments;
2370 real->segment = _gtk_text_line_byte_to_segment (real->line,
2373 g_assert (offset == 0);
2375 /* Note that if we are on the first line, we snap to the start of
2376 * the first line and return TRUE, so TRUE means the iterator
2377 * changed, not that the line changed; this is maybe a bit
2378 * weird. I'm not sure there's an obvious right thing to do though.
2381 check_invariants (iter);
2387 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2390 return gtk_text_iter_backward_lines (iter, 0 - count);
2391 else if (count == 0)
2393 else if (count == 1)
2395 check_invariants (iter);
2396 return gtk_text_iter_forward_line (iter);
2402 old_line = gtk_text_iter_get_line (iter);
2404 gtk_text_iter_set_line (iter, old_line + count);
2406 check_invariants (iter);
2408 /* return whether it moved, and is dereferenceable. */
2410 (gtk_text_iter_get_line (iter) != old_line) &&
2411 !gtk_text_iter_is_last (iter);
2416 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2419 return gtk_text_iter_forward_lines (iter, 0 - count);
2420 else if (count == 0)
2422 else if (count == 1)
2424 return gtk_text_iter_backward_line (iter);
2430 old_line = gtk_text_iter_get_line (iter);
2432 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2434 return (gtk_text_iter_get_line (iter) != old_line);
2438 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2443 gboolean already_moved_initially);
2445 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2451 find_word_end_func (const PangoLogAttr *attrs,
2456 gboolean already_moved_initially)
2458 if (!already_moved_initially)
2461 /* Find end of next word */
2462 while (offset < min_offset + len &&
2463 !attrs[offset].is_word_end)
2466 *found_offset = offset;
2468 return offset < min_offset + len;
2472 is_word_end_func (const PangoLogAttr *attrs,
2477 return attrs[offset].is_word_end;
2481 find_word_start_func (const PangoLogAttr *attrs,
2486 gboolean already_moved_initially)
2488 if (!already_moved_initially)
2491 /* Find start of prev word */
2492 while (offset >= min_offset &&
2493 !attrs[offset].is_word_start)
2496 *found_offset = offset;
2498 return offset >= min_offset;
2502 is_word_start_func (const PangoLogAttr *attrs,
2507 return attrs[offset].is_word_start;
2511 inside_word_func (const PangoLogAttr *attrs,
2516 /* Find next word start or end */
2517 while (offset >= min_offset &&
2518 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2521 return attrs[offset].is_word_start;
2525 test_log_attrs (const GtkTextIter *iter,
2526 TestLogAttrFunc func)
2529 const PangoLogAttr *attrs;
2531 gboolean result = FALSE;
2533 g_return_val_if_fail (iter != NULL, FALSE);
2535 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2538 offset = gtk_text_iter_get_line_offset (iter);
2540 g_assert (char_len > 0);
2542 if (offset < char_len)
2543 result = (* func) (attrs, offset, 0, char_len);
2549 find_line_log_attrs (const GtkTextIter *iter,
2550 FindLogAttrFunc func,
2552 gboolean already_moved_initially)
2555 const PangoLogAttr *attrs;
2557 gboolean result = FALSE;
2559 g_return_val_if_fail (iter != NULL, FALSE);
2561 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2564 offset = gtk_text_iter_get_line_offset (iter);
2566 g_assert (char_len > 0);
2568 if (offset < char_len)
2569 result = (* func) (attrs, offset, 0, char_len, found_offset,
2570 already_moved_initially);
2575 /* FIXME this function is very, very gratuitously slow */
2577 find_by_log_attrs (GtkTextIter *iter,
2578 FindLogAttrFunc func,
2580 gboolean already_moved_initially)
2584 gboolean found = FALSE;
2586 g_return_val_if_fail (iter != NULL, FALSE);
2590 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2596 if (gtk_text_iter_forward_line (iter))
2597 return find_by_log_attrs (iter, func, forward,
2604 /* go to end of previous line */
2605 gtk_text_iter_set_line_offset (iter, 0);
2607 if (gtk_text_iter_backward_char (iter))
2608 return find_by_log_attrs (iter, func, forward,
2616 gtk_text_iter_set_line_offset (iter, offset);
2619 !gtk_text_iter_equal (iter, &orig) &&
2620 !gtk_text_iter_is_last (iter);
2625 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2627 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2631 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2633 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2636 /* FIXME a loop around a truly slow function means
2637 * a truly spectacularly slow function.
2640 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
2643 g_return_val_if_fail (iter != NULL, FALSE);
2649 return gtk_text_iter_backward_word_starts (iter, -count);
2651 if (!gtk_text_iter_forward_word_end (iter))
2657 if (!gtk_text_iter_forward_word_end (iter))
2665 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
2668 g_return_val_if_fail (iter != NULL, FALSE);
2671 return gtk_text_iter_forward_word_ends (iter, -count);
2673 if (!gtk_text_iter_backward_word_start (iter))
2679 if (!gtk_text_iter_backward_word_start (iter))
2688 gtk_text_iter_starts_word (const GtkTextIter *iter)
2690 return test_log_attrs (iter, is_word_start_func);
2694 gtk_text_iter_ends_word (const GtkTextIter *iter)
2696 return test_log_attrs (iter, is_word_end_func);
2700 gtk_text_iter_inside_word (const GtkTextIter *iter)
2702 return test_log_attrs (iter, inside_word_func);
2706 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
2711 gboolean already_moved_initially)
2713 if (!already_moved_initially)
2716 while (offset < (min_offset + len) &&
2717 !attrs[offset].is_cursor_position)
2720 *found_offset = offset;
2722 return offset < (min_offset + len);
2726 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
2731 gboolean already_moved_initially)
2733 if (!already_moved_initially)
2736 while (offset > min_offset &&
2737 !attrs[offset].is_cursor_position)
2740 *found_offset = offset;
2742 return offset >= min_offset;
2746 is_cursor_pos_func (const PangoLogAttr *attrs,
2751 return attrs[offset].is_cursor_position;
2755 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
2757 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
2761 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
2763 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
2767 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
2770 g_return_val_if_fail (iter != NULL, FALSE);
2776 return gtk_text_iter_backward_cursor_positions (iter, -count);
2778 if (!gtk_text_iter_forward_cursor_position (iter))
2784 if (!gtk_text_iter_forward_cursor_position (iter))
2792 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
2795 g_return_val_if_fail (iter != NULL, FALSE);
2801 return gtk_text_iter_forward_cursor_positions (iter, -count);
2803 if (!gtk_text_iter_backward_cursor_position (iter))
2809 if (!gtk_text_iter_backward_cursor_position (iter))
2817 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
2819 return test_log_attrs (iter, is_cursor_pos_func);
2823 gtk_text_iter_set_line_offset (GtkTextIter *iter,
2826 GtkTextRealIter *real;
2829 g_return_if_fail (iter != NULL);
2831 real = gtk_text_iter_make_surreal (iter);
2836 check_invariants (iter);
2838 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
2840 g_return_if_fail (char_on_line <= chars_in_line);
2842 if (char_on_line < chars_in_line)
2843 iter_set_from_char_offset (real, real->line, char_on_line);
2845 gtk_text_iter_forward_line (iter); /* set to start of next line */
2847 check_invariants (iter);
2851 gtk_text_iter_set_line_index (GtkTextIter *iter,
2854 GtkTextRealIter *real;
2857 g_return_if_fail (iter != NULL);
2859 real = gtk_text_iter_make_surreal (iter);
2864 check_invariants (iter);
2866 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
2868 g_return_if_fail (byte_on_line <= bytes_in_line);
2870 if (byte_on_line < bytes_in_line)
2871 iter_set_from_byte_offset (real, real->line, byte_on_line);
2873 gtk_text_iter_forward_line (iter);
2875 if (real->segment->type == >k_text_char_type &&
2876 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
2877 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
2878 "character; this will crash the text buffer. "
2879 "Byte indexes must refer to the start of a character.",
2880 G_STRLOC, byte_on_line);
2882 check_invariants (iter);
2886 gtk_text_iter_set_line (GtkTextIter *iter,
2891 GtkTextRealIter *real;
2893 g_return_if_fail (iter != NULL);
2895 real = gtk_text_iter_make_surreal (iter);
2900 check_invariants (iter);
2902 line = _gtk_text_btree_get_line (real->tree, line_number, &real_line);
2904 iter_set_from_char_offset (real, line, 0);
2906 /* We might as well cache this, since we know it. */
2907 real->cached_line_number = real_line;
2909 check_invariants (iter);
2913 gtk_text_iter_set_offset (GtkTextIter *iter, gint char_index)
2916 GtkTextRealIter *real;
2918 gint real_char_index;
2920 g_return_if_fail (iter != NULL);
2922 real = gtk_text_iter_make_surreal (iter);
2927 check_invariants (iter);
2929 if (real->cached_char_index >= 0 &&
2930 real->cached_char_index == char_index)
2933 line = _gtk_text_btree_get_line_at_char (real->tree,
2938 iter_set_from_char_offset (real, line, real_char_index - line_start);
2940 /* Go ahead and cache this since we have it. */
2941 real->cached_char_index = real_char_index;
2943 check_invariants (iter);
2947 gtk_text_iter_forward_to_end (GtkTextIter *iter)
2949 GtkTextBuffer *buffer;
2950 GtkTextRealIter *real;
2952 g_return_if_fail (iter != NULL);
2954 real = gtk_text_iter_make_surreal (iter);
2959 buffer = _gtk_text_btree_get_buffer (real->tree);
2961 gtk_text_buffer_get_last_iter (buffer, iter);
2965 * gtk_text_iter_forward_to_line_end:
2966 * @iter: a #GtkTextIter
2968 * Moves the iterator to point to the paragraph delimiter characters,
2969 * which will be either a newline, a carriage return, a carriage
2970 * return/newline in sequence, or the Unicode paragraph separator
2971 * character. If the iterator is already at the paragraph delimiter
2972 * characters, moves to the paragraph delimiter characters for the
2975 * Return value: %TRUE if we moved and the new location is not the end iterator
2978 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
2980 gint current_offset;
2983 g_return_val_if_fail (iter != NULL, FALSE);
2985 current_offset = gtk_text_iter_get_line_offset (iter);
2986 /* FIXME assumption that line ends in a newline; broken */
2987 new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
2989 if (current_offset < new_offset)
2991 /* Move to end of this line. */
2992 gtk_text_iter_set_line_offset (iter, new_offset);
2997 /* Move to end of next line. */
2998 if (gtk_text_iter_forward_line (iter))
3000 /* We don't want to move past all
3003 if (!gtk_text_iter_ends_line (iter))
3004 gtk_text_iter_forward_to_line_end (iter);
3013 * gtk_text_iter_forward_to_tag_toggle:
3014 * @iter: a #GtkTextIter
3015 * @tag: a #GtkTextTag, or NULL
3017 * Moves forward to the next toggle (on or off) of the
3018 * #GtkTextTag @tag, or to the next toggle of any tag if
3019 * @tag is NULL. If no matching tag toggles are found,
3020 * returns FALSE, otherwise TRUE. Does not return toggles
3021 * located at @iter, only toggles after @iter. Sets @iter to
3022 * the location of the toggle, or to the end of the buffer
3023 * if no toggle is found.
3025 * Return value: whether we found a tag toggle after @iter
3028 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3031 GtkTextLine *next_line;
3032 GtkTextLine *current_line;
3033 GtkTextRealIter *real;
3035 g_return_val_if_fail (iter != NULL, FALSE);
3037 real = gtk_text_iter_make_real (iter);
3042 check_invariants (iter);
3044 current_line = real->line;
3045 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3048 while (_gtk_text_iter_forward_indexable_segment (iter))
3050 /* If we went forward to a line that couldn't contain a toggle
3051 for the tag, then skip forward to a line that could contain
3052 it. This potentially skips huge hunks of the tree, so we
3053 aren't a purely linear search. */
3054 if (real->line != current_line)
3056 if (next_line == NULL)
3058 /* End of search. Set to end of buffer. */
3059 _gtk_text_btree_get_last_iter (real->tree, iter);
3063 if (real->line != next_line)
3064 iter_set_from_byte_offset (real, next_line, 0);
3066 current_line = real->line;
3067 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3072 if (gtk_text_iter_toggles_tag (iter, tag))
3074 /* If there's a toggle here, it isn't indexable so
3075 any_segment can't be the indexable segment. */
3076 g_assert (real->any_segment != real->segment);
3081 /* Check end iterator for tags */
3082 if (gtk_text_iter_toggles_tag (iter, tag))
3084 /* If there's a toggle here, it isn't indexable so
3085 any_segment can't be the indexable segment. */
3086 g_assert (real->any_segment != real->segment);
3090 /* Reached end of buffer */
3095 * gtk_text_iter_backward_to_tag_toggle:
3096 * @iter: a #GtkTextIter
3097 * @tag: a #GtkTextTag, or NULL
3099 * Moves backward to the next toggle (on or off) of the
3100 * #GtkTextTag @tag, or to the next toggle of any tag if
3101 * @tag is NULL. If no matching tag toggles are found,
3102 * returns FALSE, otherwise TRUE. Does not return toggles
3103 * located at @iter, only toggles before @iter. Sets @iter
3104 * to the location of the toggle, or the start of the buffer
3105 * if no toggle is found.
3107 * Return value: whether we found a tag toggle before @iter
3110 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3113 GtkTextLine *prev_line;
3114 GtkTextLine *current_line;
3115 GtkTextRealIter *real;
3117 g_return_val_if_fail (iter != NULL, FALSE);
3119 real = gtk_text_iter_make_real (iter);
3124 check_invariants (iter);
3126 current_line = real->line;
3127 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3131 /* If we're at segment start, go to the previous segment;
3132 * if mid-segment, snap to start of current segment.
3134 if (is_segment_start (real))
3136 if (!_gtk_text_iter_backward_indexable_segment (iter))
3141 ensure_char_offsets (real);
3143 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3149 /* If we went backward to a line that couldn't contain a toggle
3150 * for the tag, then skip backward further to a line that
3151 * could contain it. This potentially skips huge hunks of the
3152 * tree, so we aren't a purely linear search.
3154 if (real->line != current_line)
3156 if (prev_line == NULL)
3158 /* End of search. Set to start of buffer. */
3159 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3163 if (real->line != prev_line)
3165 /* Set to last segment in prev_line (could do this
3168 iter_set_from_byte_offset (real, prev_line, 0);
3170 while (!at_last_indexable_segment (real))
3171 _gtk_text_iter_forward_indexable_segment (iter);
3174 current_line = real->line;
3175 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3180 if (gtk_text_iter_toggles_tag (iter, tag))
3182 /* If there's a toggle here, it isn't indexable so
3183 * any_segment can't be the indexable segment.
3185 g_assert (real->any_segment != real->segment);
3189 while (_gtk_text_iter_backward_indexable_segment (iter));
3191 /* Reached front of buffer */
3196 matches_pred (GtkTextIter *iter,
3197 GtkTextCharPredicate pred,
3202 ch = gtk_text_iter_get_char (iter);
3204 return (*pred) (ch, user_data);
3208 * gtk_text_iter_forward_find_char:
3209 * @iter: a #GtkTextIter
3210 * @pred: a function to be called on each character
3211 * @user_data: user data for @pred
3212 * @limit: search limit, or %NULL for none
3214 * Advances @iter, calling @pred on each character. If
3215 * @pred returns %TRUE, returns %TRUE and stops scanning.
3216 * If @pred never returns %TRUE, @iter is set to @limit if
3217 * @limit is non-%NULL, otherwise to the end iterator.
3219 * Return value: whether a match was found
3222 gtk_text_iter_forward_find_char (GtkTextIter *iter,
3223 GtkTextCharPredicate pred,
3225 const GtkTextIter *limit)
3227 g_return_val_if_fail (iter != NULL, FALSE);
3228 g_return_val_if_fail (pred != NULL, FALSE);
3231 gtk_text_iter_compare (iter, limit) >= 0)
3234 while ((limit == NULL ||
3235 !gtk_text_iter_equal (limit, iter)) &&
3236 gtk_text_iter_forward_char (iter))
3238 if (matches_pred (iter, pred, user_data))
3246 gtk_text_iter_backward_find_char (GtkTextIter *iter,
3247 GtkTextCharPredicate pred,
3249 const GtkTextIter *limit)
3251 g_return_val_if_fail (iter != NULL, FALSE);
3252 g_return_val_if_fail (pred != NULL, FALSE);
3255 gtk_text_iter_compare (iter, limit) <= 0)
3258 while ((limit == NULL ||
3259 !gtk_text_iter_equal (limit, iter)) &&
3260 gtk_text_iter_backward_char (iter))
3262 if (matches_pred (iter, pred, user_data))
3270 forward_chars_with_skipping (GtkTextIter *iter,
3272 gboolean skip_invisible,
3273 gboolean skip_nontext)
3278 g_return_if_fail (count >= 0);
3284 gboolean ignored = FALSE;
3287 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
3292 _gtk_text_btree_char_is_invisible (iter))
3295 gtk_text_iter_forward_char (iter);
3303 lines_match (const GtkTextIter *start,
3304 const gchar **lines,
3305 gboolean visible_only,
3307 GtkTextIter *match_start,
3308 GtkTextIter *match_end)
3315 if (*lines == NULL || **lines == '\0')
3318 *match_start = *start;
3321 *match_end = *start;
3326 gtk_text_iter_forward_line (&next);
3328 /* No more text in buffer, but *lines is nonempty */
3329 if (gtk_text_iter_equal (start, &next))
3337 line_text = gtk_text_iter_get_visible_slice (start, &next);
3339 line_text = gtk_text_iter_get_slice (start, &next);
3344 line_text = gtk_text_iter_get_visible_text (start, &next);
3346 line_text = gtk_text_iter_get_text (start, &next);
3349 if (match_start) /* if this is the first line we're matching */
3350 found = strstr (line_text, *lines);
3353 /* If it's not the first line, we have to match from the
3354 * start of the line.
3356 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
3368 /* Get offset to start of search string */
3369 offset = g_utf8_strlen (line_text, found - line_text);
3373 /* If match start needs to be returned, set it to the
3374 * start of the search string.
3378 *match_start = next;
3380 forward_chars_with_skipping (match_start, offset,
3381 visible_only, !slice);
3384 /* Go to end of search string */
3385 offset += g_utf8_strlen (*lines, -1);
3387 forward_chars_with_skipping (&next, offset,
3388 visible_only, !slice);
3397 /* pass NULL for match_start, since we don't need to find the
3400 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
3403 /* strsplit () that retains the delimiter as part of the string. */
3405 strbreakup (const char *string,
3406 const char *delimiter,
3409 GSList *string_list = NULL, *slist;
3410 gchar **str_array, *s;
3413 g_return_val_if_fail (string != NULL, NULL);
3414 g_return_val_if_fail (delimiter != NULL, NULL);
3417 max_tokens = G_MAXINT;
3419 s = strstr (string, delimiter);
3422 guint delimiter_len = strlen (delimiter);
3429 len = s - string + delimiter_len;
3430 new_string = g_new (gchar, len + 1);
3431 strncpy (new_string, string, len);
3432 new_string[len] = 0;
3433 string_list = g_slist_prepend (string_list, new_string);
3435 string = s + delimiter_len;
3436 s = strstr (string, delimiter);
3438 while (--max_tokens && s);
3443 string_list = g_slist_prepend (string_list, g_strdup (string));
3446 str_array = g_new (gchar*, n);
3450 str_array[i--] = NULL;
3451 for (slist = string_list; slist; slist = slist->next)
3452 str_array[i--] = slist->data;
3454 g_slist_free (string_list);
3460 * gtk_text_iter_forward_search:
3461 * @iter: start of search
3462 * @str: a search string
3463 * @visible_only: if %TRUE, search only visible text
3464 * @slice: if %TRUE, @str contains 0xFFFC when we want to match widgets, pixbufs
3465 * @match_start: return location for start of match, or %NULL
3466 * @match_end: return location for end of match, or %NULL
3467 * @limit: bound for the search, or %NULL for the end of the buffer
3471 * Return value: whether a match was found
3474 gtk_text_iter_forward_search (const GtkTextIter *iter,
3476 gboolean visible_only,
3478 GtkTextIter *match_start,
3479 GtkTextIter *match_end,
3480 const GtkTextIter *limit)
3482 gchar **lines = NULL;
3484 gboolean retval = FALSE;
3487 g_return_val_if_fail (iter != NULL, FALSE);
3488 g_return_val_if_fail (str != NULL, FALSE);
3491 gtk_text_iter_compare (iter, limit) >= 0)
3496 /* If we can move one char, return the empty string there */
3499 if (gtk_text_iter_forward_char (&match))
3502 gtk_text_iter_equal (&match, limit))
3506 *match_start = match;
3515 /* locate all lines */
3517 lines = strbreakup (str, "\n", -1);
3523 /* This loop has an inefficient worst-case, where
3524 * gtk_text_iter_get_text () is called repeatedly on
3530 gtk_text_iter_compare (&search, limit) >= 0)
3533 if (lines_match (&search, (const gchar**)lines,
3534 visible_only, slice, &match, &end))
3536 if (limit == NULL ||
3538 gtk_text_iter_compare (&end, limit) < 0))
3543 *match_start = match;
3552 while (gtk_text_iter_forward_line (&search));
3554 g_strfreev ((gchar**)lines);
3560 vectors_equal_ignoring_trailing (gchar **vec1,
3563 /* Ignores trailing chars in vec2's last line */
3572 if (strcmp (*i1, *i2) != 0)
3574 if (*(i2 + 1) == NULL) /* if this is the last line */
3576 gint len1 = strlen (*i1);
3577 gint len2 = strlen (*i2);
3580 strncmp (*i1, *i2, len1) == 0)
3582 /* We matched ignoring the trailing stuff in vec2 */
3607 typedef struct _LinesWindow LinesWindow;
3613 GtkTextIter first_line_start;
3614 GtkTextIter first_line_end;
3616 gboolean visible_only;
3620 lines_window_init (LinesWindow *win,
3621 const GtkTextIter *start)
3624 GtkTextIter line_start;
3625 GtkTextIter line_end;
3627 /* If we start on line 1, there are 2 lines to search (0 and 1), so
3630 if (gtk_text_iter_is_first (start) ||
3631 gtk_text_iter_get_line (start) + 1 < win->n_lines)
3633 /* Already at the end, or not enough lines to match */
3634 win->lines = g_new0 (gchar*, 1);
3639 line_start = *start;
3642 /* Move to start iter to start of line */
3643 gtk_text_iter_set_line_offset (&line_start, 0);
3645 if (gtk_text_iter_equal (&line_start, &line_end))
3647 /* we were already at the start; so go back one line */
3648 gtk_text_iter_backward_line (&line_start);
3651 win->first_line_start = line_start;
3652 win->first_line_end = line_end;
3654 win->lines = g_new0 (gchar*, win->n_lines + 1);
3656 i = win->n_lines - 1;
3663 if (win->visible_only)
3664 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
3666 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
3670 if (win->visible_only)
3671 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
3673 line_text = gtk_text_iter_get_text (&line_start, &line_end);
3676 win->lines[i] = line_text;
3678 line_end = line_start;
3679 gtk_text_iter_backward_line (&line_start);
3686 lines_window_back (LinesWindow *win)
3688 GtkTextIter new_start;
3691 new_start = win->first_line_start;
3693 if (!gtk_text_iter_backward_line (&new_start))
3697 win->first_line_start = new_start;
3698 win->first_line_end = new_start;
3700 gtk_text_iter_forward_line (&win->first_line_end);
3705 if (win->visible_only)
3706 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
3707 &win->first_line_end);
3709 line_text = gtk_text_iter_get_slice (&win->first_line_start,
3710 &win->first_line_end);
3714 if (win->visible_only)
3715 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
3716 &win->first_line_end);
3718 line_text = gtk_text_iter_get_text (&win->first_line_start,
3719 &win->first_line_end);
3722 /* Move lines to make room for first line. */
3723 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
3725 *win->lines = line_text;
3727 /* Free old last line and NULL-terminate */
3728 g_free (win->lines[win->n_lines]);
3729 win->lines[win->n_lines] = NULL;
3735 lines_window_free (LinesWindow *win)
3737 g_strfreev (win->lines);
3741 my_strrstr (const gchar *haystack,
3742 const gchar *needle)
3744 /* FIXME GLib should have a nice implementation in it, this
3748 gint haystack_len = strlen (haystack);
3749 gint needle_len = strlen (needle);
3750 const gchar *needle_end = needle + needle_len;
3751 const gchar *haystack_rend = haystack - 1;
3752 const gchar *needle_rend = needle - 1;
3755 p = haystack + haystack_len;
3756 while (p != haystack)
3758 const gchar *n = needle_end - 1;
3759 const gchar *s = p - 1;
3760 while (s != haystack_rend &&
3768 if (n == needle_rend)
3778 * gtk_text_iter_backward_search:
3779 * @iter: a #GtkTextIter where the search begins
3780 * @str: search string
3781 * @visible_only: if %TRUE search only visible text
3782 * @slice: if %TRUE the search string contains 0xFFFC to match pixbufs, widgets
3783 * @match_start: return location for start of match, or %NULL
3784 * @match_end: return location for end of match, or %NULL
3785 * @limit: location of last possible @match_start, or %NULL for start of buffer
3789 * Return value: whether a match was found
3792 gtk_text_iter_backward_search (const GtkTextIter *iter,
3794 gboolean visible_only,
3796 GtkTextIter *match_start,
3797 GtkTextIter *match_end,
3798 const GtkTextIter *limit)
3800 gchar **lines = NULL;
3804 gboolean retval = FALSE;
3806 g_return_val_if_fail (iter != NULL, FALSE);
3807 g_return_val_if_fail (str != NULL, FALSE);
3810 gtk_text_iter_compare (limit, iter) > 0)
3815 /* If we can move one char, return the empty string there */
3816 GtkTextIter match = *iter;
3818 if (limit && gtk_text_iter_equal (limit, &match))
3821 if (gtk_text_iter_backward_char (&match))
3824 *match_start = match;
3833 /* locate all lines */
3835 lines = strbreakup (str, "\n", -1);
3845 win.n_lines = n_lines;
3847 win.visible_only = visible_only;
3849 lines_window_init (&win, iter);
3851 if (*win.lines == NULL)
3856 gchar *first_line_match;
3859 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
3861 /* We're now before the search limit, abort. */
3865 /* If there are multiple lines, the first line will
3866 * end in '\n', so this will only match at the
3867 * end of the first line, which is correct.
3869 first_line_match = my_strrstr (*win.lines, *lines);
3871 if (first_line_match &&
3872 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
3877 GtkTextIter start_tmp;
3879 /* Offset to start of search string */
3880 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
3882 next = win.first_line_start;
3884 forward_chars_with_skipping (&start_tmp, offset,
3885 visible_only, !slice);
3888 gtk_text_iter_compare (limit, &start_tmp) > 0)
3889 goto out; /* match was bogus */
3892 *match_start = start_tmp;
3894 /* Go to end of search string */
3898 offset += g_utf8_strlen (*l, -1);
3902 forward_chars_with_skipping (&next, offset,
3903 visible_only, !slice);
3912 while (lines_window_back (&win));
3915 lines_window_free (&win);
3926 gtk_text_iter_equal (const GtkTextIter *lhs,
3927 const GtkTextIter *rhs)
3929 GtkTextRealIter *real_lhs;
3930 GtkTextRealIter *real_rhs;
3932 real_lhs = (GtkTextRealIter*)lhs;
3933 real_rhs = (GtkTextRealIter*)rhs;
3935 check_invariants (lhs);
3936 check_invariants (rhs);
3938 if (real_lhs->line != real_rhs->line)
3940 else if (real_lhs->line_byte_offset >= 0 &&
3941 real_rhs->line_byte_offset >= 0)
3942 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
3945 /* the ensure_char_offsets () calls do nothing if the char offsets
3946 are already up-to-date. */
3947 ensure_char_offsets (real_lhs);
3948 ensure_char_offsets (real_rhs);
3949 return real_lhs->line_char_offset == real_rhs->line_char_offset;
3954 gtk_text_iter_compare (const GtkTextIter *lhs, const GtkTextIter *rhs)
3956 GtkTextRealIter *real_lhs;
3957 GtkTextRealIter *real_rhs;
3959 real_lhs = gtk_text_iter_make_surreal (lhs);
3960 real_rhs = gtk_text_iter_make_surreal (rhs);
3962 check_invariants (lhs);
3963 check_invariants (rhs);
3965 if (real_lhs == NULL ||
3967 return -1; /* why not */
3969 if (real_lhs->line == real_rhs->line)
3971 gint left_index, right_index;
3973 if (real_lhs->line_byte_offset >= 0 &&
3974 real_rhs->line_byte_offset >= 0)
3976 left_index = real_lhs->line_byte_offset;
3977 right_index = real_rhs->line_byte_offset;
3981 /* the ensure_char_offsets () calls do nothing if
3982 the offsets are already up-to-date. */
3983 ensure_char_offsets (real_lhs);
3984 ensure_char_offsets (real_rhs);
3985 left_index = real_lhs->line_char_offset;
3986 right_index = real_rhs->line_char_offset;
3989 if (left_index < right_index)
3991 else if (left_index > right_index)
4000 line1 = gtk_text_iter_get_line (lhs);
4001 line2 = gtk_text_iter_get_line (rhs);
4004 else if (line1 > line2)
4012 gtk_text_iter_in_range (const GtkTextIter *iter,
4013 const GtkTextIter *start,
4014 const GtkTextIter *end)
4016 return gtk_text_iter_compare (iter, start) >= 0 &&
4017 gtk_text_iter_compare (iter, end) < 0;
4021 gtk_text_iter_reorder (GtkTextIter *first,
4022 GtkTextIter *second)
4024 g_return_if_fail (first != NULL);
4025 g_return_if_fail (second != NULL);
4027 if (gtk_text_iter_compare (first, second) > 0)
4038 * Init iterators from the BTree
4042 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4046 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4047 gint real_char_index;
4051 g_return_if_fail (iter != NULL);
4052 g_return_if_fail (tree != NULL);
4054 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4055 &line_start, &real_char_index);
4057 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4059 real->cached_char_index = real_char_index;
4061 check_invariants (iter);
4065 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4070 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4074 g_return_if_fail (iter != NULL);
4075 g_return_if_fail (tree != NULL);
4077 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4079 iter_init_from_char_offset (iter, tree, line, char_on_line);
4081 /* We might as well cache this, since we know it. */
4082 real->cached_line_number = real_line;
4084 check_invariants (iter);
4088 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4093 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4097 g_return_if_fail (iter != NULL);
4098 g_return_if_fail (tree != NULL);
4100 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4102 iter_init_from_byte_offset (iter, tree, line, byte_index);
4104 /* We might as well cache this, since we know it. */
4105 real->cached_line_number = real_line;
4107 if (real->segment->type == >k_text_char_type &&
4108 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
4109 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
4110 "character; this will crash the text buffer. "
4111 "Byte indexes must refer to the start of a character.",
4112 G_STRLOC, byte_index);
4114 check_invariants (iter);
4118 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
4123 g_return_if_fail (iter != NULL);
4124 g_return_if_fail (tree != NULL);
4125 g_return_if_fail (line != NULL);
4127 iter_init_from_byte_offset (iter, tree, line, byte_offset);
4129 check_invariants (iter);
4133 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
4139 g_return_val_if_fail (iter != NULL, FALSE);
4140 g_return_val_if_fail (tree != NULL, FALSE);
4142 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
4146 /* Set iter to last in tree */
4147 _gtk_text_btree_get_last_iter (tree, iter);
4148 check_invariants (iter);
4153 iter_init_from_byte_offset (iter, tree, line, 0);
4154 gtk_text_iter_forward_to_tag_toggle (iter, tag);
4155 check_invariants (iter);
4161 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
4167 g_return_val_if_fail (iter != NULL, FALSE);
4168 g_return_val_if_fail (tree != NULL, FALSE);
4170 line = _gtk_text_btree_last_could_contain_tag (tree, tag);
4174 /* Set iter to first in tree */
4175 _gtk_text_btree_get_iter_at_line_char (tree, iter, 0, 0);
4176 check_invariants (iter);
4181 iter_init_from_byte_offset (iter, tree, line, -1);
4182 gtk_text_iter_backward_to_tag_toggle (iter, tag);
4183 check_invariants (iter);
4189 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
4191 const gchar *mark_name)
4195 g_return_val_if_fail (iter != NULL, FALSE);
4196 g_return_val_if_fail (tree != NULL, FALSE);
4198 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
4204 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
4205 check_invariants (iter);
4211 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
4215 GtkTextLineSegment *seg;
4217 g_return_if_fail (iter != NULL);
4218 g_return_if_fail (tree != NULL);
4219 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
4221 seg = mark->segment;
4223 iter_init_from_segment (iter, tree,
4224 seg->body.mark.line, seg);
4225 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
4226 check_invariants (iter);
4230 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
4232 GtkTextChildAnchor *anchor)
4234 GtkTextLineSegment *seg;
4236 g_return_if_fail (iter != NULL);
4237 g_return_if_fail (tree != NULL);
4238 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
4240 seg = anchor->segment;
4242 iter_init_from_segment (iter, tree,
4243 seg->body.child.line, seg);
4244 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
4245 check_invariants (iter);
4249 _gtk_text_btree_get_last_iter (GtkTextBTree *tree,
4252 g_return_if_fail (iter != NULL);
4253 g_return_if_fail (tree != NULL);
4255 _gtk_text_btree_get_iter_at_char (tree,
4257 _gtk_text_btree_char_count (tree));
4258 check_invariants (iter);
4262 gtk_text_iter_spew (const GtkTextIter *iter, const gchar *desc)
4264 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4266 g_return_if_fail (iter != NULL);
4268 if (real->chars_changed_stamp != _gtk_text_btree_get_chars_changed_stamp (real->tree))
4269 g_print (" %20s: <invalidated iterator>\n", desc);
4272 check_invariants (iter);
4273 g_print (" %20s: line %d / char %d / line char %d / line byte %d\n",
4275 gtk_text_iter_get_line (iter),
4276 gtk_text_iter_get_offset (iter),
4277 gtk_text_iter_get_line_offset (iter),
4278 gtk_text_iter_get_line_index (iter));
4279 check_invariants (iter);
4284 _gtk_text_iter_check (const GtkTextIter *iter)
4286 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
4287 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
4288 GtkTextLineSegment *byte_segment = NULL;
4289 GtkTextLineSegment *byte_any_segment = NULL;
4290 GtkTextLineSegment *char_segment = NULL;
4291 GtkTextLineSegment *char_any_segment = NULL;
4292 gboolean segments_updated;
4294 /* This function checks our class invariants for the Iter class. */
4296 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
4298 if (real->chars_changed_stamp !=
4299 _gtk_text_btree_get_chars_changed_stamp (real->tree))
4300 g_error ("iterator check failed: invalid iterator");
4302 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
4303 g_error ("iterator check failed: both char and byte offsets are invalid");
4305 segments_updated = (real->segments_changed_stamp ==
4306 _gtk_text_btree_get_segments_changed_stamp (real->tree));
4309 printf ("checking iter, segments %s updated, byte %d char %d\n",
4310 segments_updated ? "are" : "aren't",
4311 real->line_byte_offset,
4312 real->line_char_offset);
4315 if (segments_updated)
4317 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
4318 g_error ("iterator check failed: both char and byte segment offsets are invalid");
4320 if (real->segment->char_count == 0)
4321 g_error ("iterator check failed: segment is not indexable.");
4323 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
4324 g_error ("segment char offset is not properly up-to-date");
4326 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
4327 g_error ("segment byte offset is not properly up-to-date");
4329 if (real->segment_byte_offset >= 0 &&
4330 real->segment_byte_offset >= real->segment->byte_count)
4331 g_error ("segment byte offset is too large.");
4333 if (real->segment_char_offset >= 0 &&
4334 real->segment_char_offset >= real->segment->char_count)
4335 g_error ("segment char offset is too large.");
4338 if (real->line_byte_offset >= 0)
4340 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
4341 &byte_segment, &byte_any_segment,
4342 &seg_byte_offset, &line_byte_offset);
4344 if (line_byte_offset != real->line_byte_offset)
4345 g_error ("wrong byte offset was stored in iterator");
4347 if (segments_updated)
4349 if (real->segment != byte_segment)
4350 g_error ("wrong segment was stored in iterator");
4352 if (real->any_segment != byte_any_segment)
4353 g_error ("wrong any_segment was stored in iterator");
4355 if (seg_byte_offset != real->segment_byte_offset)
4356 g_error ("wrong segment byte offset was stored in iterator");
4358 if (byte_segment->type == >k_text_char_type)
4361 p = byte_segment->body.chars + seg_byte_offset;
4363 if (!gtk_text_byte_begins_utf8_char (p))
4364 g_error ("broken iterator byte index pointed into the middle of a character");
4369 if (real->line_char_offset >= 0)
4371 _gtk_text_line_char_locate (real->line, real->line_char_offset,
4372 &char_segment, &char_any_segment,
4373 &seg_char_offset, &line_char_offset);
4375 if (line_char_offset != real->line_char_offset)
4376 g_error ("wrong char offset was stored in iterator");
4378 if (segments_updated)
4380 if (real->segment != char_segment)
4381 g_error ("wrong segment was stored in iterator");
4383 if (real->any_segment != char_any_segment)
4384 g_error ("wrong any_segment was stored in iterator");
4386 if (seg_char_offset != real->segment_char_offset)
4387 g_error ("wrong segment char offset was stored in iterator");
4389 if (char_segment->type == >k_text_char_type)
4392 p = g_utf8_offset_to_pointer (char_segment->body.chars,
4395 /* hmm, not likely to happen eh */
4396 if (!gtk_text_byte_begins_utf8_char (p))
4397 g_error ("broken iterator char offset pointed into the middle of a character");
4402 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
4404 if (byte_segment != char_segment)
4405 g_error ("char and byte offsets did not point to the same segment");
4407 if (byte_any_segment != char_any_segment)
4408 g_error ("char and byte offsets did not point to the same any segment");
4410 /* Make sure the segment offsets are equivalent, if it's a char
4412 if (char_segment->type == >k_text_char_type)
4414 gint byte_offset = 0;
4415 gint char_offset = 0;
4416 while (char_offset < seg_char_offset)
4418 const char * start = char_segment->body.chars + byte_offset;
4419 byte_offset += g_utf8_next_char (start) - start;
4423 if (byte_offset != seg_byte_offset)
4424 g_error ("byte offset did not correspond to char offset");
4427 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
4429 if (char_offset != seg_char_offset)
4430 g_error ("char offset did not correspond to byte offset");
4432 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
4433 g_error ("byte index for iterator does not index the start of a character");
4437 if (real->cached_line_number >= 0)
4441 should_be = _gtk_text_line_get_number (real->line);
4442 if (real->cached_line_number != should_be)
4443 g_error ("wrong line number was cached");
4446 if (real->cached_char_index >= 0)
4448 if (real->line_char_offset >= 0) /* only way we can check it
4449 efficiently, not a real
4454 char_index = _gtk_text_line_char_index (real->line);
4455 char_index += real->line_char_offset;
4457 if (real->cached_char_index != char_index)
4458 g_error ("wrong char index was cached");