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,
2453 find_word_end_func (const PangoLogAttr *attrs,
2458 gboolean already_moved_initially)
2460 if (!already_moved_initially)
2463 /* Find end of next word */
2464 while (offset < min_offset + len &&
2465 !attrs[offset].is_word_end)
2468 *found_offset = offset;
2470 return offset < min_offset + len;
2474 is_word_end_func (const PangoLogAttr *attrs,
2479 return attrs[offset].is_word_end;
2483 find_word_start_func (const PangoLogAttr *attrs,
2488 gboolean already_moved_initially)
2490 if (!already_moved_initially)
2493 /* Find start of prev word */
2494 while (offset >= min_offset &&
2495 !attrs[offset].is_word_start)
2498 *found_offset = offset;
2500 return offset >= min_offset;
2504 is_word_start_func (const PangoLogAttr *attrs,
2509 return attrs[offset].is_word_start;
2513 inside_word_func (const PangoLogAttr *attrs,
2518 /* Find next word start or end */
2519 while (offset >= min_offset &&
2520 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2523 return attrs[offset].is_word_start;
2526 /* Sentence funcs */
2529 find_sentence_end_func (const PangoLogAttr *attrs,
2534 gboolean already_moved_initially)
2536 if (!already_moved_initially)
2539 /* Find end of next sentence */
2540 while (offset < min_offset + len &&
2541 !attrs[offset].is_sentence_end)
2544 *found_offset = offset;
2546 return offset < min_offset + len;
2550 is_sentence_end_func (const PangoLogAttr *attrs,
2555 return attrs[offset].is_sentence_end;
2559 find_sentence_start_func (const PangoLogAttr *attrs,
2564 gboolean already_moved_initially)
2566 if (!already_moved_initially)
2569 /* Find start of prev sentence */
2570 while (offset >= min_offset &&
2571 !attrs[offset].is_sentence_start)
2574 *found_offset = offset;
2576 return offset >= min_offset;
2580 is_sentence_start_func (const PangoLogAttr *attrs,
2585 return attrs[offset].is_sentence_start;
2589 inside_sentence_func (const PangoLogAttr *attrs,
2594 /* Find next sentence start or end */
2595 while (offset >= min_offset &&
2596 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2599 return attrs[offset].is_sentence_start;
2603 test_log_attrs (const GtkTextIter *iter,
2604 TestLogAttrFunc func)
2607 const PangoLogAttr *attrs;
2609 gboolean result = FALSE;
2611 g_return_val_if_fail (iter != NULL, FALSE);
2613 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2616 offset = gtk_text_iter_get_line_offset (iter);
2618 g_assert (char_len > 0);
2620 if (offset < char_len)
2621 result = (* func) (attrs, offset, 0, char_len);
2627 find_line_log_attrs (const GtkTextIter *iter,
2628 FindLogAttrFunc func,
2630 gboolean already_moved_initially)
2633 const PangoLogAttr *attrs;
2635 gboolean result = FALSE;
2637 g_return_val_if_fail (iter != NULL, FALSE);
2639 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2642 offset = gtk_text_iter_get_line_offset (iter);
2644 g_assert (char_len > 0);
2646 if (offset < char_len)
2647 result = (* func) (attrs, offset, 0, char_len, found_offset,
2648 already_moved_initially);
2653 /* FIXME this function is very, very gratuitously slow */
2655 find_by_log_attrs (GtkTextIter *iter,
2656 FindLogAttrFunc func,
2658 gboolean already_moved_initially)
2662 gboolean found = FALSE;
2664 g_return_val_if_fail (iter != NULL, FALSE);
2668 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2674 if (gtk_text_iter_forward_line (iter))
2675 return find_by_log_attrs (iter, func, forward,
2682 /* go to end of previous line */
2683 gtk_text_iter_set_line_offset (iter, 0);
2685 if (gtk_text_iter_backward_char (iter))
2686 return find_by_log_attrs (iter, func, forward,
2694 gtk_text_iter_set_line_offset (iter, offset);
2697 !gtk_text_iter_equal (iter, &orig) &&
2698 !gtk_text_iter_is_last (iter);
2703 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2705 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2709 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2711 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2714 /* FIXME a loop around a truly slow function means
2715 * a truly spectacularly slow function.
2718 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
2721 g_return_val_if_fail (iter != NULL, FALSE);
2727 return gtk_text_iter_backward_word_starts (iter, -count);
2729 if (!gtk_text_iter_forward_word_end (iter))
2735 if (!gtk_text_iter_forward_word_end (iter))
2743 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
2746 g_return_val_if_fail (iter != NULL, FALSE);
2749 return gtk_text_iter_forward_word_ends (iter, -count);
2751 if (!gtk_text_iter_backward_word_start (iter))
2757 if (!gtk_text_iter_backward_word_start (iter))
2765 gtk_text_iter_starts_word (const GtkTextIter *iter)
2767 return test_log_attrs (iter, is_word_start_func);
2771 gtk_text_iter_ends_word (const GtkTextIter *iter)
2773 return test_log_attrs (iter, is_word_end_func);
2777 gtk_text_iter_inside_word (const GtkTextIter *iter)
2779 return test_log_attrs (iter, inside_word_func);
2783 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
2785 return test_log_attrs (iter, is_sentence_start_func);
2789 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
2791 return test_log_attrs (iter, is_sentence_end_func);
2795 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
2797 return test_log_attrs (iter, inside_sentence_func);
2801 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
2803 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
2807 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
2809 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
2812 /* FIXME a loop around a truly slow function means
2813 * a truly spectacularly slow function.
2816 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
2819 g_return_val_if_fail (iter != NULL, FALSE);
2825 return gtk_text_iter_backward_sentence_starts (iter, -count);
2827 if (!gtk_text_iter_forward_sentence_end (iter))
2833 if (!gtk_text_iter_forward_sentence_end (iter))
2841 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
2844 g_return_val_if_fail (iter != NULL, FALSE);
2847 return gtk_text_iter_forward_sentence_ends (iter, -count);
2849 if (!gtk_text_iter_backward_sentence_start (iter))
2855 if (!gtk_text_iter_backward_sentence_start (iter))
2863 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
2868 gboolean already_moved_initially)
2870 if (!already_moved_initially)
2873 while (offset < (min_offset + len) &&
2874 !attrs[offset].is_cursor_position)
2877 *found_offset = offset;
2879 return offset < (min_offset + len);
2883 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
2888 gboolean already_moved_initially)
2890 if (!already_moved_initially)
2893 while (offset > min_offset &&
2894 !attrs[offset].is_cursor_position)
2897 *found_offset = offset;
2899 return offset >= min_offset;
2903 is_cursor_pos_func (const PangoLogAttr *attrs,
2908 return attrs[offset].is_cursor_position;
2912 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
2914 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
2918 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
2920 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
2924 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
2927 g_return_val_if_fail (iter != NULL, FALSE);
2933 return gtk_text_iter_backward_cursor_positions (iter, -count);
2935 if (!gtk_text_iter_forward_cursor_position (iter))
2941 if (!gtk_text_iter_forward_cursor_position (iter))
2949 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
2952 g_return_val_if_fail (iter != NULL, FALSE);
2958 return gtk_text_iter_forward_cursor_positions (iter, -count);
2960 if (!gtk_text_iter_backward_cursor_position (iter))
2966 if (!gtk_text_iter_backward_cursor_position (iter))
2974 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
2976 return test_log_attrs (iter, is_cursor_pos_func);
2980 gtk_text_iter_set_line_offset (GtkTextIter *iter,
2983 GtkTextRealIter *real;
2986 g_return_if_fail (iter != NULL);
2988 real = gtk_text_iter_make_surreal (iter);
2993 check_invariants (iter);
2995 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
2997 g_return_if_fail (char_on_line <= chars_in_line);
2999 if (char_on_line < chars_in_line)
3000 iter_set_from_char_offset (real, real->line, char_on_line);
3002 gtk_text_iter_forward_line (iter); /* set to start of next line */
3004 check_invariants (iter);
3008 gtk_text_iter_set_line_index (GtkTextIter *iter,
3011 GtkTextRealIter *real;
3014 g_return_if_fail (iter != NULL);
3016 real = gtk_text_iter_make_surreal (iter);
3021 check_invariants (iter);
3023 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3025 g_return_if_fail (byte_on_line <= bytes_in_line);
3027 if (byte_on_line < bytes_in_line)
3028 iter_set_from_byte_offset (real, real->line, byte_on_line);
3030 gtk_text_iter_forward_line (iter);
3032 if (real->segment->type == >k_text_char_type &&
3033 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3034 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3035 "character; this will crash the text buffer. "
3036 "Byte indexes must refer to the start of a character.",
3037 G_STRLOC, byte_on_line);
3039 check_invariants (iter);
3043 gtk_text_iter_set_line (GtkTextIter *iter,
3048 GtkTextRealIter *real;
3050 g_return_if_fail (iter != NULL);
3052 real = gtk_text_iter_make_surreal (iter);
3057 check_invariants (iter);
3059 line = _gtk_text_btree_get_line (real->tree, line_number, &real_line);
3061 iter_set_from_char_offset (real, line, 0);
3063 /* We might as well cache this, since we know it. */
3064 real->cached_line_number = real_line;
3066 check_invariants (iter);
3070 gtk_text_iter_set_offset (GtkTextIter *iter, gint char_index)
3073 GtkTextRealIter *real;
3075 gint real_char_index;
3077 g_return_if_fail (iter != NULL);
3079 real = gtk_text_iter_make_surreal (iter);
3084 check_invariants (iter);
3086 if (real->cached_char_index >= 0 &&
3087 real->cached_char_index == char_index)
3090 line = _gtk_text_btree_get_line_at_char (real->tree,
3095 iter_set_from_char_offset (real, line, real_char_index - line_start);
3097 /* Go ahead and cache this since we have it. */
3098 real->cached_char_index = real_char_index;
3100 check_invariants (iter);
3104 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3106 GtkTextBuffer *buffer;
3107 GtkTextRealIter *real;
3109 g_return_if_fail (iter != NULL);
3111 real = gtk_text_iter_make_surreal (iter);
3116 buffer = _gtk_text_btree_get_buffer (real->tree);
3118 gtk_text_buffer_get_last_iter (buffer, iter);
3122 * gtk_text_iter_forward_to_line_end:
3123 * @iter: a #GtkTextIter
3125 * Moves the iterator to point to the paragraph delimiter characters,
3126 * which will be either a newline, a carriage return, a carriage
3127 * return/newline in sequence, or the Unicode paragraph separator
3128 * character. If the iterator is already at the paragraph delimiter
3129 * characters, moves to the paragraph delimiter characters for the
3132 * Return value: %TRUE if we moved and the new location is not the end iterator
3135 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3137 gint current_offset;
3140 g_return_val_if_fail (iter != NULL, FALSE);
3142 current_offset = gtk_text_iter_get_line_offset (iter);
3143 /* FIXME assumption that line ends in a newline; broken */
3144 new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
3146 if (current_offset < new_offset)
3148 /* Move to end of this line. */
3149 gtk_text_iter_set_line_offset (iter, new_offset);
3154 /* Move to end of next line. */
3155 if (gtk_text_iter_forward_line (iter))
3157 /* We don't want to move past all
3160 if (!gtk_text_iter_ends_line (iter))
3161 gtk_text_iter_forward_to_line_end (iter);
3170 * gtk_text_iter_forward_to_tag_toggle:
3171 * @iter: a #GtkTextIter
3172 * @tag: a #GtkTextTag, or NULL
3174 * Moves forward to the next toggle (on or off) of the
3175 * #GtkTextTag @tag, or to the next toggle of any tag if
3176 * @tag is NULL. If no matching tag toggles are found,
3177 * returns FALSE, otherwise TRUE. Does not return toggles
3178 * located at @iter, only toggles after @iter. Sets @iter to
3179 * the location of the toggle, or to the end of the buffer
3180 * if no toggle is found.
3182 * Return value: whether we found a tag toggle after @iter
3185 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3188 GtkTextLine *next_line;
3189 GtkTextLine *current_line;
3190 GtkTextRealIter *real;
3192 g_return_val_if_fail (iter != NULL, FALSE);
3194 real = gtk_text_iter_make_real (iter);
3199 check_invariants (iter);
3201 current_line = real->line;
3202 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3205 while (_gtk_text_iter_forward_indexable_segment (iter))
3207 /* If we went forward to a line that couldn't contain a toggle
3208 for the tag, then skip forward to a line that could contain
3209 it. This potentially skips huge hunks of the tree, so we
3210 aren't a purely linear search. */
3211 if (real->line != current_line)
3213 if (next_line == NULL)
3215 /* End of search. Set to end of buffer. */
3216 _gtk_text_btree_get_last_iter (real->tree, iter);
3220 if (real->line != next_line)
3221 iter_set_from_byte_offset (real, next_line, 0);
3223 current_line = real->line;
3224 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3229 if (gtk_text_iter_toggles_tag (iter, tag))
3231 /* If there's a toggle here, it isn't indexable so
3232 any_segment can't be the indexable segment. */
3233 g_assert (real->any_segment != real->segment);
3238 /* Check end iterator for tags */
3239 if (gtk_text_iter_toggles_tag (iter, tag))
3241 /* If there's a toggle here, it isn't indexable so
3242 any_segment can't be the indexable segment. */
3243 g_assert (real->any_segment != real->segment);
3247 /* Reached end of buffer */
3252 * gtk_text_iter_backward_to_tag_toggle:
3253 * @iter: a #GtkTextIter
3254 * @tag: a #GtkTextTag, or NULL
3256 * Moves backward to the next toggle (on or off) of the
3257 * #GtkTextTag @tag, or to the next toggle of any tag if
3258 * @tag is NULL. If no matching tag toggles are found,
3259 * returns FALSE, otherwise TRUE. Does not return toggles
3260 * located at @iter, only toggles before @iter. Sets @iter
3261 * to the location of the toggle, or the start of the buffer
3262 * if no toggle is found.
3264 * Return value: whether we found a tag toggle before @iter
3267 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3270 GtkTextLine *prev_line;
3271 GtkTextLine *current_line;
3272 GtkTextRealIter *real;
3274 g_return_val_if_fail (iter != NULL, FALSE);
3276 real = gtk_text_iter_make_real (iter);
3281 check_invariants (iter);
3283 current_line = real->line;
3284 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3288 /* If we're at segment start, go to the previous segment;
3289 * if mid-segment, snap to start of current segment.
3291 if (is_segment_start (real))
3293 if (!_gtk_text_iter_backward_indexable_segment (iter))
3298 ensure_char_offsets (real);
3300 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3306 /* If we went backward to a line that couldn't contain a toggle
3307 * for the tag, then skip backward further to a line that
3308 * could contain it. This potentially skips huge hunks of the
3309 * tree, so we aren't a purely linear search.
3311 if (real->line != current_line)
3313 if (prev_line == NULL)
3315 /* End of search. Set to start of buffer. */
3316 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3320 if (real->line != prev_line)
3322 /* Set to last segment in prev_line (could do this
3325 iter_set_from_byte_offset (real, prev_line, 0);
3327 while (!at_last_indexable_segment (real))
3328 _gtk_text_iter_forward_indexable_segment (iter);
3331 current_line = real->line;
3332 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3337 if (gtk_text_iter_toggles_tag (iter, tag))
3339 /* If there's a toggle here, it isn't indexable so
3340 * any_segment can't be the indexable segment.
3342 g_assert (real->any_segment != real->segment);
3346 while (_gtk_text_iter_backward_indexable_segment (iter));
3348 /* Reached front of buffer */
3353 matches_pred (GtkTextIter *iter,
3354 GtkTextCharPredicate pred,
3359 ch = gtk_text_iter_get_char (iter);
3361 return (*pred) (ch, user_data);
3365 * gtk_text_iter_forward_find_char:
3366 * @iter: a #GtkTextIter
3367 * @pred: a function to be called on each character
3368 * @user_data: user data for @pred
3369 * @limit: search limit, or %NULL for none
3371 * Advances @iter, calling @pred on each character. If
3372 * @pred returns %TRUE, returns %TRUE and stops scanning.
3373 * If @pred never returns %TRUE, @iter is set to @limit if
3374 * @limit is non-%NULL, otherwise to the end iterator.
3376 * Return value: whether a match was found
3379 gtk_text_iter_forward_find_char (GtkTextIter *iter,
3380 GtkTextCharPredicate pred,
3382 const GtkTextIter *limit)
3384 g_return_val_if_fail (iter != NULL, FALSE);
3385 g_return_val_if_fail (pred != NULL, FALSE);
3388 gtk_text_iter_compare (iter, limit) >= 0)
3391 while ((limit == NULL ||
3392 !gtk_text_iter_equal (limit, iter)) &&
3393 gtk_text_iter_forward_char (iter))
3395 if (matches_pred (iter, pred, user_data))
3403 gtk_text_iter_backward_find_char (GtkTextIter *iter,
3404 GtkTextCharPredicate pred,
3406 const GtkTextIter *limit)
3408 g_return_val_if_fail (iter != NULL, FALSE);
3409 g_return_val_if_fail (pred != NULL, FALSE);
3412 gtk_text_iter_compare (iter, limit) <= 0)
3415 while ((limit == NULL ||
3416 !gtk_text_iter_equal (limit, iter)) &&
3417 gtk_text_iter_backward_char (iter))
3419 if (matches_pred (iter, pred, user_data))
3427 forward_chars_with_skipping (GtkTextIter *iter,
3429 gboolean skip_invisible,
3430 gboolean skip_nontext)
3435 g_return_if_fail (count >= 0);
3441 gboolean ignored = FALSE;
3444 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
3449 _gtk_text_btree_char_is_invisible (iter))
3452 gtk_text_iter_forward_char (iter);
3460 lines_match (const GtkTextIter *start,
3461 const gchar **lines,
3462 gboolean visible_only,
3464 GtkTextIter *match_start,
3465 GtkTextIter *match_end)
3472 if (*lines == NULL || **lines == '\0')
3475 *match_start = *start;
3478 *match_end = *start;
3483 gtk_text_iter_forward_line (&next);
3485 /* No more text in buffer, but *lines is nonempty */
3486 if (gtk_text_iter_equal (start, &next))
3494 line_text = gtk_text_iter_get_visible_slice (start, &next);
3496 line_text = gtk_text_iter_get_slice (start, &next);
3501 line_text = gtk_text_iter_get_visible_text (start, &next);
3503 line_text = gtk_text_iter_get_text (start, &next);
3506 if (match_start) /* if this is the first line we're matching */
3507 found = strstr (line_text, *lines);
3510 /* If it's not the first line, we have to match from the
3511 * start of the line.
3513 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
3525 /* Get offset to start of search string */
3526 offset = g_utf8_strlen (line_text, found - line_text);
3530 /* If match start needs to be returned, set it to the
3531 * start of the search string.
3535 *match_start = next;
3537 forward_chars_with_skipping (match_start, offset,
3538 visible_only, !slice);
3541 /* Go to end of search string */
3542 offset += g_utf8_strlen (*lines, -1);
3544 forward_chars_with_skipping (&next, offset,
3545 visible_only, !slice);
3554 /* pass NULL for match_start, since we don't need to find the
3557 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
3560 /* strsplit () that retains the delimiter as part of the string. */
3562 strbreakup (const char *string,
3563 const char *delimiter,
3566 GSList *string_list = NULL, *slist;
3567 gchar **str_array, *s;
3570 g_return_val_if_fail (string != NULL, NULL);
3571 g_return_val_if_fail (delimiter != NULL, NULL);
3574 max_tokens = G_MAXINT;
3576 s = strstr (string, delimiter);
3579 guint delimiter_len = strlen (delimiter);
3586 len = s - string + delimiter_len;
3587 new_string = g_new (gchar, len + 1);
3588 strncpy (new_string, string, len);
3589 new_string[len] = 0;
3590 string_list = g_slist_prepend (string_list, new_string);
3592 string = s + delimiter_len;
3593 s = strstr (string, delimiter);
3595 while (--max_tokens && s);
3600 string_list = g_slist_prepend (string_list, g_strdup (string));
3603 str_array = g_new (gchar*, n);
3607 str_array[i--] = NULL;
3608 for (slist = string_list; slist; slist = slist->next)
3609 str_array[i--] = slist->data;
3611 g_slist_free (string_list);
3617 * gtk_text_iter_forward_search:
3618 * @iter: start of search
3619 * @str: a search string
3620 * @visible_only: if %TRUE, search only visible text
3621 * @slice: if %TRUE, @str contains 0xFFFC when we want to match widgets, pixbufs
3622 * @match_start: return location for start of match, or %NULL
3623 * @match_end: return location for end of match, or %NULL
3624 * @limit: bound for the search, or %NULL for the end of the buffer
3628 * Return value: whether a match was found
3631 gtk_text_iter_forward_search (const GtkTextIter *iter,
3633 gboolean visible_only,
3635 GtkTextIter *match_start,
3636 GtkTextIter *match_end,
3637 const GtkTextIter *limit)
3639 gchar **lines = NULL;
3641 gboolean retval = FALSE;
3644 g_return_val_if_fail (iter != NULL, FALSE);
3645 g_return_val_if_fail (str != NULL, FALSE);
3648 gtk_text_iter_compare (iter, limit) >= 0)
3653 /* If we can move one char, return the empty string there */
3656 if (gtk_text_iter_forward_char (&match))
3659 gtk_text_iter_equal (&match, limit))
3663 *match_start = match;
3672 /* locate all lines */
3674 lines = strbreakup (str, "\n", -1);
3680 /* This loop has an inefficient worst-case, where
3681 * gtk_text_iter_get_text () is called repeatedly on
3687 gtk_text_iter_compare (&search, limit) >= 0)
3690 if (lines_match (&search, (const gchar**)lines,
3691 visible_only, slice, &match, &end))
3693 if (limit == NULL ||
3695 gtk_text_iter_compare (&end, limit) < 0))
3700 *match_start = match;
3709 while (gtk_text_iter_forward_line (&search));
3711 g_strfreev ((gchar**)lines);
3717 vectors_equal_ignoring_trailing (gchar **vec1,
3720 /* Ignores trailing chars in vec2's last line */
3729 if (strcmp (*i1, *i2) != 0)
3731 if (*(i2 + 1) == NULL) /* if this is the last line */
3733 gint len1 = strlen (*i1);
3734 gint len2 = strlen (*i2);
3737 strncmp (*i1, *i2, len1) == 0)
3739 /* We matched ignoring the trailing stuff in vec2 */
3764 typedef struct _LinesWindow LinesWindow;
3770 GtkTextIter first_line_start;
3771 GtkTextIter first_line_end;
3773 gboolean visible_only;
3777 lines_window_init (LinesWindow *win,
3778 const GtkTextIter *start)
3781 GtkTextIter line_start;
3782 GtkTextIter line_end;
3784 /* If we start on line 1, there are 2 lines to search (0 and 1), so
3787 if (gtk_text_iter_is_first (start) ||
3788 gtk_text_iter_get_line (start) + 1 < win->n_lines)
3790 /* Already at the end, or not enough lines to match */
3791 win->lines = g_new0 (gchar*, 1);
3796 line_start = *start;
3799 /* Move to start iter to start of line */
3800 gtk_text_iter_set_line_offset (&line_start, 0);
3802 if (gtk_text_iter_equal (&line_start, &line_end))
3804 /* we were already at the start; so go back one line */
3805 gtk_text_iter_backward_line (&line_start);
3808 win->first_line_start = line_start;
3809 win->first_line_end = line_end;
3811 win->lines = g_new0 (gchar*, win->n_lines + 1);
3813 i = win->n_lines - 1;
3820 if (win->visible_only)
3821 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
3823 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
3827 if (win->visible_only)
3828 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
3830 line_text = gtk_text_iter_get_text (&line_start, &line_end);
3833 win->lines[i] = line_text;
3835 line_end = line_start;
3836 gtk_text_iter_backward_line (&line_start);
3843 lines_window_back (LinesWindow *win)
3845 GtkTextIter new_start;
3848 new_start = win->first_line_start;
3850 if (!gtk_text_iter_backward_line (&new_start))
3854 win->first_line_start = new_start;
3855 win->first_line_end = new_start;
3857 gtk_text_iter_forward_line (&win->first_line_end);
3862 if (win->visible_only)
3863 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
3864 &win->first_line_end);
3866 line_text = gtk_text_iter_get_slice (&win->first_line_start,
3867 &win->first_line_end);
3871 if (win->visible_only)
3872 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
3873 &win->first_line_end);
3875 line_text = gtk_text_iter_get_text (&win->first_line_start,
3876 &win->first_line_end);
3879 /* Move lines to make room for first line. */
3880 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
3882 *win->lines = line_text;
3884 /* Free old last line and NULL-terminate */
3885 g_free (win->lines[win->n_lines]);
3886 win->lines[win->n_lines] = NULL;
3892 lines_window_free (LinesWindow *win)
3894 g_strfreev (win->lines);
3898 my_strrstr (const gchar *haystack,
3899 const gchar *needle)
3901 /* FIXME GLib should have a nice implementation in it, this
3905 gint haystack_len = strlen (haystack);
3906 gint needle_len = strlen (needle);
3907 const gchar *needle_end = needle + needle_len;
3908 const gchar *haystack_rend = haystack - 1;
3909 const gchar *needle_rend = needle - 1;
3912 p = haystack + haystack_len;
3913 while (p != haystack)
3915 const gchar *n = needle_end - 1;
3916 const gchar *s = p - 1;
3917 while (s != haystack_rend &&
3925 if (n == needle_rend)
3935 * gtk_text_iter_backward_search:
3936 * @iter: a #GtkTextIter where the search begins
3937 * @str: search string
3938 * @visible_only: if %TRUE search only visible text
3939 * @slice: if %TRUE the search string contains 0xFFFC to match pixbufs, widgets
3940 * @match_start: return location for start of match, or %NULL
3941 * @match_end: return location for end of match, or %NULL
3942 * @limit: location of last possible @match_start, or %NULL for start of buffer
3946 * Return value: whether a match was found
3949 gtk_text_iter_backward_search (const GtkTextIter *iter,
3951 gboolean visible_only,
3953 GtkTextIter *match_start,
3954 GtkTextIter *match_end,
3955 const GtkTextIter *limit)
3957 gchar **lines = NULL;
3961 gboolean retval = FALSE;
3963 g_return_val_if_fail (iter != NULL, FALSE);
3964 g_return_val_if_fail (str != NULL, FALSE);
3967 gtk_text_iter_compare (limit, iter) > 0)
3972 /* If we can move one char, return the empty string there */
3973 GtkTextIter match = *iter;
3975 if (limit && gtk_text_iter_equal (limit, &match))
3978 if (gtk_text_iter_backward_char (&match))
3981 *match_start = match;
3990 /* locate all lines */
3992 lines = strbreakup (str, "\n", -1);
4002 win.n_lines = n_lines;
4004 win.visible_only = visible_only;
4006 lines_window_init (&win, iter);
4008 if (*win.lines == NULL)
4013 gchar *first_line_match;
4016 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4018 /* We're now before the search limit, abort. */
4022 /* If there are multiple lines, the first line will
4023 * end in '\n', so this will only match at the
4024 * end of the first line, which is correct.
4026 first_line_match = my_strrstr (*win.lines, *lines);
4028 if (first_line_match &&
4029 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4034 GtkTextIter start_tmp;
4036 /* Offset to start of search string */
4037 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4039 next = win.first_line_start;
4041 forward_chars_with_skipping (&start_tmp, offset,
4042 visible_only, !slice);
4045 gtk_text_iter_compare (limit, &start_tmp) > 0)
4046 goto out; /* match was bogus */
4049 *match_start = start_tmp;
4051 /* Go to end of search string */
4055 offset += g_utf8_strlen (*l, -1);
4059 forward_chars_with_skipping (&next, offset,
4060 visible_only, !slice);
4069 while (lines_window_back (&win));
4072 lines_window_free (&win);
4083 gtk_text_iter_equal (const GtkTextIter *lhs,
4084 const GtkTextIter *rhs)
4086 GtkTextRealIter *real_lhs;
4087 GtkTextRealIter *real_rhs;
4089 real_lhs = (GtkTextRealIter*)lhs;
4090 real_rhs = (GtkTextRealIter*)rhs;
4092 check_invariants (lhs);
4093 check_invariants (rhs);
4095 if (real_lhs->line != real_rhs->line)
4097 else if (real_lhs->line_byte_offset >= 0 &&
4098 real_rhs->line_byte_offset >= 0)
4099 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4102 /* the ensure_char_offsets () calls do nothing if the char offsets
4103 are already up-to-date. */
4104 ensure_char_offsets (real_lhs);
4105 ensure_char_offsets (real_rhs);
4106 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4111 gtk_text_iter_compare (const GtkTextIter *lhs, const GtkTextIter *rhs)
4113 GtkTextRealIter *real_lhs;
4114 GtkTextRealIter *real_rhs;
4116 real_lhs = gtk_text_iter_make_surreal (lhs);
4117 real_rhs = gtk_text_iter_make_surreal (rhs);
4119 check_invariants (lhs);
4120 check_invariants (rhs);
4122 if (real_lhs == NULL ||
4124 return -1; /* why not */
4126 if (real_lhs->line == real_rhs->line)
4128 gint left_index, right_index;
4130 if (real_lhs->line_byte_offset >= 0 &&
4131 real_rhs->line_byte_offset >= 0)
4133 left_index = real_lhs->line_byte_offset;
4134 right_index = real_rhs->line_byte_offset;
4138 /* the ensure_char_offsets () calls do nothing if
4139 the offsets are already up-to-date. */
4140 ensure_char_offsets (real_lhs);
4141 ensure_char_offsets (real_rhs);
4142 left_index = real_lhs->line_char_offset;
4143 right_index = real_rhs->line_char_offset;
4146 if (left_index < right_index)
4148 else if (left_index > right_index)
4157 line1 = gtk_text_iter_get_line (lhs);
4158 line2 = gtk_text_iter_get_line (rhs);
4161 else if (line1 > line2)
4169 gtk_text_iter_in_range (const GtkTextIter *iter,
4170 const GtkTextIter *start,
4171 const GtkTextIter *end)
4173 return gtk_text_iter_compare (iter, start) >= 0 &&
4174 gtk_text_iter_compare (iter, end) < 0;
4178 gtk_text_iter_reorder (GtkTextIter *first,
4179 GtkTextIter *second)
4181 g_return_if_fail (first != NULL);
4182 g_return_if_fail (second != NULL);
4184 if (gtk_text_iter_compare (first, second) > 0)
4195 * Init iterators from the BTree
4199 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4203 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4204 gint real_char_index;
4208 g_return_if_fail (iter != NULL);
4209 g_return_if_fail (tree != NULL);
4211 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4212 &line_start, &real_char_index);
4214 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4216 real->cached_char_index = real_char_index;
4218 check_invariants (iter);
4222 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4227 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4231 g_return_if_fail (iter != NULL);
4232 g_return_if_fail (tree != NULL);
4234 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4236 iter_init_from_char_offset (iter, tree, line, char_on_line);
4238 /* We might as well cache this, since we know it. */
4239 real->cached_line_number = real_line;
4241 check_invariants (iter);
4245 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4250 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4254 g_return_if_fail (iter != NULL);
4255 g_return_if_fail (tree != NULL);
4257 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4259 iter_init_from_byte_offset (iter, tree, line, byte_index);
4261 /* We might as well cache this, since we know it. */
4262 real->cached_line_number = real_line;
4264 if (real->segment->type == >k_text_char_type &&
4265 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
4266 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
4267 "character; this will crash the text buffer. "
4268 "Byte indexes must refer to the start of a character.",
4269 G_STRLOC, byte_index);
4271 check_invariants (iter);
4275 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
4280 g_return_if_fail (iter != NULL);
4281 g_return_if_fail (tree != NULL);
4282 g_return_if_fail (line != NULL);
4284 iter_init_from_byte_offset (iter, tree, line, byte_offset);
4286 check_invariants (iter);
4290 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
4296 g_return_val_if_fail (iter != NULL, FALSE);
4297 g_return_val_if_fail (tree != NULL, FALSE);
4299 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
4303 /* Set iter to last in tree */
4304 _gtk_text_btree_get_last_iter (tree, iter);
4305 check_invariants (iter);
4310 iter_init_from_byte_offset (iter, tree, line, 0);
4311 gtk_text_iter_forward_to_tag_toggle (iter, tag);
4312 check_invariants (iter);
4318 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
4324 g_return_val_if_fail (iter != NULL, FALSE);
4325 g_return_val_if_fail (tree != NULL, FALSE);
4327 line = _gtk_text_btree_last_could_contain_tag (tree, tag);
4331 /* Set iter to first in tree */
4332 _gtk_text_btree_get_iter_at_line_char (tree, iter, 0, 0);
4333 check_invariants (iter);
4338 iter_init_from_byte_offset (iter, tree, line, -1);
4339 gtk_text_iter_backward_to_tag_toggle (iter, tag);
4340 check_invariants (iter);
4346 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
4348 const gchar *mark_name)
4352 g_return_val_if_fail (iter != NULL, FALSE);
4353 g_return_val_if_fail (tree != NULL, FALSE);
4355 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
4361 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
4362 check_invariants (iter);
4368 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
4372 GtkTextLineSegment *seg;
4374 g_return_if_fail (iter != NULL);
4375 g_return_if_fail (tree != NULL);
4376 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
4378 seg = mark->segment;
4380 iter_init_from_segment (iter, tree,
4381 seg->body.mark.line, seg);
4382 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
4383 check_invariants (iter);
4387 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
4389 GtkTextChildAnchor *anchor)
4391 GtkTextLineSegment *seg;
4393 g_return_if_fail (iter != NULL);
4394 g_return_if_fail (tree != NULL);
4395 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
4397 seg = anchor->segment;
4399 iter_init_from_segment (iter, tree,
4400 seg->body.child.line, seg);
4401 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
4402 check_invariants (iter);
4406 _gtk_text_btree_get_last_iter (GtkTextBTree *tree,
4409 g_return_if_fail (iter != NULL);
4410 g_return_if_fail (tree != NULL);
4412 _gtk_text_btree_get_iter_at_char (tree,
4414 _gtk_text_btree_char_count (tree));
4415 check_invariants (iter);
4419 gtk_text_iter_spew (const GtkTextIter *iter, const gchar *desc)
4421 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4423 g_return_if_fail (iter != NULL);
4425 if (real->chars_changed_stamp != _gtk_text_btree_get_chars_changed_stamp (real->tree))
4426 g_print (" %20s: <invalidated iterator>\n", desc);
4429 check_invariants (iter);
4430 g_print (" %20s: line %d / char %d / line char %d / line byte %d\n",
4432 gtk_text_iter_get_line (iter),
4433 gtk_text_iter_get_offset (iter),
4434 gtk_text_iter_get_line_offset (iter),
4435 gtk_text_iter_get_line_index (iter));
4436 check_invariants (iter);
4441 _gtk_text_iter_check (const GtkTextIter *iter)
4443 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
4444 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
4445 GtkTextLineSegment *byte_segment = NULL;
4446 GtkTextLineSegment *byte_any_segment = NULL;
4447 GtkTextLineSegment *char_segment = NULL;
4448 GtkTextLineSegment *char_any_segment = NULL;
4449 gboolean segments_updated;
4451 /* This function checks our class invariants for the Iter class. */
4453 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
4455 if (real->chars_changed_stamp !=
4456 _gtk_text_btree_get_chars_changed_stamp (real->tree))
4457 g_error ("iterator check failed: invalid iterator");
4459 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
4460 g_error ("iterator check failed: both char and byte offsets are invalid");
4462 segments_updated = (real->segments_changed_stamp ==
4463 _gtk_text_btree_get_segments_changed_stamp (real->tree));
4466 printf ("checking iter, segments %s updated, byte %d char %d\n",
4467 segments_updated ? "are" : "aren't",
4468 real->line_byte_offset,
4469 real->line_char_offset);
4472 if (segments_updated)
4474 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
4475 g_error ("iterator check failed: both char and byte segment offsets are invalid");
4477 if (real->segment->char_count == 0)
4478 g_error ("iterator check failed: segment is not indexable.");
4480 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
4481 g_error ("segment char offset is not properly up-to-date");
4483 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
4484 g_error ("segment byte offset is not properly up-to-date");
4486 if (real->segment_byte_offset >= 0 &&
4487 real->segment_byte_offset >= real->segment->byte_count)
4488 g_error ("segment byte offset is too large.");
4490 if (real->segment_char_offset >= 0 &&
4491 real->segment_char_offset >= real->segment->char_count)
4492 g_error ("segment char offset is too large.");
4495 if (real->line_byte_offset >= 0)
4497 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
4498 &byte_segment, &byte_any_segment,
4499 &seg_byte_offset, &line_byte_offset);
4501 if (line_byte_offset != real->line_byte_offset)
4502 g_error ("wrong byte offset was stored in iterator");
4504 if (segments_updated)
4506 if (real->segment != byte_segment)
4507 g_error ("wrong segment was stored in iterator");
4509 if (real->any_segment != byte_any_segment)
4510 g_error ("wrong any_segment was stored in iterator");
4512 if (seg_byte_offset != real->segment_byte_offset)
4513 g_error ("wrong segment byte offset was stored in iterator");
4515 if (byte_segment->type == >k_text_char_type)
4518 p = byte_segment->body.chars + seg_byte_offset;
4520 if (!gtk_text_byte_begins_utf8_char (p))
4521 g_error ("broken iterator byte index pointed into the middle of a character");
4526 if (real->line_char_offset >= 0)
4528 _gtk_text_line_char_locate (real->line, real->line_char_offset,
4529 &char_segment, &char_any_segment,
4530 &seg_char_offset, &line_char_offset);
4532 if (line_char_offset != real->line_char_offset)
4533 g_error ("wrong char offset was stored in iterator");
4535 if (segments_updated)
4537 if (real->segment != char_segment)
4538 g_error ("wrong segment was stored in iterator");
4540 if (real->any_segment != char_any_segment)
4541 g_error ("wrong any_segment was stored in iterator");
4543 if (seg_char_offset != real->segment_char_offset)
4544 g_error ("wrong segment char offset was stored in iterator");
4546 if (char_segment->type == >k_text_char_type)
4549 p = g_utf8_offset_to_pointer (char_segment->body.chars,
4552 /* hmm, not likely to happen eh */
4553 if (!gtk_text_byte_begins_utf8_char (p))
4554 g_error ("broken iterator char offset pointed into the middle of a character");
4559 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
4561 if (byte_segment != char_segment)
4562 g_error ("char and byte offsets did not point to the same segment");
4564 if (byte_any_segment != char_any_segment)
4565 g_error ("char and byte offsets did not point to the same any segment");
4567 /* Make sure the segment offsets are equivalent, if it's a char
4569 if (char_segment->type == >k_text_char_type)
4571 gint byte_offset = 0;
4572 gint char_offset = 0;
4573 while (char_offset < seg_char_offset)
4575 const char * start = char_segment->body.chars + byte_offset;
4576 byte_offset += g_utf8_next_char (start) - start;
4580 if (byte_offset != seg_byte_offset)
4581 g_error ("byte offset did not correspond to char offset");
4584 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
4586 if (char_offset != seg_char_offset)
4587 g_error ("char offset did not correspond to byte offset");
4589 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
4590 g_error ("byte index for iterator does not index the start of a character");
4594 if (real->cached_line_number >= 0)
4598 should_be = _gtk_text_line_get_number (real->line);
4599 if (real->cached_line_number != should_be)
4600 g_error ("wrong line number was cached");
4603 if (real->cached_char_index >= 0)
4605 if (real->line_char_offset >= 0) /* only way we can check it
4606 efficiently, not a real
4611 char_index = _gtk_text_line_char_index (real->line);
4612 char_index += real->line_char_offset;
4614 if (real->cached_char_index != char_index)
4615 g_error ("wrong char index was cached");