1 /* GTK - The GIMP Toolkit
2 * gtktextiter.c Copyright (C) 2000 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
28 #include "gtktextiter.h"
29 #include "gtktextbtree.h"
30 #include "gtktextiterprivate.h"
35 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
37 typedef struct _GtkTextRealIter GtkTextRealIter;
39 struct _GtkTextRealIter
41 /* Always-valid information */
44 /* At least one of these is always valid;
45 if invalid, they are -1.
47 If the line byte offset is valid, so is the segment byte offset;
48 and ditto for char offsets. */
49 gint line_byte_offset;
50 gint line_char_offset;
51 /* These two are valid if >= 0 */
52 gint cached_char_index;
53 gint cached_line_number;
54 /* Stamps to detect the buffer changing under us */
55 gint chars_changed_stamp;
56 gint segments_changed_stamp;
57 /* Valid if the segments_changed_stamp is up-to-date */
58 GtkTextLineSegment *segment; /* indexable segment we index */
59 GtkTextLineSegment *any_segment; /* first segment in our location,
60 maybe same as "segment" */
61 /* One of these will always be valid if segments_changed_stamp is
62 up-to-date. If invalid, they are -1.
64 If the line byte offset is valid, so is the segment byte offset;
65 and ditto for char offsets. */
66 gint segment_byte_offset;
67 gint segment_char_offset;
70 /* These "set" functions should not assume any fields
71 other than the char stamp and the tree are valid.
74 iter_set_common (GtkTextRealIter *iter,
77 /* Update segments stamp */
78 iter->segments_changed_stamp =
79 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
83 iter->line_byte_offset = -1;
84 iter->line_char_offset = -1;
85 iter->segment_byte_offset = -1;
86 iter->segment_char_offset = -1;
87 iter->cached_char_index = -1;
88 iter->cached_line_number = -1;
92 iter_set_from_byte_offset (GtkTextRealIter *iter,
96 iter_set_common (iter, line);
98 if (!_gtk_text_line_byte_locate (iter->line,
102 &iter->segment_byte_offset,
103 &iter->line_byte_offset))
104 g_error ("Byte index %d is off the end of the line",
109 iter_set_from_char_offset (GtkTextRealIter *iter,
113 iter_set_common (iter, line);
115 if (!_gtk_text_line_char_locate (iter->line,
119 &iter->segment_char_offset,
120 &iter->line_char_offset))
121 g_error ("Char offset %d is off the end of the line",
126 iter_set_from_segment (GtkTextRealIter *iter,
128 GtkTextLineSegment *segment)
130 GtkTextLineSegment *seg;
133 /* This could theoretically be optimized by computing all the iter
134 fields in this same loop, but I'm skipping it for now. */
136 seg = line->segments;
137 while (seg != segment)
139 byte_offset += seg->byte_count;
143 iter_set_from_byte_offset (iter, line, byte_offset);
146 /* This function ensures that the segment-dependent information is
147 truly computed lazily; often we don't need to do the full make_real
148 work. This ensures the btree and line are valid, but doesn't
149 update the segments. */
150 static GtkTextRealIter*
151 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
153 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
155 if (iter->chars_changed_stamp !=
156 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
158 g_warning ("Invalid text buffer iterator: either the iterator "
159 "is uninitialized, or the characters/pixbufs/widgets "
160 "in the buffer have been modified since the iterator "
161 "was created.\nYou must use marks, character numbers, "
162 "or line numbers to preserve a position across buffer "
163 "modifications.\nYou can apply tags and insert marks "
164 "without invalidating your iterators,\n"
165 "but any mutation that affects 'indexable' buffer contents "
166 "(contents that can be referred to by character offset)\n"
167 "will invalidate all outstanding iterators");
171 /* We don't update the segments information since we are becoming
172 only surreal. However we do invalidate the segments information
173 if appropriate, to be sure we segfault if we try to use it and we
174 should have used make_real. */
176 if (iter->segments_changed_stamp !=
177 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
179 iter->segment = NULL;
180 iter->any_segment = NULL;
181 /* set to segfault-causing values. */
182 iter->segment_byte_offset = -10000;
183 iter->segment_char_offset = -10000;
189 static GtkTextRealIter*
190 gtk_text_iter_make_real (const GtkTextIter *_iter)
192 GtkTextRealIter *iter;
194 iter = gtk_text_iter_make_surreal (_iter);
196 if (iter->segments_changed_stamp !=
197 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
199 if (iter->line_byte_offset >= 0)
201 iter_set_from_byte_offset (iter,
203 iter->line_byte_offset);
207 g_assert (iter->line_char_offset >= 0);
209 iter_set_from_char_offset (iter,
211 iter->line_char_offset);
215 g_assert (iter->segment != NULL);
216 g_assert (iter->any_segment != NULL);
217 g_assert (iter->segment->char_count > 0);
222 static GtkTextRealIter*
223 iter_init_common (GtkTextIter *_iter,
226 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
228 g_return_val_if_fail (iter != NULL, NULL);
229 g_return_val_if_fail (tree != NULL, NULL);
233 iter->chars_changed_stamp =
234 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
239 static GtkTextRealIter*
240 iter_init_from_segment (GtkTextIter *iter,
243 GtkTextLineSegment *segment)
245 GtkTextRealIter *real;
247 g_return_val_if_fail (line != NULL, NULL);
249 real = iter_init_common (iter, tree);
251 iter_set_from_segment (real, line, segment);
256 static GtkTextRealIter*
257 iter_init_from_byte_offset (GtkTextIter *iter,
260 gint line_byte_offset)
262 GtkTextRealIter *real;
264 g_return_val_if_fail (line != NULL, NULL);
266 real = iter_init_common (iter, tree);
268 iter_set_from_byte_offset (real, line, line_byte_offset);
270 if (real->segment->type == >k_text_char_type &&
271 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
272 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
273 "character; this will crash the text buffer. "
274 "Byte indexes must refer to the start of a character.",
280 static GtkTextRealIter*
281 iter_init_from_char_offset (GtkTextIter *iter,
284 gint line_char_offset)
286 GtkTextRealIter *real;
288 g_return_val_if_fail (line != NULL, NULL);
290 real = iter_init_common (iter, tree);
292 iter_set_from_char_offset (real, line, line_char_offset);
298 invalidate_segment (GtkTextRealIter *iter)
300 iter->segments_changed_stamp -= 1;
304 invalidate_char_index (GtkTextRealIter *iter)
306 iter->cached_char_index = -1;
310 invalidate_line_number (GtkTextRealIter *iter)
312 iter->cached_line_number = -1;
316 adjust_char_index (GtkTextRealIter *iter, gint count)
318 if (iter->cached_char_index >= 0)
319 iter->cached_char_index += count;
323 adjust_line_number (GtkTextRealIter *iter, gint count)
325 if (iter->cached_line_number >= 0)
326 iter->cached_line_number += count;
330 adjust_char_offsets (GtkTextRealIter *iter, gint count)
332 if (iter->line_char_offset >= 0)
334 iter->line_char_offset += count;
335 g_assert (iter->segment_char_offset >= 0);
336 iter->segment_char_offset += count;
341 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
343 if (iter->line_byte_offset >= 0)
345 iter->line_byte_offset += count;
346 g_assert (iter->segment_byte_offset >= 0);
347 iter->segment_byte_offset += count;
352 ensure_char_offsets (GtkTextRealIter *iter)
354 if (iter->line_char_offset < 0)
356 g_assert (iter->line_byte_offset >= 0);
358 _gtk_text_line_byte_to_char_offsets (iter->line,
359 iter->line_byte_offset,
360 &iter->line_char_offset,
361 &iter->segment_char_offset);
366 ensure_byte_offsets (GtkTextRealIter *iter)
368 if (iter->line_byte_offset < 0)
370 g_assert (iter->line_char_offset >= 0);
372 _gtk_text_line_char_to_byte_offsets (iter->line,
373 iter->line_char_offset,
374 &iter->line_byte_offset,
375 &iter->segment_byte_offset);
379 static inline gboolean
380 is_segment_start (GtkTextRealIter *real)
382 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
387 check_invariants (const GtkTextIter *iter)
389 if (gtk_debug_flags & GTK_DEBUG_TEXT)
390 _gtk_text_iter_check (iter);
393 #define check_invariants (x)
397 * gtk_text_iter_get_buffer:
400 * Returns the #GtkTextBuffer this iterator is associated with.
402 * Return value: the buffer
405 gtk_text_iter_get_buffer (const GtkTextIter *iter)
407 GtkTextRealIter *real;
409 g_return_val_if_fail (iter != NULL, NULL);
411 real = gtk_text_iter_make_surreal (iter);
416 check_invariants (iter);
418 return _gtk_text_btree_get_buffer (real->tree);
422 * gtk_text_iter_copy:
425 * Creates a dynamically-allocated copy of an iterator. This function
426 * is not useful in applications, because iterators can be copied with a
427 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
428 * function is used by language bindings.
430 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
433 gtk_text_iter_copy (const GtkTextIter *iter)
435 GtkTextIter *new_iter;
437 g_return_val_if_fail (iter != NULL, NULL);
439 new_iter = g_new (GtkTextIter, 1);
447 * gtk_text_iter_free:
448 * @iter: a dynamically-allocated iterator
450 * Free an iterator allocated on the heap. This function
451 * is intended for use in language bindings, and is not
452 * especially useful for applications, because iterators can
453 * simply be allocated on the stack.
456 gtk_text_iter_free (GtkTextIter *iter)
458 g_return_if_fail (iter != NULL);
464 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
466 GtkTextRealIter *real;
468 g_return_val_if_fail (iter != NULL, 0);
470 real = gtk_text_iter_make_real (iter);
475 check_invariants (iter);
477 g_assert (real->segment != NULL);
479 return real->segment;
483 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
485 GtkTextRealIter *real;
487 g_return_val_if_fail (iter != NULL, 0);
489 real = gtk_text_iter_make_real (iter);
494 check_invariants (iter);
496 g_assert (real->any_segment != NULL);
498 return real->any_segment;
502 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
504 GtkTextRealIter *real;
506 g_return_val_if_fail (iter != NULL, 0);
508 real = gtk_text_iter_make_real (iter);
513 ensure_byte_offsets (real);
515 check_invariants (iter);
517 return real->segment_byte_offset;
521 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
523 GtkTextRealIter *real;
525 g_return_val_if_fail (iter != NULL, 0);
527 real = gtk_text_iter_make_real (iter);
532 ensure_char_offsets (real);
534 check_invariants (iter);
536 return real->segment_char_offset;
539 /* This function does not require a still-valid
542 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
544 const GtkTextRealIter *real;
546 g_return_val_if_fail (iter != NULL, 0);
548 real = (const GtkTextRealIter*)iter;
553 /* This function does not require a still-valid
556 _gtk_text_iter_get_btree (const GtkTextIter *iter)
558 const GtkTextRealIter *real;
560 g_return_val_if_fail (iter != NULL, 0);
562 real = (const GtkTextRealIter*)iter;
572 * gtk_text_iter_get_offset:
575 * Returns the character offset of an iterator.
576 * Each character in a #GtkTextBuffer has an offset,
577 * starting with 0 for the first character in the buffer.
578 * Use gtk_text_buffer_get_iter_at_offset () to convert an
579 * offset back into an iterator.
581 * Return value: a character offset
584 gtk_text_iter_get_offset (const GtkTextIter *iter)
586 GtkTextRealIter *real;
588 g_return_val_if_fail (iter != NULL, 0);
590 real = gtk_text_iter_make_surreal (iter);
595 check_invariants (iter);
597 if (real->cached_char_index < 0)
599 ensure_char_offsets (real);
601 real->cached_char_index =
602 _gtk_text_line_char_index (real->line);
603 real->cached_char_index += real->line_char_offset;
606 check_invariants (iter);
608 return real->cached_char_index;
612 * gtk_text_iter_get_line:
615 * Returns the line number containing the iterator. Lines in
616 * a #GtkTextBuffer are numbered beginning with 0 for the first
617 * line in the buffer.
619 * Return value: a line number
622 gtk_text_iter_get_line (const GtkTextIter *iter)
624 GtkTextRealIter *real;
626 g_return_val_if_fail (iter != NULL, 0);
628 real = gtk_text_iter_make_surreal (iter);
633 if (real->cached_line_number < 0)
634 real->cached_line_number =
635 _gtk_text_line_get_number (real->line);
637 check_invariants (iter);
639 return real->cached_line_number;
643 * gtk_text_iter_get_line_offset:
646 * Returns the character offset of the iterator,
647 * counting from the start of a newline-terminated line.
648 * The first character on the line has offset 0.
650 * Return value: offset from start of line
653 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
655 GtkTextRealIter *real;
657 g_return_val_if_fail (iter != NULL, 0);
659 real = gtk_text_iter_make_surreal (iter);
664 ensure_char_offsets (real);
666 check_invariants (iter);
668 return real->line_char_offset;
672 * gtk_text_iter_get_line_index:
675 * Returns the byte index of the iterator, counting
676 * from the start of a newline-terminated line.
677 * Remember that #GtkTextBuffer encodes text in
678 * UTF-8, and that characters can require a variable
679 * number of bytes to represent.
681 * Return value: distance from start of line, in bytes
684 gtk_text_iter_get_line_index (const GtkTextIter *iter)
686 GtkTextRealIter *real;
688 g_return_val_if_fail (iter != NULL, 0);
690 real = gtk_text_iter_make_surreal (iter);
695 ensure_byte_offsets (real);
697 check_invariants (iter);
699 return real->line_byte_offset;
703 * gtk_text_iter_get_visible_line_offset:
704 * @iter: a #GtkTextIter
706 * Returns the offset in characters from the start of the
707 * line to the given @iter, not counting characters that
708 * are invisible due to tags with the "invisible" flag
711 * Return value: offset in visible characters from the start of the line
714 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
716 GtkTextRealIter *real;
718 GtkTextLineSegment *seg;
721 g_return_val_if_fail (iter != NULL, 0);
723 real = gtk_text_iter_make_real (iter);
728 ensure_char_offsets (real);
730 check_invariants (iter);
732 vis_offset = real->line_char_offset;
734 _gtk_text_btree_get_iter_at_line (real->tree,
739 seg = _gtk_text_iter_get_indexable_segment (&pos);
741 while (seg != real->segment)
743 /* This is a pretty expensive call, making the
744 * whole function pretty lame; we could keep track
745 * of current invisibility state by looking at toggle
746 * segments as we loop, and then call this function
747 * only once per line, in order to speed up the loop
750 if (_gtk_text_btree_char_is_invisible (&pos))
751 vis_offset -= seg->char_count;
753 _gtk_text_iter_forward_indexable_segment (&pos);
755 seg = _gtk_text_iter_get_indexable_segment (&pos);
758 if (_gtk_text_btree_char_is_invisible (&pos))
759 vis_offset -= real->segment_char_offset;
766 * gtk_text_iter_get_visible_line_index:
767 * @iter: a #GtkTextIter
769 * Returns the number of bytes from the start of the
770 * line to the given @iter, not counting bytes that
771 * are invisible due to tags with the "invisible" flag
774 * Return value: byte index of @iter with respect to the start of the line
777 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
779 GtkTextRealIter *real;
781 GtkTextLineSegment *seg;
784 g_return_val_if_fail (iter != NULL, 0);
786 real = gtk_text_iter_make_real (iter);
791 ensure_char_offsets (real);
793 check_invariants (iter);
795 vis_offset = real->line_byte_offset;
797 _gtk_text_btree_get_iter_at_line (real->tree,
802 seg = _gtk_text_iter_get_indexable_segment (&pos);
804 while (seg != real->segment)
806 /* This is a pretty expensive call, making the
807 * whole function pretty lame; we could keep track
808 * of current invisibility state by looking at toggle
809 * segments as we loop, and then call this function
810 * only once per line, in order to speed up the loop
813 if (_gtk_text_btree_char_is_invisible (&pos))
814 vis_offset -= seg->byte_count;
816 _gtk_text_iter_forward_indexable_segment (&pos);
818 seg = _gtk_text_iter_get_indexable_segment (&pos);
821 if (_gtk_text_btree_char_is_invisible (&pos))
822 vis_offset -= real->segment_byte_offset;
832 * gtk_text_iter_get_char:
835 * Returns the Unicode character at this iterator. (Equivalent to
836 * operator* on a C++ iterator.) If the iterator points at a
837 * non-character element, such as an image embedded in the buffer, the
838 * Unicode "unknown" character 0xFFFC is returned. If invoked on
839 * the end iterator, zero is returned; zero is not a valid Unicode character.
840 * So you can write a loop which ends when gtk_text_iter_get_char ()
843 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
846 gtk_text_iter_get_char (const GtkTextIter *iter)
848 GtkTextRealIter *real;
850 g_return_val_if_fail (iter != NULL, 0);
852 real = gtk_text_iter_make_real (iter);
857 check_invariants (iter);
859 if (gtk_text_iter_is_end (iter))
861 else if (real->segment->type == >k_text_char_type)
863 ensure_byte_offsets (real);
865 return g_utf8_get_char (real->segment->body.chars +
866 real->segment_byte_offset);
870 /* Unicode "unknown character" 0xFFFC */
871 return GTK_TEXT_UNKNOWN_CHAR;
876 * gtk_text_iter_get_slice:
877 * @start: iterator at start of a range
878 * @end: iterator at end of a range
880 * Returns the text in the given range. A "slice" is an array of
881 * characters encoded in UTF-8 format, including the Unicode "unknown"
882 * character 0xFFFC for iterable non-character elements in the buffer,
883 * such as images. Because images are encoded in the slice, byte and
884 * character offsets in the returned array will correspond to byte
885 * offsets in the text buffer. Note that 0xFFFC can occur in normal
886 * text as well, so it is not a reliable indicator that a pixbuf or
887 * widget is in the buffer.
889 * Return value: slice of text from the buffer
892 gtk_text_iter_get_slice (const GtkTextIter *start,
893 const GtkTextIter *end)
895 g_return_val_if_fail (start != NULL, NULL);
896 g_return_val_if_fail (end != NULL, NULL);
898 check_invariants (start);
899 check_invariants (end);
901 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
905 * gtk_text_iter_get_text:
906 * @start: iterator at start of a range
907 * @end: iterator at end of a range
909 * Returns <emphasis>text</emphasis> in the given range. If the range
910 * contains non-text elements such as images, the character and byte
911 * offsets in the returned string will not correspond to character and
912 * byte offsets in the buffer. If you want offsets to correspond, see
913 * gtk_text_iter_get_slice ().
915 * Return value: array of characters from the buffer
918 gtk_text_iter_get_text (const GtkTextIter *start,
919 const GtkTextIter *end)
921 g_return_val_if_fail (start != NULL, NULL);
922 g_return_val_if_fail (end != NULL, NULL);
924 check_invariants (start);
925 check_invariants (end);
927 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
931 * gtk_text_iter_get_visible_slice:
932 * @start: iterator at start of range
933 * @end: iterator at end of range
935 * Like gtk_text_iter_get_slice (), but invisible text is not included.
936 * Invisible text is usually invisible because a #GtkTextTag with the
937 * "invisible" attribute turned on has been applied to it.
939 * Return value: slice of text from the buffer
942 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
943 const GtkTextIter *end)
945 g_return_val_if_fail (start != NULL, NULL);
946 g_return_val_if_fail (end != NULL, NULL);
948 check_invariants (start);
949 check_invariants (end);
951 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
955 * gtk_text_iter_get_visible_text:
956 * @start: iterator at start of range
957 * @end: iterator at end of range
959 * Like gtk_text_iter_get_text (), but invisible text is not included.
960 * Invisible text is usually invisible because a #GtkTextTag with the
961 * "invisible" attribute turned on has been applied to it.
963 * Return value: string containing visible text in the range
966 gtk_text_iter_get_visible_text (const GtkTextIter *start,
967 const GtkTextIter *end)
969 g_return_val_if_fail (start != NULL, NULL);
970 g_return_val_if_fail (end != NULL, NULL);
972 check_invariants (start);
973 check_invariants (end);
975 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
979 * gtk_text_iter_get_pixbuf:
982 * If the location pointed to by @iter contains a pixbuf, the pixbuf
983 * is returned (with no new reference count added). Otherwise,
986 * Return value: the pixbuf at @iter
989 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
991 GtkTextRealIter *real;
993 g_return_val_if_fail (iter != NULL, NULL);
995 real = gtk_text_iter_make_real (iter);
1000 check_invariants (iter);
1002 if (real->segment->type != >k_text_pixbuf_type)
1005 return real->segment->body.pixbuf.pixbuf;
1009 * gtk_text_iter_get_child_anchor:
1010 * @iter: an iterator
1012 * If the location pointed to by @iter contains a child anchor, the
1013 * anchor is returned (with no new reference count added). Otherwise,
1014 * %NULL is returned.
1016 * Return value: the anchor at @iter
1019 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1021 GtkTextRealIter *real;
1023 g_return_val_if_fail (iter != NULL, NULL);
1025 real = gtk_text_iter_make_real (iter);
1030 check_invariants (iter);
1032 if (real->segment->type != >k_text_child_type)
1035 return real->segment->body.child.obj;
1039 * gtk_text_iter_get_marks:
1040 * @iter: an iterator
1042 * Returns a list of all #GtkTextMark at this location. Because marks
1043 * are not iterable (they don't take up any "space" in the buffer,
1044 * they are just marks in between iterable locations), multiple marks
1045 * can exist in the same place. The returned list is not in any
1048 * Return value: list of #GtkTextMark
1051 gtk_text_iter_get_marks (const GtkTextIter *iter)
1053 GtkTextRealIter *real;
1054 GtkTextLineSegment *seg;
1057 g_return_val_if_fail (iter != NULL, NULL);
1059 real = gtk_text_iter_make_real (iter);
1064 check_invariants (iter);
1067 seg = real->any_segment;
1068 while (seg != real->segment)
1070 if (seg->type == >k_text_left_mark_type ||
1071 seg->type == >k_text_right_mark_type)
1072 retval = g_slist_prepend (retval, seg->body.mark.obj);
1077 /* The returned list isn't guaranteed to be in any special order,
1083 * gtk_text_iter_get_toggled_tags:
1084 * @iter: an iterator
1085 * @toggled_on: %TRUE to get toggled-on tags
1087 * Returns a list of #GtkTextTag that are toggled on or off at this
1088 * point. (If @toggled_on is %TRUE, the list contains tags that are
1089 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1090 * range of characters following @iter has that tag applied to it. If
1091 * a tag is toggled off, then some non-empty range following @iter
1092 * does <emphasis>not</emphasis> have the tag applied to it.
1094 * Return value: tags toggled at this point
1097 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1098 gboolean toggled_on)
1100 GtkTextRealIter *real;
1101 GtkTextLineSegment *seg;
1104 g_return_val_if_fail (iter != NULL, NULL);
1106 real = gtk_text_iter_make_real (iter);
1111 check_invariants (iter);
1114 seg = real->any_segment;
1115 while (seg != real->segment)
1119 if (seg->type == >k_text_toggle_on_type)
1121 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1126 if (seg->type == >k_text_toggle_off_type)
1128 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1135 /* The returned list isn't guaranteed to be in any special order,
1141 * gtk_text_iter_begins_tag:
1142 * @iter: an iterator
1143 * @tag: a #GtkTextTag, or %NULL
1145 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1146 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1147 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1148 * <emphasis>start</emphasis> of the tagged range;
1149 * gtk_text_iter_has_tag () tells you whether an iterator is
1150 * <emphasis>within</emphasis> a tagged range.
1152 * Return value: whether @iter is the start of a range tagged with @tag
1155 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1158 GtkTextRealIter *real;
1159 GtkTextLineSegment *seg;
1161 g_return_val_if_fail (iter != NULL, FALSE);
1163 real = gtk_text_iter_make_real (iter);
1168 check_invariants (iter);
1170 seg = real->any_segment;
1171 while (seg != real->segment)
1173 if (seg->type == >k_text_toggle_on_type)
1176 seg->body.toggle.info->tag == tag)
1187 * gtk_text_iter_ends_tag:
1188 * @iter: an iterator
1189 * @tag: a #GtkTextTag, or %NULL
1191 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1192 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1193 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1194 * <emphasis>end</emphasis> of the tagged range;
1195 * gtk_text_iter_has_tag () tells you whether an iterator is
1196 * <emphasis>within</emphasis> a tagged range.
1198 * Return value: whether @iter is the end of a range tagged with @tag
1202 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1205 GtkTextRealIter *real;
1206 GtkTextLineSegment *seg;
1208 g_return_val_if_fail (iter != NULL, FALSE);
1210 real = gtk_text_iter_make_real (iter);
1215 check_invariants (iter);
1217 seg = real->any_segment;
1218 while (seg != real->segment)
1220 if (seg->type == >k_text_toggle_off_type)
1223 seg->body.toggle.info->tag == tag)
1234 * gtk_text_iter_toggles_tag:
1235 * @iter: an iterator
1236 * @tag: a #GtkTextTag, or %NULL
1238 * This is equivalent to (gtk_text_iter_begins_tag () ||
1239 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1240 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1242 * Return value: whether @tag is toggled on or off at @iter
1245 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1248 GtkTextRealIter *real;
1249 GtkTextLineSegment *seg;
1251 g_return_val_if_fail (iter != NULL, FALSE);
1253 real = gtk_text_iter_make_real (iter);
1258 check_invariants (iter);
1260 seg = real->any_segment;
1261 while (seg != real->segment)
1263 if ( (seg->type == >k_text_toggle_off_type ||
1264 seg->type == >k_text_toggle_on_type) &&
1266 seg->body.toggle.info->tag == tag) )
1276 * gtk_text_iter_has_tag:
1277 * @iter: an iterator
1278 * @tag: a #GtkTextTag
1280 * Returns %TRUE if @iter is within a range tagged with @tag.
1282 * Return value: whether @iter is tagged with @tag
1285 gtk_text_iter_has_tag (const GtkTextIter *iter,
1288 GtkTextRealIter *real;
1290 g_return_val_if_fail (iter != NULL, FALSE);
1291 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1293 real = gtk_text_iter_make_surreal (iter);
1298 check_invariants (iter);
1300 if (real->line_byte_offset >= 0)
1302 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1303 real->line_byte_offset, tag);
1307 g_assert (real->line_char_offset >= 0);
1308 return _gtk_text_line_char_has_tag (real->line, real->tree,
1309 real->line_char_offset, tag);
1314 * gtk_text_iter_get_tags:
1315 * @iter: a #GtkTextIter
1317 * Returns a list of tags that apply to @iter, in ascending order of
1318 * priority (highest-priority tags are last). The #GtkTextTag in the
1319 * list don't have a reference added, but you have to free the list
1322 * Return value: list of #GtkTextTag
1325 gtk_text_iter_get_tags (const GtkTextIter *iter)
1332 g_return_val_if_fail (iter != NULL, NULL);
1334 /* Get the tags at this spot */
1335 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1337 /* No tags, use default style */
1338 if (tags == NULL || tag_count == 0)
1346 /* Sort tags in ascending order of priority */
1347 _gtk_text_tag_array_sort (tags, tag_count);
1351 while (i < tag_count)
1353 retval = g_slist_prepend (retval, tags[i]);
1359 /* Return tags in ascending order of priority */
1360 return g_slist_reverse (retval);
1364 * gtk_text_iter_editable:
1365 * @iter: an iterator
1366 * @default_setting: %TRUE if text is editable by default
1368 * Returns whether the character at @iter is within an editable region
1369 * of text. Non-editable text is "locked" and can't be changed by the
1370 * user via #GtkTextView. This function is simply a convenience
1371 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1372 * to this text affect editability, @default_setting will be returned.
1374 * You don't want to use this function to decide whether text can be
1375 * inserted at @iter, because for insertion you don't want to know
1376 * whether the char at @iter is inside an editable range, you want to
1377 * know whether a new character inserted at @iter would be inside an
1378 * editable range. Use gtk_text_iter_can_insert() to handle this
1381 * Return value: whether @iter is inside an editable range
1384 gtk_text_iter_editable (const GtkTextIter *iter,
1385 gboolean default_setting)
1387 GtkTextAttributes *values;
1390 g_return_val_if_fail (iter != NULL, FALSE);
1392 values = gtk_text_attributes_new ();
1394 values->editable = default_setting;
1396 gtk_text_iter_get_attributes (iter, values);
1398 retval = values->editable;
1400 gtk_text_attributes_unref (values);
1406 * gtk_text_iter_can_insert:
1407 * @iter: an iterator
1408 * @default_editability: %TRUE if text is editable by default
1410 * Considering the default editability of the buffer, and tags that
1411 * affect editability, determines whether text inserted at @iter would
1412 * be editable. If text inserted at @iter would be editable then the
1413 * user should be allowed to insert text at @iter.
1414 * gtk_text_buffer_insert_interactive() uses this function to decide
1415 * whether insertions are allowed at a given position.
1417 * Return value: whether text inserted at @iter would be editable
1420 gtk_text_iter_can_insert (const GtkTextIter *iter,
1421 gboolean default_editability)
1423 g_return_val_if_fail (iter != NULL, FALSE);
1425 if (gtk_text_iter_editable (iter, default_editability))
1427 /* If at start/end of buffer, default editability is used */
1428 else if ((gtk_text_iter_is_start (iter) ||
1429 gtk_text_iter_is_end (iter)) &&
1430 default_editability)
1434 /* if iter isn't editable, and the char before iter is,
1435 * then iter is the first char in an editable region
1436 * and thus insertion at iter results in editable text.
1438 GtkTextIter prev = *iter;
1439 gtk_text_iter_backward_char (&prev);
1440 return gtk_text_iter_editable (&prev, default_editability);
1446 * gtk_text_iter_get_language:
1447 * @iter: an iterator
1449 * A convenience wrapper around gtk_text_iter_get_attributes (),
1450 * which returns the language in effect at @iter. If no tags affecting
1451 * language apply to @iter, the return value is identical to that of
1452 * gtk_get_default_language ().
1454 * Return value: language in effect at @iter
1457 gtk_text_iter_get_language (const GtkTextIter *iter)
1459 GtkTextAttributes *values;
1460 PangoLanguage *retval;
1462 values = gtk_text_attributes_new ();
1464 gtk_text_iter_get_attributes (iter, values);
1466 retval = values->language;
1468 gtk_text_attributes_unref (values);
1474 * gtk_text_iter_starts_line:
1475 * @iter: an iterator
1477 * Returns %TRUE if @iter begins a paragraph,
1478 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1479 * However this function is potentially more efficient than
1480 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1481 * the offset, it just has to see whether it's 0.
1483 * Return value: whether @iter begins a line
1486 gtk_text_iter_starts_line (const GtkTextIter *iter)
1488 GtkTextRealIter *real;
1490 g_return_val_if_fail (iter != NULL, FALSE);
1492 real = gtk_text_iter_make_surreal (iter);
1497 check_invariants (iter);
1499 if (real->line_byte_offset >= 0)
1501 return (real->line_byte_offset == 0);
1505 g_assert (real->line_char_offset >= 0);
1506 return (real->line_char_offset == 0);
1511 * gtk_text_iter_ends_line:
1512 * @iter: an iterator
1514 * Returns %TRUE if @iter points to the start of the paragraph delimiter
1515 * characters for a line (delimiters will be either a newline, a
1516 * carriage return, a carriage return followed by a newline, or a
1517 * Unicode paragraph separator character). Note that an iterator pointing
1518 * to the \n of a \r\n pair will not be counted as the end of a line,
1519 * the line ends before the \r.
1521 * Return value: whether @iter is at the end of a line
1524 gtk_text_iter_ends_line (const GtkTextIter *iter)
1526 GtkTextRealIter *real;
1529 g_return_val_if_fail (iter != NULL, FALSE);
1531 real = gtk_text_iter_make_real (iter);
1533 check_invariants (iter);
1535 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1536 * Unicode 3.0; update this if that changes.
1538 #define PARAGRAPH_SEPARATOR 0x2029
1540 wc = gtk_text_iter_get_char (iter);
1542 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR)
1544 else if (wc == '\n')
1546 /* need to determine if a \r precedes the \n, in which case
1547 * we aren't the end of the line
1549 GtkTextIter tmp = *iter;
1550 if (!gtk_text_iter_backward_char (&tmp))
1553 return gtk_text_iter_get_char (&tmp) != '\r';
1560 * gtk_text_iter_is_end:
1561 * @iter: an iterator
1563 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1564 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1565 * the most efficient way to check whether an iterator is the end
1568 * Return value: whether @iter is the end iterator
1571 gtk_text_iter_is_end (const GtkTextIter *iter)
1573 GtkTextRealIter *real;
1575 g_return_val_if_fail (iter != NULL, FALSE);
1577 real = gtk_text_iter_make_surreal (iter);
1582 check_invariants (iter);
1584 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1587 /* Now we need the segments validated */
1588 real = gtk_text_iter_make_real (iter);
1593 return _gtk_text_btree_is_end (real->tree, real->line,
1595 real->segment_byte_offset,
1596 real->segment_char_offset);
1600 * gtk_text_iter_is_start:
1601 * @iter: an iterator
1603 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1604 * if @iter has a character offset of 0.
1606 * Return value: whether @iter is the first in the buffer
1609 gtk_text_iter_is_start (const GtkTextIter *iter)
1611 return gtk_text_iter_get_offset (iter) == 0;
1615 * gtk_text_iter_get_chars_in_line:
1616 * @iter: an iterator
1618 * Returns the number of characters in the line containing @iter,
1619 * including the paragraph delimiters.
1621 * Return value: number of characters in the line
1624 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1626 GtkTextRealIter *real;
1628 GtkTextLineSegment *seg;
1630 g_return_val_if_fail (iter != NULL, FALSE);
1632 real = gtk_text_iter_make_surreal (iter);
1637 check_invariants (iter);
1639 if (real->line_char_offset >= 0)
1641 /* We can start at the segments we've already found. */
1642 count = real->line_char_offset - real->segment_char_offset;
1643 seg = _gtk_text_iter_get_indexable_segment (iter);
1647 /* count whole line. */
1648 seg = real->line->segments;
1655 count += seg->char_count;
1660 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1661 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1667 * gtk_text_iter_get_bytes_in_line:
1668 * @iter: an iterator
1670 * Returns the number of bytes in the line containing @iter,
1671 * including the paragraph delimiters.
1673 * Return value: number of bytes in the line
1676 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1678 GtkTextRealIter *real;
1680 GtkTextLineSegment *seg;
1682 g_return_val_if_fail (iter != NULL, FALSE);
1684 real = gtk_text_iter_make_surreal (iter);
1689 check_invariants (iter);
1691 if (real->line_byte_offset >= 0)
1693 /* We can start at the segments we've already found. */
1694 count = real->line_byte_offset - real->segment_byte_offset;
1695 seg = _gtk_text_iter_get_indexable_segment (iter);
1699 /* count whole line. */
1700 seg = real->line->segments;
1706 count += seg->byte_count;
1711 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1712 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1718 * gtk_text_iter_get_attributes:
1719 * @iter: an iterator
1720 * @values: a #GtkTextAttributes to be filled in
1722 * Computes the effect of any tags applied to this spot in the
1723 * text. The @values parameter should be initialized to the default
1724 * settings you wish to use if no tags are in effect. You'd typically
1725 * obtain the defaults from gtk_text_view_get_default_attributes().
1727 * gtk_text_iter_get_attributes () will modify @values, applying the
1728 * effects of any tags present at @iter. If any tags affected @values,
1729 * the function returns %TRUE.
1731 * Return value: %TRUE if @values was modified
1734 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1735 GtkTextAttributes *values)
1740 /* Get the tags at this spot */
1741 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1743 /* No tags, use default style */
1744 if (tags == NULL || tag_count == 0)
1752 /* Sort tags in ascending order of priority */
1753 _gtk_text_tag_array_sort (tags, tag_count);
1755 _gtk_text_attributes_fill_from_tags (values,
1765 * Increments/decrements
1768 /* The return value of this indicates WHETHER WE MOVED.
1769 * The return value of public functions indicates
1770 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1772 * This function will not change the iterator if
1773 * it's already on the last (end iter) line, i.e. it
1774 * won't move to the end of the last line.
1777 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1779 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1781 GtkTextLine *new_line;
1783 new_line = _gtk_text_line_next (real->line);
1784 g_assert (new_line);
1785 g_assert (new_line != real->line);
1786 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1788 real->line = new_line;
1790 real->line_byte_offset = 0;
1791 real->line_char_offset = 0;
1793 real->segment_byte_offset = 0;
1794 real->segment_char_offset = 0;
1796 /* Find first segments in new line */
1797 real->any_segment = real->line->segments;
1798 real->segment = real->any_segment;
1799 while (real->segment->char_count == 0)
1800 real->segment = real->segment->next;
1806 /* There is no way to move forward a line; we were already at
1807 * the line containing the end iterator.
1808 * However we may not be at the end iterator itself.
1816 /* The return value of this indicates WHETHER WE MOVED.
1817 * The return value of public functions indicates
1818 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1821 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1823 GtkTextLine *new_line;
1825 new_line = _gtk_text_line_previous (real->line);
1827 g_assert (new_line != real->line);
1829 if (new_line != NULL)
1831 real->line = new_line;
1833 real->line_byte_offset = 0;
1834 real->line_char_offset = 0;
1836 real->segment_byte_offset = 0;
1837 real->segment_char_offset = 0;
1839 /* Find first segments in new line */
1840 real->any_segment = real->line->segments;
1841 real->segment = real->any_segment;
1842 while (real->segment->char_count == 0)
1843 real->segment = real->segment->next;
1849 /* There is no way to move backward; we were already
1850 at the first line. */
1852 /* We leave real->line as-is */
1854 /* Note that we didn't clamp to the start of the first line. */
1860 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1864 forward_char (GtkTextRealIter *real)
1866 GtkTextIter *iter = (GtkTextIter*)real;
1868 check_invariants ((GtkTextIter*)real);
1870 ensure_char_offsets (real);
1872 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1874 /* Need to move to the next segment; if no next segment,
1875 need to move to next line. */
1876 return _gtk_text_iter_forward_indexable_segment (iter);
1880 /* Just moving within a segment. Keep byte count
1881 up-to-date, if it was already up-to-date. */
1883 g_assert (real->segment->type == >k_text_char_type);
1885 if (real->line_byte_offset >= 0)
1888 const char * start =
1889 real->segment->body.chars + real->segment_byte_offset;
1891 bytes = g_utf8_next_char (start) - start;
1893 real->line_byte_offset += bytes;
1894 real->segment_byte_offset += bytes;
1896 g_assert (real->segment_byte_offset < real->segment->byte_count);
1899 real->line_char_offset += 1;
1900 real->segment_char_offset += 1;
1902 adjust_char_index (real, 1);
1904 g_assert (real->segment_char_offset < real->segment->char_count);
1906 /* We moved into the middle of a segment, so the any_segment
1907 must now be the segment we're in the middle of. */
1908 real->any_segment = real->segment;
1910 check_invariants ((GtkTextIter*)real);
1912 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1920 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1922 /* Need to move to the next segment; if no next segment,
1923 need to move to next line. */
1924 GtkTextLineSegment *seg;
1925 GtkTextLineSegment *any_seg;
1926 GtkTextRealIter *real;
1930 g_return_val_if_fail (iter != NULL, FALSE);
1932 real = gtk_text_iter_make_real (iter);
1937 check_invariants (iter);
1939 if (real->line_char_offset >= 0)
1941 chars_skipped = real->segment->char_count - real->segment_char_offset;
1942 g_assert (chars_skipped > 0);
1947 if (real->line_byte_offset >= 0)
1949 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1950 g_assert (bytes_skipped > 0);
1955 /* Get first segment of any kind */
1956 any_seg = real->segment->next;
1957 /* skip non-indexable segments, if any */
1959 while (seg != NULL && seg->char_count == 0)
1964 real->any_segment = any_seg;
1965 real->segment = seg;
1967 if (real->line_byte_offset >= 0)
1969 g_assert (bytes_skipped > 0);
1970 real->segment_byte_offset = 0;
1971 real->line_byte_offset += bytes_skipped;
1974 if (real->line_char_offset >= 0)
1976 g_assert (chars_skipped > 0);
1977 real->segment_char_offset = 0;
1978 real->line_char_offset += chars_skipped;
1979 adjust_char_index (real, chars_skipped);
1982 check_invariants (iter);
1984 return !gtk_text_iter_is_end (iter);
1988 /* End of the line */
1989 if (forward_line_leaving_caches_unmodified (real))
1991 adjust_line_number (real, 1);
1992 if (real->line_char_offset >= 0)
1993 adjust_char_index (real, chars_skipped);
1995 g_assert (real->line_byte_offset == 0);
1996 g_assert (real->line_char_offset == 0);
1997 g_assert (real->segment_byte_offset == 0);
1998 g_assert (real->segment_char_offset == 0);
1999 g_assert (gtk_text_iter_starts_line (iter));
2001 check_invariants (iter);
2003 return !gtk_text_iter_is_end (iter);
2009 check_invariants (iter);
2011 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2012 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2013 if (!gtk_text_iter_is_end (iter))
2014 _gtk_text_btree_spew (_gtk_text_iter_get_btree (iter));
2015 g_assert (gtk_text_iter_is_end (iter));
2023 at_last_indexable_segment (GtkTextRealIter *real)
2025 GtkTextLineSegment *seg;
2027 /* Return TRUE if there are no indexable segments after
2031 seg = real->segment->next;
2034 if (seg->char_count > 0)
2041 /* Goes back to the start of the next segment, even if
2042 * we're not at the start of the current segment (always
2043 * ends up on a different segment if it returns TRUE)
2046 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2048 /* Move to the start of the previous segment; if no previous
2049 * segment, to the last segment in the previous line. This is
2050 * inherently a bit inefficient due to the singly-linked list and
2051 * tree nodes, but we can't afford the RAM for doubly-linked.
2053 GtkTextRealIter *real;
2054 GtkTextLineSegment *seg;
2055 GtkTextLineSegment *any_seg;
2056 GtkTextLineSegment *prev_seg;
2057 GtkTextLineSegment *prev_any_seg;
2061 g_return_val_if_fail (iter != NULL, FALSE);
2063 real = gtk_text_iter_make_real (iter);
2068 check_invariants (iter);
2070 /* Find first segments in line */
2071 any_seg = real->line->segments;
2073 while (seg->char_count == 0)
2076 if (seg == real->segment)
2078 /* Could probably do this case faster by hand-coding the
2082 /* We were already at the start of a line;
2083 * go back to the previous line.
2085 if (gtk_text_iter_backward_line (iter))
2087 /* Go forward to last indexable segment in line. */
2088 while (!at_last_indexable_segment (real))
2089 _gtk_text_iter_forward_indexable_segment (iter);
2091 check_invariants (iter);
2096 return FALSE; /* We were at the start of the first line. */
2099 /* We must be in the middle of a line; so find the indexable
2100 * segment just before our current segment.
2102 g_assert (seg != real->segment);
2103 while (seg != real->segment)
2106 prev_any_seg = any_seg;
2108 any_seg = seg->next;
2110 while (seg->char_count == 0)
2114 g_assert (prev_seg != NULL);
2115 g_assert (prev_any_seg != NULL);
2116 g_assert (prev_seg->char_count > 0);
2118 /* We skipped the entire previous segment, plus any
2119 * chars we were into the current segment.
2121 if (real->segment_byte_offset >= 0)
2122 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2126 if (real->segment_char_offset >= 0)
2127 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2131 real->segment = prev_seg;
2132 real->any_segment = prev_any_seg;
2133 real->segment_byte_offset = 0;
2134 real->segment_char_offset = 0;
2136 if (bytes_skipped >= 0)
2138 if (real->line_byte_offset >= 0)
2140 real->line_byte_offset -= bytes_skipped;
2141 g_assert (real->line_byte_offset >= 0);
2145 real->line_byte_offset = -1;
2147 if (chars_skipped >= 0)
2149 if (real->line_char_offset >= 0)
2151 real->line_char_offset -= chars_skipped;
2152 g_assert (real->line_char_offset >= 0);
2155 if (real->cached_char_index >= 0)
2157 real->cached_char_index -= chars_skipped;
2158 g_assert (real->cached_char_index >= 0);
2163 real->line_char_offset = -1;
2164 real->cached_char_index = -1;
2167 /* line number is unchanged. */
2169 check_invariants (iter);
2175 * gtk_text_iter_forward_char:
2176 * @iter: an iterator
2178 * Moves @iter forward by one character offset. Note that images
2179 * embedded in the buffer occupy 1 character slot, so
2180 * gtk_text_iter_forward_char () may actually move onto an image instead
2181 * of a character, if you have images in your buffer. If @iter is the
2182 * end iterator or one character before it, @iter will now point at
2183 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2184 * convenience when writing loops.
2186 * Return value: whether @iter moved and is dereferenceable
2189 gtk_text_iter_forward_char (GtkTextIter *iter)
2191 GtkTextRealIter *real;
2193 g_return_val_if_fail (iter != NULL, FALSE);
2195 real = gtk_text_iter_make_real (iter);
2201 check_invariants (iter);
2202 return forward_char (real);
2207 * gtk_text_iter_backward_char:
2208 * @iter: an iterator
2210 * Moves backward by one character offset. Returns %TRUE if movement
2211 * was possible; if @iter was the first in the buffer (character
2212 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2215 * Return value: whether movement was possible
2218 gtk_text_iter_backward_char (GtkTextIter *iter)
2220 g_return_val_if_fail (iter != NULL, FALSE);
2222 check_invariants (iter);
2224 return gtk_text_iter_backward_chars (iter, 1);
2228 Definitely we should try to linear scan as often as possible for
2229 movement within a single line, because we can't use the BTree to
2230 speed within-line searches up; for movement between lines, we would
2231 like to avoid the linear scan probably.
2233 Instead of using this constant, it might be nice to cache the line
2234 length in the iterator and linear scan if motion is within a single
2237 I guess you'd have to profile the various approaches.
2239 #define MAX_LINEAR_SCAN 150
2243 * gtk_text_iter_forward_chars:
2244 * @iter: an iterator
2245 * @count: number of characters to move, may be negative
2247 * Moves @count characters if possible (if @count would move past the
2248 * start or end of the buffer, moves to the start or end of the
2249 * buffer). The return value indicates whether the new position of
2250 * @iter is different from its original position, and dereferenceable
2251 * (the last iterator in the buffer is not dereferenceable). If @count
2252 * is 0, the function does nothing and returns %FALSE.
2254 * Return value: whether @iter moved and is dereferenceable
2257 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2259 GtkTextRealIter *real;
2261 g_return_val_if_fail (iter != NULL, FALSE);
2263 FIX_OVERFLOWS (count);
2265 real = gtk_text_iter_make_real (iter);
2269 else if (count == 0)
2272 return gtk_text_iter_backward_chars (iter, 0 - count);
2273 else if (count < MAX_LINEAR_SCAN)
2275 check_invariants (iter);
2279 if (!forward_char (real))
2284 return forward_char (real);
2288 gint current_char_index;
2289 gint new_char_index;
2291 check_invariants (iter);
2293 current_char_index = gtk_text_iter_get_offset (iter);
2295 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2296 return FALSE; /* can't move forward */
2298 new_char_index = current_char_index + count;
2299 gtk_text_iter_set_offset (iter, new_char_index);
2301 check_invariants (iter);
2303 /* Return FALSE if we're on the non-dereferenceable end
2306 if (gtk_text_iter_is_end (iter))
2314 * gtk_text_iter_backward_chars:
2315 * @iter: an iterator
2316 * @count: number of characters to move
2318 * Moves @count characters backward, if possible (if @count would move
2319 * past the start or end of the buffer, moves to the start or end of
2320 * the buffer). The return value indicates whether the iterator moved
2321 * onto a dereferenceable position; if the iterator didn't move, or
2322 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2323 * the function does nothing and returns %FALSE.
2325 * Return value: whether @iter moved and is dereferenceable
2329 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2331 GtkTextRealIter *real;
2333 g_return_val_if_fail (iter != NULL, FALSE);
2335 FIX_OVERFLOWS (count);
2337 real = gtk_text_iter_make_real (iter);
2341 else if (count == 0)
2344 return gtk_text_iter_forward_chars (iter, 0 - count);
2346 ensure_char_offsets (real);
2347 check_invariants (iter);
2349 /* <, not <=, because if count == segment_char_offset
2350 * we're going to the front of the segment and the any_segment
2353 if (count < real->segment_char_offset)
2355 /* Optimize the within-segment case */
2356 g_assert (real->segment->char_count > 0);
2357 g_assert (real->segment->type == >k_text_char_type);
2359 real->segment_char_offset -= count;
2360 g_assert (real->segment_char_offset >= 0);
2362 if (real->line_byte_offset >= 0)
2364 gint new_byte_offset;
2367 new_byte_offset = 0;
2369 while (i < real->segment_char_offset)
2371 const char * start = real->segment->body.chars + new_byte_offset;
2372 new_byte_offset += g_utf8_next_char (start) - start;
2377 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2378 real->segment_byte_offset = new_byte_offset;
2381 real->line_char_offset -= count;
2383 adjust_char_index (real, 0 - count);
2385 check_invariants (iter);
2391 /* We need to go back into previous segments. For now,
2392 * just keep this really simple. FIXME
2393 * use backward_indexable_segment.
2395 if (TRUE || count > MAX_LINEAR_SCAN)
2397 gint current_char_index;
2398 gint new_char_index;
2400 current_char_index = gtk_text_iter_get_offset (iter);
2402 if (current_char_index == 0)
2403 return FALSE; /* can't move backward */
2405 new_char_index = current_char_index - count;
2406 if (new_char_index < 0)
2409 gtk_text_iter_set_offset (iter, new_char_index);
2411 check_invariants (iter);
2417 /* FIXME backward_indexable_segment here */
2426 /* These two can't be implemented efficiently (always have to use
2427 * a linear scan, since that's the only way to find all the non-text
2432 * gtk_text_iter_forward_text_chars:
2433 * @iter: a #GtkTextIter
2434 * @count: number of chars to move
2436 * Moves forward by @count text characters (pixbufs, widgets,
2437 * etc. do not count as characters for this). Equivalent to moving
2438 * through the results of gtk_text_iter_get_text (), rather than
2439 * gtk_text_iter_get_slice ().
2441 * Return value: whether @iter moved and is dereferenceable
2444 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2453 * gtk_text_iter_forward_text_chars:
2454 * @iter: a #GtkTextIter
2455 * @count: number of chars to move
2457 * Moves backward by @count text characters (pixbufs, widgets,
2458 * etc. do not count as characters for this). Equivalent to moving
2459 * through the results of gtk_text_iter_get_text (), rather than
2460 * gtk_text_iter_get_slice ().
2462 * Return value: whether @iter moved and is dereferenceable
2465 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2474 * gtk_text_iter_forward_line:
2475 * @iter: an iterator
2477 * Moves @iter to the start of the next line. Returns %TRUE if there
2478 * was a next line to move to, and %FALSE if @iter was simply moved to
2479 * the end of the buffer and is now not dereferenceable, or if @iter was
2480 * already at the end of the buffer.
2482 * Return value: whether @iter can be dereferenced
2485 gtk_text_iter_forward_line (GtkTextIter *iter)
2487 GtkTextRealIter *real;
2489 g_return_val_if_fail (iter != NULL, FALSE);
2491 real = gtk_text_iter_make_real (iter);
2496 check_invariants (iter);
2498 if (forward_line_leaving_caches_unmodified (real))
2500 invalidate_char_index (real);
2501 adjust_line_number (real, 1);
2503 check_invariants (iter);
2505 if (gtk_text_iter_is_end (iter))
2512 /* On the last line, move to end of it */
2514 if (!gtk_text_iter_is_end (iter))
2515 gtk_text_iter_forward_to_end (iter);
2517 check_invariants (iter);
2523 * gtk_text_iter_backward_line:
2524 * @iter: an iterator
2526 * Moves @iter to the start of the previous line. Returns %TRUE if
2527 * @iter could be moved; i.e. if @iter was at character offset 0, this
2528 * function returns %FALSE. Therefore if @iter was already on line 0,
2529 * but not at the start of the line, @iter is snapped to the start of
2530 * the line and the function returns %TRUE. (Note that this implies that
2531 * in a loop calling this function, the line number may not change on
2532 * every iteration, if your first iteration is on line 0.)
2534 * Return value: whether @iter moved
2537 gtk_text_iter_backward_line (GtkTextIter *iter)
2539 GtkTextLine *new_line;
2540 GtkTextRealIter *real;
2541 gboolean offset_will_change;
2544 g_return_val_if_fail (iter != NULL, FALSE);
2546 real = gtk_text_iter_make_real (iter);
2551 check_invariants (iter);
2553 new_line = _gtk_text_line_previous (real->line);
2555 offset_will_change = FALSE;
2556 if (real->line_char_offset > 0)
2557 offset_will_change = TRUE;
2559 if (new_line != NULL)
2561 real->line = new_line;
2563 adjust_line_number (real, -1);
2567 if (!offset_will_change)
2571 invalidate_char_index (real);
2573 real->line_byte_offset = 0;
2574 real->line_char_offset = 0;
2576 real->segment_byte_offset = 0;
2577 real->segment_char_offset = 0;
2579 /* Find first segment in line */
2580 real->any_segment = real->line->segments;
2581 real->segment = _gtk_text_line_byte_to_segment (real->line,
2584 g_assert (offset == 0);
2586 /* Note that if we are on the first line, we snap to the start of
2587 * the first line and return TRUE, so TRUE means the iterator
2588 * changed, not that the line changed; this is maybe a bit
2589 * weird. I'm not sure there's an obvious right thing to do though.
2592 check_invariants (iter);
2599 * gtk_text_iter_forward_lines:
2600 * @iter: a #GtkTextIter
2601 * @count: number of lines to move forward
2603 * Moves @count lines forward, if possible (if @count would move
2604 * past the start or end of the buffer, moves to the start or end of
2605 * the buffer). The return value indicates whether the iterator moved
2606 * onto a dereferenceable position; if the iterator didn't move, or
2607 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2608 * the function does nothing and returns %FALSE. If @count is negative,
2609 * moves backward by 0 - @count lines.
2611 * Return value: whether @iter moved and is dereferenceable
2614 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2616 FIX_OVERFLOWS (count);
2619 return gtk_text_iter_backward_lines (iter, 0 - count);
2620 else if (count == 0)
2622 else if (count == 1)
2624 check_invariants (iter);
2625 return gtk_text_iter_forward_line (iter);
2631 if (gtk_text_iter_is_end (iter))
2634 old_line = gtk_text_iter_get_line (iter);
2636 gtk_text_iter_set_line (iter, old_line + count);
2638 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2640 /* count went past the last line, so move to end of last line */
2641 if (!gtk_text_iter_is_end (iter))
2642 gtk_text_iter_forward_to_end (iter);
2645 return !gtk_text_iter_is_end (iter);
2650 * gtk_text_iter_backward_lines:
2651 * @iter: a #GtkTextIter
2652 * @count: number of lines to move backward
2654 * Moves @count lines backward, if possible (if @count would move
2655 * past the start or end of the buffer, moves to the start or end of
2656 * the buffer). The return value indicates whether the iterator moved
2657 * onto a dereferenceable position; if the iterator didn't move, or
2658 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2659 * the function does nothing and returns %FALSE. If @count is negative,
2660 * moves forward by 0 - @count lines.
2662 * Return value: whether @iter moved and is dereferenceable
2665 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2667 FIX_OVERFLOWS (count);
2670 return gtk_text_iter_forward_lines (iter, 0 - count);
2671 else if (count == 0)
2673 else if (count == 1)
2675 return gtk_text_iter_backward_line (iter);
2681 old_line = gtk_text_iter_get_line (iter);
2683 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2685 return (gtk_text_iter_get_line (iter) != old_line);
2689 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2694 gboolean already_moved_initially);
2696 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2704 find_word_end_func (const PangoLogAttr *attrs,
2709 gboolean already_moved_initially)
2711 if (!already_moved_initially)
2714 /* Find end of next word */
2715 while (offset < min_offset + len &&
2716 !attrs[offset].is_word_end)
2719 *found_offset = offset;
2721 return offset < min_offset + len;
2725 is_word_end_func (const PangoLogAttr *attrs,
2730 return attrs[offset].is_word_end;
2734 find_word_start_func (const PangoLogAttr *attrs,
2739 gboolean already_moved_initially)
2741 if (!already_moved_initially)
2744 /* Find start of prev word */
2745 while (offset >= min_offset &&
2746 !attrs[offset].is_word_start)
2749 *found_offset = offset;
2751 return offset >= min_offset;
2755 is_word_start_func (const PangoLogAttr *attrs,
2760 return attrs[offset].is_word_start;
2764 inside_word_func (const PangoLogAttr *attrs,
2769 /* Find next word start or end */
2770 while (offset >= min_offset &&
2771 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2774 return attrs[offset].is_word_start;
2777 /* Sentence funcs */
2780 find_sentence_end_func (const PangoLogAttr *attrs,
2785 gboolean already_moved_initially)
2787 if (!already_moved_initially)
2790 /* Find end of next sentence */
2791 while (offset < min_offset + len &&
2792 !attrs[offset].is_sentence_end)
2795 *found_offset = offset;
2797 return offset < min_offset + len;
2801 is_sentence_end_func (const PangoLogAttr *attrs,
2806 return attrs[offset].is_sentence_end;
2810 find_sentence_start_func (const PangoLogAttr *attrs,
2815 gboolean already_moved_initially)
2817 if (!already_moved_initially)
2820 /* Find start of prev sentence */
2821 while (offset >= min_offset &&
2822 !attrs[offset].is_sentence_start)
2825 *found_offset = offset;
2827 return offset >= min_offset;
2831 is_sentence_start_func (const PangoLogAttr *attrs,
2836 return attrs[offset].is_sentence_start;
2840 inside_sentence_func (const PangoLogAttr *attrs,
2845 /* Find next sentence start or end */
2846 while (offset >= min_offset &&
2847 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2850 return attrs[offset].is_sentence_start;
2854 test_log_attrs (const GtkTextIter *iter,
2855 TestLogAttrFunc func)
2858 const PangoLogAttr *attrs;
2860 gboolean result = FALSE;
2862 g_return_val_if_fail (iter != NULL, FALSE);
2864 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2867 offset = gtk_text_iter_get_line_offset (iter);
2869 /* char_len may be 0 and attrs will be NULL if so, if
2870 * iter is the end iter and the last line is empty.
2872 * offset may be equal to char_len, since attrs contains an entry
2873 * for one past the end
2876 if (attrs && offset <= char_len)
2877 result = (* func) (attrs, offset, 0, char_len);
2883 find_line_log_attrs (const GtkTextIter *iter,
2884 FindLogAttrFunc func,
2886 gboolean already_moved_initially)
2889 const PangoLogAttr *attrs;
2891 gboolean result = FALSE;
2893 g_return_val_if_fail (iter != NULL, FALSE);
2895 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2898 offset = gtk_text_iter_get_line_offset (iter);
2900 /* char_len may be 0 and attrs will be NULL if so, if
2901 * iter is the end iter and the last line is empty
2905 result = (* func) (attrs, offset, 0, char_len, found_offset,
2906 already_moved_initially);
2911 /* FIXME this function is very, very gratuitously slow */
2913 find_by_log_attrs (GtkTextIter *iter,
2914 FindLogAttrFunc func,
2916 gboolean already_moved_initially)
2920 gboolean found = FALSE;
2922 g_return_val_if_fail (iter != NULL, FALSE);
2926 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2932 if (gtk_text_iter_forward_line (iter))
2933 return find_by_log_attrs (iter, func, forward,
2940 /* go to end of previous line. need to check that
2941 * line is > 0 because backward_line snaps to start of
2942 * line 0 if it's on line 0
2944 if (gtk_text_iter_get_line (iter) > 0 &&
2945 gtk_text_iter_backward_line (iter))
2947 if (!gtk_text_iter_ends_line (iter))
2948 gtk_text_iter_forward_to_line_end (iter);
2950 return find_by_log_attrs (iter, func, forward,
2959 gtk_text_iter_set_line_offset (iter, offset);
2962 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2963 !gtk_text_iter_is_end (iter);
2968 * gtk_text_iter_forward_word_end:
2969 * @iter: a #GtkTextIter
2971 * Moves forward to the next word end. (If @iter is currently on a
2972 * word end, moves forward to the next one after that.) Word breaks
2973 * are determined by Pango and should be correct for nearly any
2974 * language (if not, the correct fix would be to the Pango word break
2977 * Return value: %TRUE if @iter moved and is not the end iterator
2980 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2982 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2986 * gtk_text_iter_backward_word_start:
2987 * @iter: a #GtkTextIter
2989 * Moves backward to the previous word start. (If @iter is currently on a
2990 * word start, moves backward to the next one after that.) Word breaks
2991 * are determined by Pango and should be correct for nearly any
2992 * language (if not, the correct fix would be to the Pango word break
2995 * Return value: %TRUE if @iter moved and is not the end iterator
2998 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3000 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3003 /* FIXME a loop around a truly slow function means
3004 * a truly spectacularly slow function.
3008 * gtk_text_iter_forward_word_ends:
3009 * @iter: a #GtkTextIter
3010 * @count: number of times to move
3012 * Calls gtk_text_iter_forward_word_end() up to @count times.
3014 * Return value: %TRUE if @iter moved and is not the end iterator
3017 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3020 g_return_val_if_fail (iter != NULL, FALSE);
3022 FIX_OVERFLOWS (count);
3028 return gtk_text_iter_backward_word_starts (iter, -count);
3030 if (!gtk_text_iter_forward_word_end (iter))
3036 if (!gtk_text_iter_forward_word_end (iter))
3041 return !gtk_text_iter_is_end (iter);
3045 * gtk_text_iter_backward_word_starts
3046 * @iter: a #GtkTextIter
3047 * @count: number of times to move
3049 * Calls gtk_text_iter_backward_word_starts() up to @count times.
3051 * Return value: %TRUE if @iter moved and is not the end iterator
3054 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3057 g_return_val_if_fail (iter != NULL, FALSE);
3059 FIX_OVERFLOWS (count);
3062 return gtk_text_iter_forward_word_ends (iter, -count);
3064 if (!gtk_text_iter_backward_word_start (iter))
3070 if (!gtk_text_iter_backward_word_start (iter))
3075 return !gtk_text_iter_is_end (iter);
3079 * gtk_text_iter_starts_word:
3080 * @iter: a #GtkTextIter
3082 * Determines whether @iter begins a natural-language word. Word
3083 * breaks are determined by Pango and should be correct for nearly any
3084 * language (if not, the correct fix would be to the Pango word break
3087 * Return value: %TRUE if @iter is at the start of a word
3090 gtk_text_iter_starts_word (const GtkTextIter *iter)
3092 return test_log_attrs (iter, is_word_start_func);
3096 * gtk_text_iter_ends_word:
3097 * @iter: a #GtkTextIter
3099 * Determines whether @iter ends a natural-language word. Word breaks
3100 * are determined by Pango and should be correct for nearly any
3101 * language (if not, the correct fix would be to the Pango word break
3104 * Return value: %TRUE if @iter is at the end of a word
3107 gtk_text_iter_ends_word (const GtkTextIter *iter)
3109 return test_log_attrs (iter, is_word_end_func);
3113 * gtk_text_iter_inside_word:
3114 * @iter: a #GtkTextIter
3116 * Determines whether @iter is inside a natural-language word (as
3117 * opposed to say inside some whitespace). Word breaks are determined
3118 * by Pango and should be correct for nearly any language (if not, the
3119 * correct fix would be to the Pango word break algorithms).
3121 * Return value: %TRUE if @iter is inside a word
3124 gtk_text_iter_inside_word (const GtkTextIter *iter)
3126 return test_log_attrs (iter, inside_word_func);
3130 * gtk_text_iter_starts_sentence:
3131 * @iter: a #GtkTextIter
3133 * Determines whether @iter begins a sentence. Sentence boundaries are
3134 * determined by Pango and should be correct for nearly any language
3135 * (if not, the correct fix would be to the Pango text boundary
3138 * Return value: %TRUE if @iter is at the start of a sentence.
3141 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3143 return test_log_attrs (iter, is_sentence_start_func);
3147 * gtk_text_iter_ends_sentence:
3148 * @iter: a #GtkTextIter
3150 * Determines whether @iter ends a sentence. Sentence boundaries are
3151 * determined by Pango and should be correct for nearly any language
3152 * (if not, the correct fix would be to the Pango text boundary
3155 * Return value: %TRUE if @iter is at the end of a sentence.
3158 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3160 return test_log_attrs (iter, is_sentence_end_func);
3164 * gtk_text_iter_inside_sentence:
3165 * @iter: a #GtkTextIter
3167 * Determines whether @iter is inside a sentence (as opposed to in
3168 * between two sentences, e.g. after a period and before the first
3169 * letter of the next sentence). Sentence boundaries are determined
3170 * by Pango and should be correct for nearly any language (if not, the
3171 * correct fix would be to the Pango text boundary algorithms).
3173 * Return value: %TRUE if @iter is inside a sentence.
3176 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3178 return test_log_attrs (iter, inside_sentence_func);
3182 * gtk_text_iter_forward_sentence_end:
3183 * @iter: a #GtkTextIter
3185 * Moves forward to the next sentence end. (If @iter is at the end of
3186 * a sentence, moves to the next end of sentence.) Sentence
3187 * boundaries are determined by Pango and should be correct for nearly
3188 * any language (if not, the correct fix would be to the Pango text
3189 * boundary algorithms).
3191 * Return value: %TRUE if @iter moved and is not the end iterator
3194 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3196 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3200 * gtk_text_iter_backward_sentence_start:
3201 * @iter: a #GtkTextIter
3203 * Moves backward to the previous sentence start; if @iter is already at
3204 * the start of a sentence, moves backward to the next one. Sentence
3205 * boundaries are determined by Pango and should be correct for nearly
3206 * any language (if not, the correct fix would be to the Pango text
3207 * boundary algorithms).
3209 * Return value: %TRUE if @iter moved and is not the end iterator
3212 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3214 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3217 /* FIXME a loop around a truly slow function means
3218 * a truly spectacularly slow function.
3221 * gtk_text_iter_forward_sentence_ends:
3222 * @iter: a #GtkTextIter
3223 * @count: number of sentences to move
3225 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3226 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3227 * negative, moves backward instead of forward.
3229 * Return value: %TRUE if @iter moved and is not the end iterator
3232 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3235 g_return_val_if_fail (iter != NULL, FALSE);
3241 return gtk_text_iter_backward_sentence_starts (iter, -count);
3243 if (!gtk_text_iter_forward_sentence_end (iter))
3249 if (!gtk_text_iter_forward_sentence_end (iter))
3254 return !gtk_text_iter_is_end (iter);
3258 * gtk_text_iter_backward_sentence_starts:
3259 * @iter: a #GtkTextIter
3260 * @count: number of sentences to move
3262 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3263 * or until it returns %FALSE. If @count is negative, moves forward
3264 * instead of backward.
3266 * Return value: %TRUE if @iter moved and is not the end iterator
3269 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3272 g_return_val_if_fail (iter != NULL, FALSE);
3275 return gtk_text_iter_forward_sentence_ends (iter, -count);
3277 if (!gtk_text_iter_backward_sentence_start (iter))
3283 if (!gtk_text_iter_backward_sentence_start (iter))
3288 return !gtk_text_iter_is_end (iter);
3292 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3297 gboolean already_moved_initially)
3299 if (!already_moved_initially)
3302 while (offset < (min_offset + len) &&
3303 !attrs[offset].is_cursor_position)
3306 *found_offset = offset;
3308 return offset < (min_offset + len);
3312 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3317 gboolean already_moved_initially)
3319 if (!already_moved_initially)
3322 while (offset > min_offset &&
3323 !attrs[offset].is_cursor_position)
3326 *found_offset = offset;
3328 return offset >= min_offset;
3332 is_cursor_pos_func (const PangoLogAttr *attrs,
3337 return attrs[offset].is_cursor_position;
3341 * gtk_text_iter_forward_cursor_position:
3342 * @iter: a #GtkTextIter
3344 * Moves @iter forward by a single cursor position. Cursor positions
3345 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3346 * surprisingly, there may not be a cursor position between all
3347 * characters. The most common example for European languages would be
3348 * a carriage return/newline sequence. For some Unicode characters,
3349 * the equivalent of say the letter "a" with an accent mark will be
3350 * represented as two characters, first the letter then a "combining
3351 * mark" that causes the accent to be rendered; so the cursor can't go
3352 * between those two characters. See also the #PangoLogAttr structure and
3353 * pango_break() function.
3355 * Return value: %TRUE if we moved and the new position is dereferenceable
3358 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3360 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3364 * gtk_text_iter_backward_cursor_position:
3365 * @iter: a #GtkTextIter
3367 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3369 * Return value: %TRUE if we moved and the new position is dereferenceable
3372 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3374 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3378 * gtk_text_iter_forward_cursor_positions:
3379 * @iter: a #GtkTextIter
3380 * @count: number of positions to move
3382 * Moves up to @count cursor positions. See
3383 * gtk_text_iter_forward_cursor_position() for details.
3385 * Return value: %TRUE if we moved and the new position is dereferenceable
3388 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3391 g_return_val_if_fail (iter != NULL, FALSE);
3393 FIX_OVERFLOWS (count);
3399 return gtk_text_iter_backward_cursor_positions (iter, -count);
3401 if (!gtk_text_iter_forward_cursor_position (iter))
3407 if (!gtk_text_iter_forward_cursor_position (iter))
3412 return !gtk_text_iter_is_end (iter);
3416 * gtk_text_iter_backward_cursor_positions:
3417 * @iter: a #GtkTextIter
3418 * @count: number of positions to move
3420 * Moves up to @count cursor positions. See
3421 * gtk_text_iter_forward_cursor_position() for details.
3423 * Return value: %TRUE if we moved and the new position is dereferenceable
3426 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3429 g_return_val_if_fail (iter != NULL, FALSE);
3431 FIX_OVERFLOWS (count);
3437 return gtk_text_iter_forward_cursor_positions (iter, -count);
3439 if (!gtk_text_iter_backward_cursor_position (iter))
3445 if (!gtk_text_iter_backward_cursor_position (iter))
3450 return !gtk_text_iter_is_end (iter);
3454 * gtk_text_iter_is_cursor_position:
3455 * @iter: a #GtkTextIter
3457 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3458 * pango_break() for details on what a cursor position is.
3460 * Return value: %TRUE if the cursor can be placed at @iter
3463 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3465 return test_log_attrs (iter, is_cursor_pos_func);
3469 * gtk_text_iter_set_line_offset:
3470 * @iter: a #GtkTextIter
3471 * @char_on_line: a character offset relative to the start of @iter's current line
3473 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3474 * (not byte) offset. The given character offset must be less than or
3475 * equal to the number of characters in the line; if equal, @iter
3476 * moves to the start of the next line. See
3477 * gtk_text_iter_set_line_index() if you have a byte index rather than
3478 * a character offset.
3482 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3485 GtkTextRealIter *real;
3488 g_return_if_fail (iter != NULL);
3490 real = gtk_text_iter_make_surreal (iter);
3495 check_invariants (iter);
3497 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3499 g_return_if_fail (char_on_line <= chars_in_line);
3501 if (char_on_line < chars_in_line)
3502 iter_set_from_char_offset (real, real->line, char_on_line);
3504 gtk_text_iter_forward_line (iter); /* set to start of next line */
3506 check_invariants (iter);
3510 * gtk_text_iter_set_line_index:
3511 * @iter: a #GtkTextIter
3512 * @byte_on_line: a byte index relative to the start of @iter's current line
3514 * Same as gtk_text_iter_set_line_offset(), but works with a
3515 * <emphasis>byte</emphasis> index. The given byte index must be at
3516 * the start of a character, it can't be in the middle of a UTF-8
3517 * encoded character.
3521 gtk_text_iter_set_line_index (GtkTextIter *iter,
3524 GtkTextRealIter *real;
3527 g_return_if_fail (iter != NULL);
3529 real = gtk_text_iter_make_surreal (iter);
3534 check_invariants (iter);
3536 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3538 g_return_if_fail (byte_on_line <= bytes_in_line);
3540 if (byte_on_line < bytes_in_line)
3541 iter_set_from_byte_offset (real, real->line, byte_on_line);
3543 gtk_text_iter_forward_line (iter);
3545 if (real->segment->type == >k_text_char_type &&
3546 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3547 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3548 "character; this will crash the text buffer. "
3549 "Byte indexes must refer to the start of a character.",
3550 G_STRLOC, byte_on_line);
3552 check_invariants (iter);
3557 * gtk_text_iter_set_visible_line_offset:
3558 * @iter: a #GtkTextIter
3559 * @char_on_line: a character offset
3561 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3562 * characters, i.e. text with a tag making it invisible is not
3563 * counted in the offset.
3566 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3569 gint chars_seen = 0;
3572 g_return_if_fail (iter != NULL);
3576 /* For now we use a ludicrously slow implementation */
3577 while (chars_seen < char_on_line)
3579 if (!_gtk_text_btree_char_is_invisible (&pos))
3582 if (!gtk_text_iter_forward_char (&pos))
3585 if (chars_seen == char_on_line)
3589 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3592 gtk_text_iter_forward_line (iter);
3596 bytes_in_char (GtkTextIter *iter)
3598 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3602 * gtk_text_iter_set_visible_line_index:
3603 * @iter: a #GtkTextIter
3604 * @byte_on_line: a byte index
3606 * Like gtk_text_iter_set_line_index(), but the index is in visible
3607 * bytes, i.e. text with a tag making it invisible is not counted
3611 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3614 gint bytes_seen = 0;
3617 g_return_if_fail (iter != NULL);
3621 /* For now we use a ludicrously slow implementation */
3622 while (bytes_seen < byte_on_line)
3624 if (!_gtk_text_btree_char_is_invisible (&pos))
3625 bytes_seen += bytes_in_char (&pos);
3627 if (!gtk_text_iter_forward_char (&pos))
3630 if (bytes_seen >= byte_on_line)
3634 if (bytes_seen > byte_on_line)
3635 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3636 "character; this will crash the text buffer. "
3637 "Byte indexes must refer to the start of a character.",
3638 G_STRLOC, byte_on_line);
3640 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3643 gtk_text_iter_forward_line (iter);
3647 * gtk_text_iter_set_line:
3648 * @iter: a #GtkTextIter
3649 * @line_number: line number (counted from 0)
3651 * Moves iterator @iter to the start of the line @line_number. If
3652 * @line_number is negative or larger than the number of lines in the
3653 * buffer, moves @iter to the start of the last line in the buffer.
3657 gtk_text_iter_set_line (GtkTextIter *iter,
3662 GtkTextRealIter *real;
3664 g_return_if_fail (iter != NULL);
3666 real = gtk_text_iter_make_surreal (iter);
3671 check_invariants (iter);
3673 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3675 iter_set_from_char_offset (real, line, 0);
3677 /* We might as well cache this, since we know it. */
3678 real->cached_line_number = real_line;
3680 check_invariants (iter);
3684 * gtk_text_iter_set_offset:
3685 * @iter: a #GtkTextIter
3686 * @char_offset: a character number
3688 * Sets @iter to point to @char_offset. @char_offset counts from the start
3689 * of the entire text buffer, starting with 0.
3692 gtk_text_iter_set_offset (GtkTextIter *iter,
3696 GtkTextRealIter *real;
3698 gint real_char_index;
3700 g_return_if_fail (iter != NULL);
3702 real = gtk_text_iter_make_surreal (iter);
3707 check_invariants (iter);
3709 if (real->cached_char_index >= 0 &&
3710 real->cached_char_index == char_offset)
3713 line = _gtk_text_btree_get_line_at_char (real->tree,
3718 iter_set_from_char_offset (real, line, real_char_index - line_start);
3720 /* Go ahead and cache this since we have it. */
3721 real->cached_char_index = real_char_index;
3723 check_invariants (iter);
3727 * gtk_text_iter_forward_to_end:
3728 * @iter: a #GtkTextIter
3730 * Moves @iter forward to the "end iterator," which points one past the last
3731 * valid character in the buffer. gtk_text_iter_get_char() called on the
3732 * end iterator returns 0, which is convenient for writing loops.
3735 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3737 GtkTextBuffer *buffer;
3738 GtkTextRealIter *real;
3740 g_return_if_fail (iter != NULL);
3742 real = gtk_text_iter_make_surreal (iter);
3747 buffer = _gtk_text_btree_get_buffer (real->tree);
3749 gtk_text_buffer_get_end_iter (buffer, iter);
3752 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3753 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3754 * If all else fails we could cache the para delimiter pos in the iter.
3755 * I think forward_to_line_end() actually gets called fairly often.
3758 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3763 /* if we aren't on the last line, go forward to start of next line, then scan
3764 * back for the delimiters on the previous line
3766 if (gtk_text_iter_forward_line (&end))
3768 gtk_text_iter_backward_char (&end);
3769 while (!gtk_text_iter_ends_line (&end))
3770 gtk_text_iter_backward_char (&end);
3773 return gtk_text_iter_get_line_offset (&end);
3777 * gtk_text_iter_forward_to_line_end:
3778 * @iter: a #GtkTextIter
3780 * Moves the iterator to point to the paragraph delimiter characters,
3781 * which will be either a newline, a carriage return, a carriage
3782 * return/newline in sequence, or the Unicode paragraph separator
3783 * character. If the iterator is already at the paragraph delimiter
3784 * characters, moves to the paragraph delimiter characters for the
3785 * next line. If @iter is on the last line in the buffer, which does
3786 * not end in paragraph delimiters, moves to the end iterator (end of
3787 * the last line), and returns %FALSE.
3789 * Return value: %TRUE if we moved and the new location is not the end iterator
3792 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3794 gint current_offset;
3798 g_return_val_if_fail (iter != NULL, FALSE);
3800 current_offset = gtk_text_iter_get_line_offset (iter);
3801 new_offset = find_paragraph_delimiter_for_line (iter);
3803 if (current_offset < new_offset)
3805 /* Move to end of this line. */
3806 gtk_text_iter_set_line_offset (iter, new_offset);
3811 /* Move to end of next line. */
3812 if (gtk_text_iter_forward_line (iter))
3814 /* We don't want to move past all
3817 if (!gtk_text_iter_ends_line (iter))
3818 gtk_text_iter_forward_to_line_end (iter);
3827 * gtk_text_iter_forward_to_tag_toggle:
3828 * @iter: a #GtkTextIter
3829 * @tag: a #GtkTextTag, or %NULL
3831 * Moves forward to the next toggle (on or off) of the
3832 * #GtkTextTag @tag, or to the next toggle of any tag if
3833 * @tag is %NULL. If no matching tag toggles are found,
3834 * returns %FALSE, otherwise %TRUE. Does not return toggles
3835 * located at @iter, only toggles after @iter. Sets @iter to
3836 * the location of the toggle, or to the end of the buffer
3837 * if no toggle is found.
3839 * Return value: whether we found a tag toggle after @iter
3842 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3845 GtkTextLine *next_line;
3846 GtkTextLine *current_line;
3847 GtkTextRealIter *real;
3849 g_return_val_if_fail (iter != NULL, FALSE);
3851 real = gtk_text_iter_make_real (iter);
3856 check_invariants (iter);
3858 current_line = real->line;
3859 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3862 while (_gtk_text_iter_forward_indexable_segment (iter))
3864 /* If we went forward to a line that couldn't contain a toggle
3865 for the tag, then skip forward to a line that could contain
3866 it. This potentially skips huge hunks of the tree, so we
3867 aren't a purely linear search. */
3868 if (real->line != current_line)
3870 if (next_line == NULL)
3872 /* End of search. Set to end of buffer. */
3873 _gtk_text_btree_get_end_iter (real->tree, iter);
3877 if (real->line != next_line)
3878 iter_set_from_byte_offset (real, next_line, 0);
3880 current_line = real->line;
3881 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3886 if (gtk_text_iter_toggles_tag (iter, tag))
3888 /* If there's a toggle here, it isn't indexable so
3889 any_segment can't be the indexable segment. */
3890 g_assert (real->any_segment != real->segment);
3895 /* Check end iterator for tags */
3896 if (gtk_text_iter_toggles_tag (iter, tag))
3898 /* If there's a toggle here, it isn't indexable so
3899 any_segment can't be the indexable segment. */
3900 g_assert (real->any_segment != real->segment);
3904 /* Reached end of buffer */
3909 * gtk_text_iter_backward_to_tag_toggle:
3910 * @iter: a #GtkTextIter
3911 * @tag: a #GtkTextTag, or %NULL
3913 * Moves backward to the next toggle (on or off) of the
3914 * #GtkTextTag @tag, or to the next toggle of any tag if
3915 * @tag is %NULL. If no matching tag toggles are found,
3916 * returns %FALSE, otherwise %TRUE. Does not return toggles
3917 * located at @iter, only toggles before @iter. Sets @iter
3918 * to the location of the toggle, or the start of the buffer
3919 * if no toggle is found.
3921 * Return value: whether we found a tag toggle before @iter
3924 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3927 GtkTextLine *prev_line;
3928 GtkTextLine *current_line;
3929 GtkTextRealIter *real;
3931 g_return_val_if_fail (iter != NULL, FALSE);
3933 real = gtk_text_iter_make_real (iter);
3938 check_invariants (iter);
3940 current_line = real->line;
3941 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3945 /* If we're at segment start, go to the previous segment;
3946 * if mid-segment, snap to start of current segment.
3948 if (is_segment_start (real))
3950 if (!_gtk_text_iter_backward_indexable_segment (iter))
3955 ensure_char_offsets (real);
3957 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3963 /* If we went backward to a line that couldn't contain a toggle
3964 * for the tag, then skip backward further to a line that
3965 * could contain it. This potentially skips huge hunks of the
3966 * tree, so we aren't a purely linear search.
3968 if (real->line != current_line)
3970 if (prev_line == NULL)
3972 /* End of search. Set to start of buffer. */
3973 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3977 if (real->line != prev_line)
3979 /* Set to last segment in prev_line (could do this
3982 iter_set_from_byte_offset (real, prev_line, 0);
3984 while (!at_last_indexable_segment (real))
3985 _gtk_text_iter_forward_indexable_segment (iter);
3988 current_line = real->line;
3989 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3994 if (gtk_text_iter_toggles_tag (iter, tag))
3996 /* If there's a toggle here, it isn't indexable so
3997 * any_segment can't be the indexable segment.
3999 g_assert (real->any_segment != real->segment);
4003 while (_gtk_text_iter_backward_indexable_segment (iter));
4005 /* Reached front of buffer */
4010 matches_pred (GtkTextIter *iter,
4011 GtkTextCharPredicate pred,
4016 ch = gtk_text_iter_get_char (iter);
4018 return (*pred) (ch, user_data);
4022 * gtk_text_iter_forward_find_char:
4023 * @iter: a #GtkTextIter
4024 * @pred: a function to be called on each character
4025 * @user_data: user data for @pred
4026 * @limit: search limit, or %NULL for none
4028 * Advances @iter, calling @pred on each character. If
4029 * @pred returns %TRUE, returns %TRUE and stops scanning.
4030 * If @pred never returns %TRUE, @iter is set to @limit if
4031 * @limit is non-%NULL, otherwise to the end iterator.
4033 * Return value: whether a match was found
4036 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4037 GtkTextCharPredicate pred,
4039 const GtkTextIter *limit)
4041 g_return_val_if_fail (iter != NULL, FALSE);
4042 g_return_val_if_fail (pred != NULL, FALSE);
4045 gtk_text_iter_compare (iter, limit) >= 0)
4048 while ((limit == NULL ||
4049 !gtk_text_iter_equal (limit, iter)) &&
4050 gtk_text_iter_forward_char (iter))
4052 if (matches_pred (iter, pred, user_data))
4060 * gtk_text_iter_backward_find_char:
4061 * @iter: a #GtkTextIter
4062 * @pred: function to be called on each character
4063 * @user_data: user data for @pred
4064 * @limit: search limit, or %NULL for none
4066 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4068 * Return value: whether a match was found
4071 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4072 GtkTextCharPredicate pred,
4074 const GtkTextIter *limit)
4076 g_return_val_if_fail (iter != NULL, FALSE);
4077 g_return_val_if_fail (pred != NULL, FALSE);
4080 gtk_text_iter_compare (iter, limit) <= 0)
4083 while ((limit == NULL ||
4084 !gtk_text_iter_equal (limit, iter)) &&
4085 gtk_text_iter_backward_char (iter))
4087 if (matches_pred (iter, pred, user_data))
4095 forward_chars_with_skipping (GtkTextIter *iter,
4097 gboolean skip_invisible,
4098 gboolean skip_nontext)
4103 g_return_if_fail (count >= 0);
4109 gboolean ignored = FALSE;
4112 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4117 _gtk_text_btree_char_is_invisible (iter))
4120 gtk_text_iter_forward_char (iter);
4128 lines_match (const GtkTextIter *start,
4129 const gchar **lines,
4130 gboolean visible_only,
4132 GtkTextIter *match_start,
4133 GtkTextIter *match_end)
4140 if (*lines == NULL || **lines == '\0')
4143 *match_start = *start;
4146 *match_end = *start;
4151 gtk_text_iter_forward_line (&next);
4153 /* No more text in buffer, but *lines is nonempty */
4154 if (gtk_text_iter_equal (start, &next))
4162 line_text = gtk_text_iter_get_visible_slice (start, &next);
4164 line_text = gtk_text_iter_get_slice (start, &next);
4169 line_text = gtk_text_iter_get_visible_text (start, &next);
4171 line_text = gtk_text_iter_get_text (start, &next);
4174 if (match_start) /* if this is the first line we're matching */
4175 found = strstr (line_text, *lines);
4178 /* If it's not the first line, we have to match from the
4179 * start of the line.
4181 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4193 /* Get offset to start of search string */
4194 offset = g_utf8_strlen (line_text, found - line_text);
4198 /* If match start needs to be returned, set it to the
4199 * start of the search string.
4203 *match_start = next;
4205 forward_chars_with_skipping (match_start, offset,
4206 visible_only, !slice);
4209 /* Go to end of search string */
4210 offset += g_utf8_strlen (*lines, -1);
4212 forward_chars_with_skipping (&next, offset,
4213 visible_only, !slice);
4222 /* pass NULL for match_start, since we don't need to find the
4225 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4228 /* strsplit () that retains the delimiter as part of the string. */
4230 strbreakup (const char *string,
4231 const char *delimiter,
4234 GSList *string_list = NULL, *slist;
4235 gchar **str_array, *s;
4238 g_return_val_if_fail (string != NULL, NULL);
4239 g_return_val_if_fail (delimiter != NULL, NULL);
4242 max_tokens = G_MAXINT;
4244 s = strstr (string, delimiter);
4247 guint delimiter_len = strlen (delimiter);
4254 len = s - string + delimiter_len;
4255 new_string = g_new (gchar, len + 1);
4256 strncpy (new_string, string, len);
4257 new_string[len] = 0;
4258 string_list = g_slist_prepend (string_list, new_string);
4260 string = s + delimiter_len;
4261 s = strstr (string, delimiter);
4263 while (--max_tokens && s);
4268 string_list = g_slist_prepend (string_list, g_strdup (string));
4271 str_array = g_new (gchar*, n);
4275 str_array[i--] = NULL;
4276 for (slist = string_list; slist; slist = slist->next)
4277 str_array[i--] = slist->data;
4279 g_slist_free (string_list);
4285 * gtk_text_iter_forward_search:
4286 * @iter: start of search
4287 * @str: a search string
4288 * @flags: flags affecting how the search is done
4289 * @match_start: return location for start of match, or %NULL
4290 * @match_end: return location for end of match, or %NULL
4291 * @limit: bound for the search, or %NULL for the end of the buffer
4293 * Searches forward for @str. Any match is returned as the range
4294 * @match_start, @match_end. The search will not continue past
4295 * @limit. Note that a search is a linear or O(n) operation, so you
4296 * may wish to use @limit to avoid locking up your UI on large
4299 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4300 * have invisible text interspersed in @str. i.e. @str will be a
4301 * possibly-noncontiguous subsequence of the matched range. similarly,
4302 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4303 * pixbufs or child widgets mixed inside the matched range. If these
4304 * flags are not given, the match must be exact; the special 0xFFFC
4305 * character in @str will match embedded pixbufs or child widgets.
4307 * Return value: whether a match was found
4310 gtk_text_iter_forward_search (const GtkTextIter *iter,
4312 GtkTextSearchFlags flags,
4313 GtkTextIter *match_start,
4314 GtkTextIter *match_end,
4315 const GtkTextIter *limit)
4317 gchar **lines = NULL;
4319 gboolean retval = FALSE;
4321 gboolean visible_only;
4324 g_return_val_if_fail (iter != NULL, FALSE);
4325 g_return_val_if_fail (str != NULL, FALSE);
4328 gtk_text_iter_compare (iter, limit) >= 0)
4333 /* If we can move one char, return the empty string there */
4336 if (gtk_text_iter_forward_char (&match))
4339 gtk_text_iter_equal (&match, limit))
4343 *match_start = match;
4352 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4353 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4355 /* locate all lines */
4357 lines = strbreakup (str, "\n", -1);
4363 /* This loop has an inefficient worst-case, where
4364 * gtk_text_iter_get_text () is called repeatedly on
4370 gtk_text_iter_compare (&search, limit) >= 0)
4373 if (lines_match (&search, (const gchar**)lines,
4374 visible_only, slice, &match, &end))
4376 if (limit == NULL ||
4378 gtk_text_iter_compare (&end, limit) < 0))
4383 *match_start = match;
4392 while (gtk_text_iter_forward_line (&search));
4394 g_strfreev ((gchar**)lines);
4400 vectors_equal_ignoring_trailing (gchar **vec1,
4403 /* Ignores trailing chars in vec2's last line */
4412 if (strcmp (*i1, *i2) != 0)
4414 if (*(i2 + 1) == NULL) /* if this is the last line */
4416 gint len1 = strlen (*i1);
4417 gint len2 = strlen (*i2);
4420 strncmp (*i1, *i2, len1) == 0)
4422 /* We matched ignoring the trailing stuff in vec2 */
4447 typedef struct _LinesWindow LinesWindow;
4453 GtkTextIter first_line_start;
4454 GtkTextIter first_line_end;
4456 gboolean visible_only;
4460 lines_window_init (LinesWindow *win,
4461 const GtkTextIter *start)
4464 GtkTextIter line_start;
4465 GtkTextIter line_end;
4467 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4470 if (gtk_text_iter_is_start (start) ||
4471 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4473 /* Already at the end, or not enough lines to match */
4474 win->lines = g_new0 (gchar*, 1);
4479 line_start = *start;
4482 /* Move to start iter to start of line */
4483 gtk_text_iter_set_line_offset (&line_start, 0);
4485 if (gtk_text_iter_equal (&line_start, &line_end))
4487 /* we were already at the start; so go back one line */
4488 gtk_text_iter_backward_line (&line_start);
4491 win->first_line_start = line_start;
4492 win->first_line_end = line_end;
4494 win->lines = g_new0 (gchar*, win->n_lines + 1);
4496 i = win->n_lines - 1;
4503 if (win->visible_only)
4504 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4506 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4510 if (win->visible_only)
4511 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4513 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4516 win->lines[i] = line_text;
4518 line_end = line_start;
4519 gtk_text_iter_backward_line (&line_start);
4526 lines_window_back (LinesWindow *win)
4528 GtkTextIter new_start;
4531 new_start = win->first_line_start;
4533 if (!gtk_text_iter_backward_line (&new_start))
4537 win->first_line_start = new_start;
4538 win->first_line_end = new_start;
4540 gtk_text_iter_forward_line (&win->first_line_end);
4545 if (win->visible_only)
4546 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4547 &win->first_line_end);
4549 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4550 &win->first_line_end);
4554 if (win->visible_only)
4555 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4556 &win->first_line_end);
4558 line_text = gtk_text_iter_get_text (&win->first_line_start,
4559 &win->first_line_end);
4562 /* Move lines to make room for first line. */
4563 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4565 *win->lines = line_text;
4567 /* Free old last line and NULL-terminate */
4568 g_free (win->lines[win->n_lines]);
4569 win->lines[win->n_lines] = NULL;
4575 lines_window_free (LinesWindow *win)
4577 g_strfreev (win->lines);
4581 my_strrstr (const gchar *haystack,
4582 const gchar *needle)
4584 /* FIXME GLib should have a nice implementation in it, this
4588 gint haystack_len = strlen (haystack);
4589 gint needle_len = strlen (needle);
4590 const gchar *needle_end = needle + needle_len;
4591 const gchar *haystack_rend = haystack - 1;
4592 const gchar *needle_rend = needle - 1;
4595 p = haystack + haystack_len;
4596 while (p != haystack)
4598 const gchar *n = needle_end - 1;
4599 const gchar *s = p - 1;
4600 while (s != haystack_rend &&
4608 if (n == needle_rend)
4618 * gtk_text_iter_backward_search:
4619 * @iter: a #GtkTextIter where the search begins
4620 * @str: search string
4621 * @flags: bitmask of flags affecting the search
4622 * @match_start: return location for start of match, or %NULL
4623 * @match_end: return location for end of match, or %NULL
4624 * @limit: location of last possible @match_start, or %NULL for start of buffer
4626 * Same as gtk_text_iter_forward_search(), but moves backward.
4628 * Return value: whether a match was found
4631 gtk_text_iter_backward_search (const GtkTextIter *iter,
4633 GtkTextSearchFlags flags,
4634 GtkTextIter *match_start,
4635 GtkTextIter *match_end,
4636 const GtkTextIter *limit)
4638 gchar **lines = NULL;
4642 gboolean retval = FALSE;
4643 gboolean visible_only;
4646 g_return_val_if_fail (iter != NULL, FALSE);
4647 g_return_val_if_fail (str != NULL, FALSE);
4650 gtk_text_iter_compare (limit, iter) > 0)
4655 /* If we can move one char, return the empty string there */
4656 GtkTextIter match = *iter;
4658 if (limit && gtk_text_iter_equal (limit, &match))
4661 if (gtk_text_iter_backward_char (&match))
4664 *match_start = match;
4673 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4674 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4676 /* locate all lines */
4678 lines = strbreakup (str, "\n", -1);
4688 win.n_lines = n_lines;
4690 win.visible_only = visible_only;
4692 lines_window_init (&win, iter);
4694 if (*win.lines == NULL)
4699 gchar *first_line_match;
4702 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4704 /* We're now before the search limit, abort. */
4708 /* If there are multiple lines, the first line will
4709 * end in '\n', so this will only match at the
4710 * end of the first line, which is correct.
4712 first_line_match = my_strrstr (*win.lines, *lines);
4714 if (first_line_match &&
4715 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4720 GtkTextIter start_tmp;
4722 /* Offset to start of search string */
4723 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4725 next = win.first_line_start;
4727 forward_chars_with_skipping (&start_tmp, offset,
4728 visible_only, !slice);
4731 gtk_text_iter_compare (limit, &start_tmp) > 0)
4732 goto out; /* match was bogus */
4735 *match_start = start_tmp;
4737 /* Go to end of search string */
4741 offset += g_utf8_strlen (*l, -1);
4745 forward_chars_with_skipping (&next, offset,
4746 visible_only, !slice);
4755 while (lines_window_back (&win));
4758 lines_window_free (&win);
4769 * gtk_text_iter_equal:
4770 * @lhs: a #GtkTextIter
4771 * @rhs: another #GtkTextIter
4773 * Tests whether two iterators are equal, using the fastest possible
4774 * mechanism. This function is very fast; you can expect it to perform
4775 * better than e.g. getting the character offset for each iterator and
4776 * comparing the offsets yourself. Also, it's a bit faster than
4777 * gtk_text_iter_compare().
4779 * Return value: %TRUE if the iterators point to the same place in the buffer
4782 gtk_text_iter_equal (const GtkTextIter *lhs,
4783 const GtkTextIter *rhs)
4785 GtkTextRealIter *real_lhs;
4786 GtkTextRealIter *real_rhs;
4788 real_lhs = (GtkTextRealIter*)lhs;
4789 real_rhs = (GtkTextRealIter*)rhs;
4791 check_invariants (lhs);
4792 check_invariants (rhs);
4794 if (real_lhs->line != real_rhs->line)
4796 else if (real_lhs->line_byte_offset >= 0 &&
4797 real_rhs->line_byte_offset >= 0)
4798 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4801 /* the ensure_char_offsets () calls do nothing if the char offsets
4802 are already up-to-date. */
4803 ensure_char_offsets (real_lhs);
4804 ensure_char_offsets (real_rhs);
4805 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4810 * gtk_text_iter_compare:
4811 * @lhs: a #GtkTextIter
4812 * @rhs: another #GtkTextIter
4814 * A qsort()-style function that returns negative if @lhs is less than
4815 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4816 * Ordering is in character offset order, i.e. the first character in the buffer
4817 * is less than the second character in the buffer.
4819 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4822 gtk_text_iter_compare (const GtkTextIter *lhs,
4823 const GtkTextIter *rhs)
4825 GtkTextRealIter *real_lhs;
4826 GtkTextRealIter *real_rhs;
4828 real_lhs = gtk_text_iter_make_surreal (lhs);
4829 real_rhs = gtk_text_iter_make_surreal (rhs);
4831 if (real_lhs == NULL ||
4833 return -1; /* why not */
4835 check_invariants (lhs);
4836 check_invariants (rhs);
4838 if (real_lhs->line == real_rhs->line)
4840 gint left_index, right_index;
4842 if (real_lhs->line_byte_offset >= 0 &&
4843 real_rhs->line_byte_offset >= 0)
4845 left_index = real_lhs->line_byte_offset;
4846 right_index = real_rhs->line_byte_offset;
4850 /* the ensure_char_offsets () calls do nothing if
4851 the offsets are already up-to-date. */
4852 ensure_char_offsets (real_lhs);
4853 ensure_char_offsets (real_rhs);
4854 left_index = real_lhs->line_char_offset;
4855 right_index = real_rhs->line_char_offset;
4858 if (left_index < right_index)
4860 else if (left_index > right_index)
4869 line1 = gtk_text_iter_get_line (lhs);
4870 line2 = gtk_text_iter_get_line (rhs);
4873 else if (line1 > line2)
4881 * gtk_text_iter_in_range:
4882 * @iter: a #GtkTextIter
4883 * @start: start of range
4884 * @end: end of range
4886 * Checks whether @iter falls in the range [@start, @end).
4887 * @start and @end must be in ascending order.
4889 * Return value: %TRUE if @iter is in the range
4892 gtk_text_iter_in_range (const GtkTextIter *iter,
4893 const GtkTextIter *start,
4894 const GtkTextIter *end)
4896 g_return_val_if_fail (iter != NULL, FALSE);
4897 g_return_val_if_fail (start != NULL, FALSE);
4898 g_return_val_if_fail (end != NULL, FALSE);
4899 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4901 return gtk_text_iter_compare (iter, start) >= 0 &&
4902 gtk_text_iter_compare (iter, end) < 0;
4906 * gtk_text_iter_order:
4907 * @first: a #GtkTextIter
4908 * @second: another #GtkTextIter
4910 * Swaps the value of @first and @second if @second comes before
4911 * @first in the buffer. That is, ensures that @first and @second are
4912 * in sequence. Most text buffer functions that take a range call this
4913 * automatically on your behalf, so there's no real reason to call it yourself
4914 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4915 * that expect a pre-sorted range.
4919 gtk_text_iter_order (GtkTextIter *first,
4920 GtkTextIter *second)
4922 g_return_if_fail (first != NULL);
4923 g_return_if_fail (second != NULL);
4925 if (gtk_text_iter_compare (first, second) > 0)
4936 * Init iterators from the BTree
4940 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4944 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4945 gint real_char_index;
4949 g_return_if_fail (iter != NULL);
4950 g_return_if_fail (tree != NULL);
4952 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4953 &line_start, &real_char_index);
4955 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4957 real->cached_char_index = real_char_index;
4959 check_invariants (iter);
4963 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4968 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4972 g_return_if_fail (iter != NULL);
4973 g_return_if_fail (tree != NULL);
4975 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
4977 iter_init_from_char_offset (iter, tree, line, char_on_line);
4979 /* We might as well cache this, since we know it. */
4980 real->cached_line_number = real_line;
4982 check_invariants (iter);
4986 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4991 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4995 g_return_if_fail (iter != NULL);
4996 g_return_if_fail (tree != NULL);
4998 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5000 iter_init_from_byte_offset (iter, tree, line, byte_index);
5002 /* We might as well cache this, since we know it. */
5003 real->cached_line_number = real_line;
5005 check_invariants (iter);
5009 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5014 g_return_if_fail (iter != NULL);
5015 g_return_if_fail (tree != NULL);
5016 g_return_if_fail (line != NULL);
5018 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5020 check_invariants (iter);
5024 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5030 g_return_val_if_fail (iter != NULL, FALSE);
5031 g_return_val_if_fail (tree != NULL, FALSE);
5033 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5037 /* Set iter to last in tree */
5038 _gtk_text_btree_get_end_iter (tree, iter);
5039 check_invariants (iter);
5044 iter_init_from_byte_offset (iter, tree, line, 0);
5045 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5046 check_invariants (iter);
5052 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5056 g_return_val_if_fail (iter != NULL, FALSE);
5057 g_return_val_if_fail (tree != NULL, FALSE);
5059 _gtk_text_btree_get_end_iter (tree, iter);
5060 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5061 check_invariants (iter);
5067 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5069 const gchar *mark_name)
5073 g_return_val_if_fail (iter != NULL, FALSE);
5074 g_return_val_if_fail (tree != NULL, FALSE);
5076 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5082 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5083 check_invariants (iter);
5089 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5093 GtkTextLineSegment *seg;
5095 g_return_if_fail (iter != NULL);
5096 g_return_if_fail (tree != NULL);
5097 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5099 seg = mark->segment;
5101 iter_init_from_segment (iter, tree,
5102 seg->body.mark.line, seg);
5103 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5104 check_invariants (iter);
5108 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5110 GtkTextChildAnchor *anchor)
5112 GtkTextLineSegment *seg;
5114 g_return_if_fail (iter != NULL);
5115 g_return_if_fail (tree != NULL);
5116 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5118 seg = anchor->segment;
5120 iter_init_from_segment (iter, tree,
5121 seg->body.child.line, seg);
5122 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5123 check_invariants (iter);
5127 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5130 g_return_if_fail (iter != NULL);
5131 g_return_if_fail (tree != NULL);
5133 _gtk_text_btree_get_iter_at_char (tree,
5135 _gtk_text_btree_char_count (tree));
5136 check_invariants (iter);
5140 _gtk_text_iter_check (const GtkTextIter *iter)
5142 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5143 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5144 GtkTextLineSegment *byte_segment = NULL;
5145 GtkTextLineSegment *byte_any_segment = NULL;
5146 GtkTextLineSegment *char_segment = NULL;
5147 GtkTextLineSegment *char_any_segment = NULL;
5148 gboolean segments_updated;
5150 /* This function checks our class invariants for the Iter class. */
5152 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5154 if (real->chars_changed_stamp !=
5155 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5156 g_error ("iterator check failed: invalid iterator");
5158 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5159 g_error ("iterator check failed: both char and byte offsets are invalid");
5161 segments_updated = (real->segments_changed_stamp ==
5162 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5165 printf ("checking iter, segments %s updated, byte %d char %d\n",
5166 segments_updated ? "are" : "aren't",
5167 real->line_byte_offset,
5168 real->line_char_offset);
5171 if (segments_updated)
5173 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5174 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5176 if (real->segment->char_count == 0)
5177 g_error ("iterator check failed: segment is not indexable.");
5179 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5180 g_error ("segment char offset is not properly up-to-date");
5182 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5183 g_error ("segment byte offset is not properly up-to-date");
5185 if (real->segment_byte_offset >= 0 &&
5186 real->segment_byte_offset >= real->segment->byte_count)
5187 g_error ("segment byte offset is too large.");
5189 if (real->segment_char_offset >= 0 &&
5190 real->segment_char_offset >= real->segment->char_count)
5191 g_error ("segment char offset is too large.");
5194 if (real->line_byte_offset >= 0)
5196 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5197 &byte_segment, &byte_any_segment,
5198 &seg_byte_offset, &line_byte_offset);
5200 if (line_byte_offset != real->line_byte_offset)
5201 g_error ("wrong byte offset was stored in iterator");
5203 if (segments_updated)
5205 if (real->segment != byte_segment)
5206 g_error ("wrong segment was stored in iterator");
5208 if (real->any_segment != byte_any_segment)
5209 g_error ("wrong any_segment was stored in iterator");
5211 if (seg_byte_offset != real->segment_byte_offset)
5212 g_error ("wrong segment byte offset was stored in iterator");
5214 if (byte_segment->type == >k_text_char_type)
5217 p = byte_segment->body.chars + seg_byte_offset;
5219 if (!gtk_text_byte_begins_utf8_char (p))
5220 g_error ("broken iterator byte index pointed into the middle of a character");
5225 if (real->line_char_offset >= 0)
5227 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5228 &char_segment, &char_any_segment,
5229 &seg_char_offset, &line_char_offset);
5231 if (line_char_offset != real->line_char_offset)
5232 g_error ("wrong char offset was stored in iterator");
5234 if (segments_updated)
5236 if (real->segment != char_segment)
5237 g_error ("wrong segment was stored in iterator");
5239 if (real->any_segment != char_any_segment)
5240 g_error ("wrong any_segment was stored in iterator");
5242 if (seg_char_offset != real->segment_char_offset)
5243 g_error ("wrong segment char offset was stored in iterator");
5245 if (char_segment->type == >k_text_char_type)
5248 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5251 /* hmm, not likely to happen eh */
5252 if (!gtk_text_byte_begins_utf8_char (p))
5253 g_error ("broken iterator char offset pointed into the middle of a character");
5258 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5260 if (byte_segment != char_segment)
5261 g_error ("char and byte offsets did not point to the same segment");
5263 if (byte_any_segment != char_any_segment)
5264 g_error ("char and byte offsets did not point to the same any segment");
5266 /* Make sure the segment offsets are equivalent, if it's a char
5268 if (char_segment->type == >k_text_char_type)
5270 gint byte_offset = 0;
5271 gint char_offset = 0;
5272 while (char_offset < seg_char_offset)
5274 const char * start = char_segment->body.chars + byte_offset;
5275 byte_offset += g_utf8_next_char (start) - start;
5279 if (byte_offset != seg_byte_offset)
5280 g_error ("byte offset did not correspond to char offset");
5283 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5285 if (char_offset != seg_char_offset)
5286 g_error ("char offset did not correspond to byte offset");
5288 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5289 g_error ("byte index for iterator does not index the start of a character");
5293 if (real->cached_line_number >= 0)
5297 should_be = _gtk_text_line_get_number (real->line);
5298 if (real->cached_line_number != should_be)
5299 g_error ("wrong line number was cached");
5302 if (real->cached_char_index >= 0)
5304 if (real->line_char_offset >= 0) /* only way we can check it
5305 efficiently, not a real
5310 char_index = _gtk_text_line_char_index (real->line);
5311 char_index += real->line_char_offset;
5313 if (real->cached_char_index != char_index)
5314 g_error ("wrong char index was cached");
5318 if (_gtk_text_line_is_last (real->line, real->tree))
5319 g_error ("Iterator was on last line (past the end iterator)");