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;
74 /* These "set" functions should not assume any fields
75 other than the char stamp and the tree are valid.
78 iter_set_common (GtkTextRealIter *iter,
81 /* Update segments stamp */
82 iter->segments_changed_stamp =
83 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
87 iter->line_byte_offset = -1;
88 iter->line_char_offset = -1;
89 iter->segment_byte_offset = -1;
90 iter->segment_char_offset = -1;
91 iter->cached_char_index = -1;
92 iter->cached_line_number = -1;
96 iter_set_from_byte_offset (GtkTextRealIter *iter,
100 iter_set_common (iter, line);
102 if (!_gtk_text_line_byte_locate (iter->line,
106 &iter->segment_byte_offset,
107 &iter->line_byte_offset))
108 g_error ("Byte index %d is off the end of the line",
113 iter_set_from_char_offset (GtkTextRealIter *iter,
117 iter_set_common (iter, line);
119 if (!_gtk_text_line_char_locate (iter->line,
123 &iter->segment_char_offset,
124 &iter->line_char_offset))
125 g_error ("Char offset %d is off the end of the line",
130 iter_set_from_segment (GtkTextRealIter *iter,
132 GtkTextLineSegment *segment)
134 GtkTextLineSegment *seg;
137 /* This could theoretically be optimized by computing all the iter
138 fields in this same loop, but I'm skipping it for now. */
140 seg = line->segments;
141 while (seg != segment)
143 byte_offset += seg->byte_count;
147 iter_set_from_byte_offset (iter, line, byte_offset);
150 /* This function ensures that the segment-dependent information is
151 truly computed lazily; often we don't need to do the full make_real
152 work. This ensures the btree and line are valid, but doesn't
153 update the segments. */
154 static GtkTextRealIter*
155 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
157 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
159 if (iter->chars_changed_stamp !=
160 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
162 g_warning ("Invalid text buffer iterator: either the iterator "
163 "is uninitialized, or the characters/pixbufs/widgets "
164 "in the buffer have been modified since the iterator "
165 "was created.\nYou must use marks, character numbers, "
166 "or line numbers to preserve a position across buffer "
167 "modifications.\nYou can apply tags and insert marks "
168 "without invalidating your iterators,\n"
169 "but any mutation that affects 'indexable' buffer contents "
170 "(contents that can be referred to by character offset)\n"
171 "will invalidate all outstanding iterators");
175 /* We don't update the segments information since we are becoming
176 only surreal. However we do invalidate the segments information
177 if appropriate, to be sure we segfault if we try to use it and we
178 should have used make_real. */
180 if (iter->segments_changed_stamp !=
181 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
183 iter->segment = NULL;
184 iter->any_segment = NULL;
185 /* set to segfault-causing values. */
186 iter->segment_byte_offset = -10000;
187 iter->segment_char_offset = -10000;
193 static GtkTextRealIter*
194 gtk_text_iter_make_real (const GtkTextIter *_iter)
196 GtkTextRealIter *iter;
198 iter = gtk_text_iter_make_surreal (_iter);
200 if (iter->segments_changed_stamp !=
201 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
203 if (iter->line_byte_offset >= 0)
205 iter_set_from_byte_offset (iter,
207 iter->line_byte_offset);
211 g_assert (iter->line_char_offset >= 0);
213 iter_set_from_char_offset (iter,
215 iter->line_char_offset);
219 g_assert (iter->segment != NULL);
220 g_assert (iter->any_segment != NULL);
221 g_assert (iter->segment->char_count > 0);
226 static GtkTextRealIter*
227 iter_init_common (GtkTextIter *_iter,
230 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
232 g_return_val_if_fail (iter != NULL, NULL);
233 g_return_val_if_fail (tree != NULL, NULL);
237 iter->chars_changed_stamp =
238 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
243 static GtkTextRealIter*
244 iter_init_from_segment (GtkTextIter *iter,
247 GtkTextLineSegment *segment)
249 GtkTextRealIter *real;
251 g_return_val_if_fail (line != NULL, NULL);
253 real = iter_init_common (iter, tree);
255 iter_set_from_segment (real, line, segment);
260 static GtkTextRealIter*
261 iter_init_from_byte_offset (GtkTextIter *iter,
264 gint line_byte_offset)
266 GtkTextRealIter *real;
268 g_return_val_if_fail (line != NULL, NULL);
270 real = iter_init_common (iter, tree);
272 iter_set_from_byte_offset (real, line, line_byte_offset);
274 if (real->segment->type == >k_text_char_type &&
275 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
276 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
277 "character; this will crash the text buffer. "
278 "Byte indexes must refer to the start of a character.",
284 static GtkTextRealIter*
285 iter_init_from_char_offset (GtkTextIter *iter,
288 gint line_char_offset)
290 GtkTextRealIter *real;
292 g_return_val_if_fail (line != NULL, NULL);
294 real = iter_init_common (iter, tree);
296 iter_set_from_char_offset (real, line, line_char_offset);
302 invalidate_segment (GtkTextRealIter *iter)
304 iter->segments_changed_stamp -= 1;
308 invalidate_char_index (GtkTextRealIter *iter)
310 iter->cached_char_index = -1;
314 invalidate_line_number (GtkTextRealIter *iter)
316 iter->cached_line_number = -1;
320 adjust_char_index (GtkTextRealIter *iter, gint count)
322 if (iter->cached_char_index >= 0)
323 iter->cached_char_index += count;
327 adjust_line_number (GtkTextRealIter *iter, gint count)
329 if (iter->cached_line_number >= 0)
330 iter->cached_line_number += count;
334 adjust_char_offsets (GtkTextRealIter *iter, gint count)
336 if (iter->line_char_offset >= 0)
338 iter->line_char_offset += count;
339 g_assert (iter->segment_char_offset >= 0);
340 iter->segment_char_offset += count;
345 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
347 if (iter->line_byte_offset >= 0)
349 iter->line_byte_offset += count;
350 g_assert (iter->segment_byte_offset >= 0);
351 iter->segment_byte_offset += count;
356 ensure_char_offsets (GtkTextRealIter *iter)
358 if (iter->line_char_offset < 0)
360 g_assert (iter->line_byte_offset >= 0);
362 _gtk_text_line_byte_to_char_offsets (iter->line,
363 iter->line_byte_offset,
364 &iter->line_char_offset,
365 &iter->segment_char_offset);
370 ensure_byte_offsets (GtkTextRealIter *iter)
372 if (iter->line_byte_offset < 0)
374 g_assert (iter->line_char_offset >= 0);
376 _gtk_text_line_char_to_byte_offsets (iter->line,
377 iter->line_char_offset,
378 &iter->line_byte_offset,
379 &iter->segment_byte_offset);
383 static inline gboolean
384 is_segment_start (GtkTextRealIter *real)
386 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
391 check_invariants (const GtkTextIter *iter)
393 if (gtk_debug_flags & GTK_DEBUG_TEXT)
394 _gtk_text_iter_check (iter);
397 #define check_invariants (x)
401 * gtk_text_iter_get_buffer:
404 * Returns the #GtkTextBuffer this iterator is associated with.
406 * Return value: the buffer
409 gtk_text_iter_get_buffer (const GtkTextIter *iter)
411 GtkTextRealIter *real;
413 g_return_val_if_fail (iter != NULL, NULL);
415 real = gtk_text_iter_make_surreal (iter);
420 check_invariants (iter);
422 return _gtk_text_btree_get_buffer (real->tree);
426 * gtk_text_iter_copy:
429 * Creates a dynamically-allocated copy of an iterator. This function
430 * is not useful in applications, because iterators can be copied with a
431 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
432 * function is used by language bindings.
434 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
437 gtk_text_iter_copy (const GtkTextIter *iter)
439 GtkTextIter *new_iter;
441 g_return_val_if_fail (iter != NULL, NULL);
443 new_iter = g_new (GtkTextIter, 1);
451 * gtk_text_iter_free:
452 * @iter: a dynamically-allocated iterator
454 * Free an iterator allocated on the heap. This function
455 * is intended for use in language bindings, and is not
456 * especially useful for applications, because iterators can
457 * simply be allocated on the stack.
460 gtk_text_iter_free (GtkTextIter *iter)
462 g_return_if_fail (iter != NULL);
468 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
470 GtkTextRealIter *real;
472 g_return_val_if_fail (iter != NULL, 0);
474 real = gtk_text_iter_make_real (iter);
479 check_invariants (iter);
481 g_assert (real->segment != NULL);
483 return real->segment;
487 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
489 GtkTextRealIter *real;
491 g_return_val_if_fail (iter != NULL, 0);
493 real = gtk_text_iter_make_real (iter);
498 check_invariants (iter);
500 g_assert (real->any_segment != NULL);
502 return real->any_segment;
506 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
508 GtkTextRealIter *real;
510 g_return_val_if_fail (iter != NULL, 0);
512 real = gtk_text_iter_make_real (iter);
517 ensure_byte_offsets (real);
519 check_invariants (iter);
521 return real->segment_byte_offset;
525 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
527 GtkTextRealIter *real;
529 g_return_val_if_fail (iter != NULL, 0);
531 real = gtk_text_iter_make_real (iter);
536 ensure_char_offsets (real);
538 check_invariants (iter);
540 return real->segment_char_offset;
543 /* This function does not require a still-valid
546 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
548 const GtkTextRealIter *real;
550 g_return_val_if_fail (iter != NULL, 0);
552 real = (const GtkTextRealIter*)iter;
557 /* This function does not require a still-valid
560 _gtk_text_iter_get_btree (const GtkTextIter *iter)
562 const GtkTextRealIter *real;
564 g_return_val_if_fail (iter != NULL, 0);
566 real = (const GtkTextRealIter*)iter;
576 * gtk_text_iter_get_offset:
579 * Returns the character offset of an iterator.
580 * Each character in a #GtkTextBuffer has an offset,
581 * starting with 0 for the first character in the buffer.
582 * Use gtk_text_buffer_get_iter_at_offset () to convert an
583 * offset back into an iterator.
585 * Return value: a character offset
588 gtk_text_iter_get_offset (const GtkTextIter *iter)
590 GtkTextRealIter *real;
592 g_return_val_if_fail (iter != NULL, 0);
594 real = gtk_text_iter_make_surreal (iter);
599 check_invariants (iter);
601 if (real->cached_char_index < 0)
603 ensure_char_offsets (real);
605 real->cached_char_index =
606 _gtk_text_line_char_index (real->line);
607 real->cached_char_index += real->line_char_offset;
610 check_invariants (iter);
612 return real->cached_char_index;
616 * gtk_text_iter_get_line:
619 * Returns the line number containing the iterator. Lines in
620 * a #GtkTextBuffer are numbered beginning with 0 for the first
621 * line in the buffer.
623 * Return value: a line number
626 gtk_text_iter_get_line (const GtkTextIter *iter)
628 GtkTextRealIter *real;
630 g_return_val_if_fail (iter != NULL, 0);
632 real = gtk_text_iter_make_surreal (iter);
637 if (real->cached_line_number < 0)
638 real->cached_line_number =
639 _gtk_text_line_get_number (real->line);
641 check_invariants (iter);
643 return real->cached_line_number;
647 * gtk_text_iter_get_line_offset:
650 * Returns the character offset of the iterator,
651 * counting from the start of a newline-terminated line.
652 * The first character on the line has offset 0.
654 * Return value: offset from start of line
657 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
659 GtkTextRealIter *real;
661 g_return_val_if_fail (iter != NULL, 0);
663 real = gtk_text_iter_make_surreal (iter);
668 ensure_char_offsets (real);
670 check_invariants (iter);
672 return real->line_char_offset;
676 * gtk_text_iter_get_line_index:
679 * Returns the byte index of the iterator, counting
680 * from the start of a newline-terminated line.
681 * Remember that #GtkTextBuffer encodes text in
682 * UTF-8, and that characters can require a variable
683 * number of bytes to represent.
685 * Return value: distance from start of line, in bytes
688 gtk_text_iter_get_line_index (const GtkTextIter *iter)
690 GtkTextRealIter *real;
692 g_return_val_if_fail (iter != NULL, 0);
694 real = gtk_text_iter_make_surreal (iter);
699 ensure_byte_offsets (real);
701 check_invariants (iter);
703 return real->line_byte_offset;
707 * gtk_text_iter_get_visible_line_offset:
708 * @iter: a #GtkTextIter
710 * Returns the offset in characters from the start of the
711 * line to the given @iter, not counting characters that
712 * are invisible due to tags with the "invisible" flag
715 * Return value: offset in visible characters from the start of the line
718 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
720 GtkTextRealIter *real;
722 GtkTextLineSegment *seg;
725 g_return_val_if_fail (iter != NULL, 0);
727 real = gtk_text_iter_make_real (iter);
732 ensure_char_offsets (real);
734 check_invariants (iter);
736 vis_offset = real->line_char_offset;
738 g_assert (vis_offset >= 0);
740 _gtk_text_btree_get_iter_at_line (real->tree,
745 seg = _gtk_text_iter_get_indexable_segment (&pos);
747 while (seg != real->segment)
749 /* This is a pretty expensive call, making the
750 * whole function pretty lame; we could keep track
751 * of current invisibility state by looking at toggle
752 * segments as we loop, and then call this function
753 * only once per line, in order to speed up the loop
756 if (_gtk_text_btree_char_is_invisible (&pos))
757 vis_offset -= seg->char_count;
759 _gtk_text_iter_forward_indexable_segment (&pos);
761 seg = _gtk_text_iter_get_indexable_segment (&pos);
764 if (_gtk_text_btree_char_is_invisible (&pos))
765 vis_offset -= real->segment_char_offset;
772 * gtk_text_iter_get_visible_line_index:
773 * @iter: a #GtkTextIter
775 * Returns the number of bytes from the start of the
776 * line to the given @iter, not counting bytes that
777 * are invisible due to tags with the "invisible" flag
780 * Return value: byte index of @iter with respect to the start of the line
783 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
785 GtkTextRealIter *real;
787 GtkTextLineSegment *seg;
790 g_return_val_if_fail (iter != NULL, 0);
792 real = gtk_text_iter_make_real (iter);
797 ensure_byte_offsets (real);
799 check_invariants (iter);
801 vis_offset = real->line_byte_offset;
803 g_assert (vis_offset >= 0);
805 _gtk_text_btree_get_iter_at_line (real->tree,
810 seg = _gtk_text_iter_get_indexable_segment (&pos);
812 while (seg != real->segment)
814 /* This is a pretty expensive call, making the
815 * whole function pretty lame; we could keep track
816 * of current invisibility state by looking at toggle
817 * segments as we loop, and then call this function
818 * only once per line, in order to speed up the loop
821 if (_gtk_text_btree_char_is_invisible (&pos))
822 vis_offset -= seg->byte_count;
824 _gtk_text_iter_forward_indexable_segment (&pos);
826 seg = _gtk_text_iter_get_indexable_segment (&pos);
829 if (_gtk_text_btree_char_is_invisible (&pos))
830 vis_offset -= real->segment_byte_offset;
840 * gtk_text_iter_get_char:
843 * Returns the Unicode character at this iterator. (Equivalent to
844 * operator* on a C++ iterator.) If the iterator points at a
845 * non-character element, such as an image embedded in the buffer, the
846 * Unicode "unknown" character 0xFFFC is returned. If invoked on
847 * the end iterator, zero is returned; zero is not a valid Unicode character.
848 * So you can write a loop which ends when gtk_text_iter_get_char ()
851 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
854 gtk_text_iter_get_char (const GtkTextIter *iter)
856 GtkTextRealIter *real;
858 g_return_val_if_fail (iter != NULL, 0);
860 real = gtk_text_iter_make_real (iter);
865 check_invariants (iter);
867 if (gtk_text_iter_is_end (iter))
869 else if (real->segment->type == >k_text_char_type)
871 ensure_byte_offsets (real);
873 return g_utf8_get_char (real->segment->body.chars +
874 real->segment_byte_offset);
878 /* Unicode "unknown character" 0xFFFC */
879 return GTK_TEXT_UNKNOWN_CHAR;
884 * gtk_text_iter_get_slice:
885 * @start: iterator at start of a range
886 * @end: iterator at end of a range
888 * Returns the text in the given range. A "slice" is an array of
889 * characters encoded in UTF-8 format, including the Unicode "unknown"
890 * character 0xFFFC for iterable non-character elements in the buffer,
891 * such as images. Because images are encoded in the slice, byte and
892 * character offsets in the returned array will correspond to byte
893 * offsets in the text buffer. Note that 0xFFFC can occur in normal
894 * text as well, so it is not a reliable indicator that a pixbuf or
895 * widget is in the buffer.
897 * Return value: slice of text from the buffer
900 gtk_text_iter_get_slice (const GtkTextIter *start,
901 const GtkTextIter *end)
903 g_return_val_if_fail (start != NULL, NULL);
904 g_return_val_if_fail (end != NULL, NULL);
906 check_invariants (start);
907 check_invariants (end);
909 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
913 * gtk_text_iter_get_text:
914 * @start: iterator at start of a range
915 * @end: iterator at end of a range
917 * Returns <emphasis>text</emphasis> in the given range. If the range
918 * contains non-text elements such as images, the character and byte
919 * offsets in the returned string will not correspond to character and
920 * byte offsets in the buffer. If you want offsets to correspond, see
921 * gtk_text_iter_get_slice ().
923 * Return value: array of characters from the buffer
926 gtk_text_iter_get_text (const GtkTextIter *start,
927 const GtkTextIter *end)
929 g_return_val_if_fail (start != NULL, NULL);
930 g_return_val_if_fail (end != NULL, NULL);
932 check_invariants (start);
933 check_invariants (end);
935 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
939 * gtk_text_iter_get_visible_slice:
940 * @start: iterator at start of range
941 * @end: iterator at end of range
943 * Like gtk_text_iter_get_slice (), but invisible text is not included.
944 * Invisible text is usually invisible because a #GtkTextTag with the
945 * "invisible" attribute turned on has been applied to it.
947 * Return value: slice of text from the buffer
950 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
951 const GtkTextIter *end)
953 g_return_val_if_fail (start != NULL, NULL);
954 g_return_val_if_fail (end != NULL, NULL);
956 check_invariants (start);
957 check_invariants (end);
959 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
963 * gtk_text_iter_get_visible_text:
964 * @start: iterator at start of range
965 * @end: iterator at end of range
967 * Like gtk_text_iter_get_text (), but invisible text is not included.
968 * Invisible text is usually invisible because a #GtkTextTag with the
969 * "invisible" attribute turned on has been applied to it.
971 * Return value: string containing visible text in the range
974 gtk_text_iter_get_visible_text (const GtkTextIter *start,
975 const GtkTextIter *end)
977 g_return_val_if_fail (start != NULL, NULL);
978 g_return_val_if_fail (end != NULL, NULL);
980 check_invariants (start);
981 check_invariants (end);
983 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
987 * gtk_text_iter_get_pixbuf:
990 * If the location pointed to by @iter contains a pixbuf, the pixbuf
991 * is returned (with no new reference count added). Otherwise,
994 * Return value: the pixbuf at @iter
997 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
999 GtkTextRealIter *real;
1001 g_return_val_if_fail (iter != NULL, NULL);
1003 real = gtk_text_iter_make_real (iter);
1008 check_invariants (iter);
1010 if (real->segment->type != >k_text_pixbuf_type)
1013 return real->segment->body.pixbuf.pixbuf;
1017 * gtk_text_iter_get_child_anchor:
1018 * @iter: an iterator
1020 * If the location pointed to by @iter contains a child anchor, the
1021 * anchor is returned (with no new reference count added). Otherwise,
1022 * %NULL is returned.
1024 * Return value: the anchor at @iter
1027 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1029 GtkTextRealIter *real;
1031 g_return_val_if_fail (iter != NULL, NULL);
1033 real = gtk_text_iter_make_real (iter);
1038 check_invariants (iter);
1040 if (real->segment->type != >k_text_child_type)
1043 return real->segment->body.child.obj;
1047 * gtk_text_iter_get_marks:
1048 * @iter: an iterator
1050 * Returns a list of all #GtkTextMark at this location. Because marks
1051 * are not iterable (they don't take up any "space" in the buffer,
1052 * they are just marks in between iterable locations), multiple marks
1053 * can exist in the same place. The returned list is not in any
1056 * Return value: list of #GtkTextMark
1059 gtk_text_iter_get_marks (const GtkTextIter *iter)
1061 GtkTextRealIter *real;
1062 GtkTextLineSegment *seg;
1065 g_return_val_if_fail (iter != NULL, NULL);
1067 real = gtk_text_iter_make_real (iter);
1072 check_invariants (iter);
1075 seg = real->any_segment;
1076 while (seg != real->segment)
1078 if (seg->type == >k_text_left_mark_type ||
1079 seg->type == >k_text_right_mark_type)
1080 retval = g_slist_prepend (retval, seg->body.mark.obj);
1085 /* The returned list isn't guaranteed to be in any special order,
1091 * gtk_text_iter_get_toggled_tags:
1092 * @iter: an iterator
1093 * @toggled_on: %TRUE to get toggled-on tags
1095 * Returns a list of #GtkTextTag that are toggled on or off at this
1096 * point. (If @toggled_on is %TRUE, the list contains tags that are
1097 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1098 * range of characters following @iter has that tag applied to it. If
1099 * a tag is toggled off, then some non-empty range following @iter
1100 * does <emphasis>not</emphasis> have the tag applied to it.
1102 * Return value: tags toggled at this point
1105 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1106 gboolean toggled_on)
1108 GtkTextRealIter *real;
1109 GtkTextLineSegment *seg;
1112 g_return_val_if_fail (iter != NULL, NULL);
1114 real = gtk_text_iter_make_real (iter);
1119 check_invariants (iter);
1122 seg = real->any_segment;
1123 while (seg != real->segment)
1127 if (seg->type == >k_text_toggle_on_type)
1129 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1134 if (seg->type == >k_text_toggle_off_type)
1136 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1143 /* The returned list isn't guaranteed to be in any special order,
1149 * gtk_text_iter_begins_tag:
1150 * @iter: an iterator
1151 * @tag: a #GtkTextTag, or %NULL
1153 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1154 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1155 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1156 * <emphasis>start</emphasis> of the tagged range;
1157 * gtk_text_iter_has_tag () tells you whether an iterator is
1158 * <emphasis>within</emphasis> a tagged range.
1160 * Return value: whether @iter is the start of a range tagged with @tag
1163 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1166 GtkTextRealIter *real;
1167 GtkTextLineSegment *seg;
1169 g_return_val_if_fail (iter != NULL, FALSE);
1171 real = gtk_text_iter_make_real (iter);
1176 check_invariants (iter);
1178 seg = real->any_segment;
1179 while (seg != real->segment)
1181 if (seg->type == >k_text_toggle_on_type)
1184 seg->body.toggle.info->tag == tag)
1195 * gtk_text_iter_ends_tag:
1196 * @iter: an iterator
1197 * @tag: a #GtkTextTag, or %NULL
1199 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1200 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1201 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1202 * <emphasis>end</emphasis> of the tagged range;
1203 * gtk_text_iter_has_tag () tells you whether an iterator is
1204 * <emphasis>within</emphasis> a tagged range.
1206 * Return value: whether @iter is the end of a range tagged with @tag
1210 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1213 GtkTextRealIter *real;
1214 GtkTextLineSegment *seg;
1216 g_return_val_if_fail (iter != NULL, FALSE);
1218 real = gtk_text_iter_make_real (iter);
1223 check_invariants (iter);
1225 seg = real->any_segment;
1226 while (seg != real->segment)
1228 if (seg->type == >k_text_toggle_off_type)
1231 seg->body.toggle.info->tag == tag)
1242 * gtk_text_iter_toggles_tag:
1243 * @iter: an iterator
1244 * @tag: a #GtkTextTag, or %NULL
1246 * This is equivalent to (gtk_text_iter_begins_tag () ||
1247 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1248 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1250 * Return value: whether @tag is toggled on or off at @iter
1253 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1256 GtkTextRealIter *real;
1257 GtkTextLineSegment *seg;
1259 g_return_val_if_fail (iter != NULL, FALSE);
1261 real = gtk_text_iter_make_real (iter);
1266 check_invariants (iter);
1268 seg = real->any_segment;
1269 while (seg != real->segment)
1271 if ( (seg->type == >k_text_toggle_off_type ||
1272 seg->type == >k_text_toggle_on_type) &&
1274 seg->body.toggle.info->tag == tag) )
1284 * gtk_text_iter_has_tag:
1285 * @iter: an iterator
1286 * @tag: a #GtkTextTag
1288 * Returns %TRUE if @iter is within a range tagged with @tag.
1290 * Return value: whether @iter is tagged with @tag
1293 gtk_text_iter_has_tag (const GtkTextIter *iter,
1296 GtkTextRealIter *real;
1298 g_return_val_if_fail (iter != NULL, FALSE);
1299 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1301 real = gtk_text_iter_make_surreal (iter);
1306 check_invariants (iter);
1308 if (real->line_byte_offset >= 0)
1310 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1311 real->line_byte_offset, tag);
1315 g_assert (real->line_char_offset >= 0);
1316 return _gtk_text_line_char_has_tag (real->line, real->tree,
1317 real->line_char_offset, tag);
1322 * gtk_text_iter_get_tags:
1323 * @iter: a #GtkTextIter
1325 * Returns a list of tags that apply to @iter, in ascending order of
1326 * priority (highest-priority tags are last). The #GtkTextTag in the
1327 * list don't have a reference added, but you have to free the list
1330 * Return value: list of #GtkTextTag
1333 gtk_text_iter_get_tags (const GtkTextIter *iter)
1340 g_return_val_if_fail (iter != NULL, NULL);
1342 /* Get the tags at this spot */
1343 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1345 /* No tags, use default style */
1346 if (tags == NULL || tag_count == 0)
1354 /* Sort tags in ascending order of priority */
1355 _gtk_text_tag_array_sort (tags, tag_count);
1359 while (i < tag_count)
1361 retval = g_slist_prepend (retval, tags[i]);
1367 /* Return tags in ascending order of priority */
1368 return g_slist_reverse (retval);
1372 * gtk_text_iter_editable:
1373 * @iter: an iterator
1374 * @default_setting: %TRUE if text is editable by default
1376 * Returns whether the character at @iter is within an editable region
1377 * of text. Non-editable text is "locked" and can't be changed by the
1378 * user via #GtkTextView. This function is simply a convenience
1379 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1380 * to this text affect editability, @default_setting will be returned.
1382 * You don't want to use this function to decide whether text can be
1383 * inserted at @iter, because for insertion you don't want to know
1384 * whether the char at @iter is inside an editable range, you want to
1385 * know whether a new character inserted at @iter would be inside an
1386 * editable range. Use gtk_text_iter_can_insert() to handle this
1389 * Return value: whether @iter is inside an editable range
1392 gtk_text_iter_editable (const GtkTextIter *iter,
1393 gboolean default_setting)
1395 GtkTextAttributes *values;
1398 g_return_val_if_fail (iter != NULL, FALSE);
1400 values = gtk_text_attributes_new ();
1402 values->editable = default_setting;
1404 gtk_text_iter_get_attributes (iter, values);
1406 retval = values->editable;
1408 gtk_text_attributes_unref (values);
1414 * gtk_text_iter_can_insert:
1415 * @iter: an iterator
1416 * @default_editability: %TRUE if text is editable by default
1418 * Considering the default editability of the buffer, and tags that
1419 * affect editability, determines whether text inserted at @iter would
1420 * be editable. If text inserted at @iter would be editable then the
1421 * user should be allowed to insert text at @iter.
1422 * gtk_text_buffer_insert_interactive() uses this function to decide
1423 * whether insertions are allowed at a given position.
1425 * Return value: whether text inserted at @iter would be editable
1428 gtk_text_iter_can_insert (const GtkTextIter *iter,
1429 gboolean default_editability)
1431 g_return_val_if_fail (iter != NULL, FALSE);
1433 if (gtk_text_iter_editable (iter, default_editability))
1435 /* If at start/end of buffer, default editability is used */
1436 else if ((gtk_text_iter_is_start (iter) ||
1437 gtk_text_iter_is_end (iter)) &&
1438 default_editability)
1442 /* if iter isn't editable, and the char before iter is,
1443 * then iter is the first char in an editable region
1444 * and thus insertion at iter results in editable text.
1446 GtkTextIter prev = *iter;
1447 gtk_text_iter_backward_char (&prev);
1448 return gtk_text_iter_editable (&prev, default_editability);
1454 * gtk_text_iter_get_language:
1455 * @iter: an iterator
1457 * A convenience wrapper around gtk_text_iter_get_attributes (),
1458 * which returns the language in effect at @iter. If no tags affecting
1459 * language apply to @iter, the return value is identical to that of
1460 * gtk_get_default_language ().
1462 * Return value: language in effect at @iter
1465 gtk_text_iter_get_language (const GtkTextIter *iter)
1467 GtkTextAttributes *values;
1468 PangoLanguage *retval;
1470 values = gtk_text_attributes_new ();
1472 gtk_text_iter_get_attributes (iter, values);
1474 retval = values->language;
1476 gtk_text_attributes_unref (values);
1482 * gtk_text_iter_starts_line:
1483 * @iter: an iterator
1485 * Returns %TRUE if @iter begins a paragraph,
1486 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1487 * However this function is potentially more efficient than
1488 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1489 * the offset, it just has to see whether it's 0.
1491 * Return value: whether @iter begins a line
1494 gtk_text_iter_starts_line (const GtkTextIter *iter)
1496 GtkTextRealIter *real;
1498 g_return_val_if_fail (iter != NULL, FALSE);
1500 real = gtk_text_iter_make_surreal (iter);
1505 check_invariants (iter);
1507 if (real->line_byte_offset >= 0)
1509 return (real->line_byte_offset == 0);
1513 g_assert (real->line_char_offset >= 0);
1514 return (real->line_char_offset == 0);
1519 * gtk_text_iter_ends_line:
1520 * @iter: an iterator
1522 * Returns %TRUE if @iter points to the start of the paragraph
1523 * delimiter characters for a line (delimiters will be either a
1524 * newline, a carriage return, a carriage return followed by a
1525 * newline, or a Unicode paragraph separator character). Note that an
1526 * iterator pointing to the \n of a \r\n pair will not be counted as
1527 * the end of a line, the line ends before the \r. The end iterator is
1528 * considered to be at the end of a line, even though there are no
1529 * paragraph delimiter chars there.
1531 * Return value: whether @iter is at the end of a line
1534 gtk_text_iter_ends_line (const GtkTextIter *iter)
1536 GtkTextRealIter *real;
1539 g_return_val_if_fail (iter != NULL, FALSE);
1541 real = gtk_text_iter_make_real (iter);
1543 check_invariants (iter);
1545 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1546 * Unicode 3.0; update this if that changes.
1548 #define PARAGRAPH_SEPARATOR 0x2029
1550 wc = gtk_text_iter_get_char (iter);
1552 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1554 else if (wc == '\n')
1556 /* need to determine if a \r precedes the \n, in which case
1557 * we aren't the end of the line
1559 GtkTextIter tmp = *iter;
1560 if (!gtk_text_iter_backward_char (&tmp))
1563 return gtk_text_iter_get_char (&tmp) != '\r';
1570 * gtk_text_iter_is_end:
1571 * @iter: an iterator
1573 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1574 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1575 * the most efficient way to check whether an iterator is the end
1578 * Return value: whether @iter is the end iterator
1581 gtk_text_iter_is_end (const GtkTextIter *iter)
1583 GtkTextRealIter *real;
1585 g_return_val_if_fail (iter != NULL, FALSE);
1587 real = gtk_text_iter_make_surreal (iter);
1592 check_invariants (iter);
1594 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1597 /* Now we need the segments validated */
1598 real = gtk_text_iter_make_real (iter);
1603 return _gtk_text_btree_is_end (real->tree, real->line,
1605 real->segment_byte_offset,
1606 real->segment_char_offset);
1610 * gtk_text_iter_is_start:
1611 * @iter: an iterator
1613 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1614 * if @iter has a character offset of 0.
1616 * Return value: whether @iter is the first in the buffer
1619 gtk_text_iter_is_start (const GtkTextIter *iter)
1621 return gtk_text_iter_get_offset (iter) == 0;
1625 * gtk_text_iter_get_chars_in_line:
1626 * @iter: an iterator
1628 * Returns the number of characters in the line containing @iter,
1629 * including the paragraph delimiters.
1631 * Return value: number of characters in the line
1634 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1636 GtkTextRealIter *real;
1638 GtkTextLineSegment *seg;
1640 g_return_val_if_fail (iter != NULL, FALSE);
1642 real = gtk_text_iter_make_surreal (iter);
1647 check_invariants (iter);
1649 if (real->line_char_offset >= 0)
1651 /* We can start at the segments we've already found. */
1652 count = real->line_char_offset - real->segment_char_offset;
1653 seg = _gtk_text_iter_get_indexable_segment (iter);
1657 /* count whole line. */
1658 seg = real->line->segments;
1665 count += seg->char_count;
1670 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1671 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1677 * gtk_text_iter_get_bytes_in_line:
1678 * @iter: an iterator
1680 * Returns the number of bytes in the line containing @iter,
1681 * including the paragraph delimiters.
1683 * Return value: number of bytes in the line
1686 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1688 GtkTextRealIter *real;
1690 GtkTextLineSegment *seg;
1692 g_return_val_if_fail (iter != NULL, FALSE);
1694 real = gtk_text_iter_make_surreal (iter);
1699 check_invariants (iter);
1701 if (real->line_byte_offset >= 0)
1703 /* We can start at the segments we've already found. */
1704 count = real->line_byte_offset - real->segment_byte_offset;
1705 seg = _gtk_text_iter_get_indexable_segment (iter);
1709 /* count whole line. */
1710 seg = real->line->segments;
1716 count += seg->byte_count;
1721 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1722 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1728 * gtk_text_iter_get_attributes:
1729 * @iter: an iterator
1730 * @values: a #GtkTextAttributes to be filled in
1732 * Computes the effect of any tags applied to this spot in the
1733 * text. The @values parameter should be initialized to the default
1734 * settings you wish to use if no tags are in effect. You'd typically
1735 * obtain the defaults from gtk_text_view_get_default_attributes().
1737 * gtk_text_iter_get_attributes () will modify @values, applying the
1738 * effects of any tags present at @iter. If any tags affected @values,
1739 * the function returns %TRUE.
1741 * Return value: %TRUE if @values was modified
1744 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1745 GtkTextAttributes *values)
1750 /* Get the tags at this spot */
1751 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1753 /* No tags, use default style */
1754 if (tags == NULL || tag_count == 0)
1762 /* Sort tags in ascending order of priority */
1763 _gtk_text_tag_array_sort (tags, tag_count);
1765 _gtk_text_attributes_fill_from_tags (values,
1775 * Increments/decrements
1778 /* The return value of this indicates WHETHER WE MOVED.
1779 * The return value of public functions indicates
1780 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1782 * This function will not change the iterator if
1783 * it's already on the last (end iter) line, i.e. it
1784 * won't move to the end of the last line.
1787 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1789 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1791 GtkTextLine *new_line;
1793 new_line = _gtk_text_line_next (real->line);
1794 g_assert (new_line);
1795 g_assert (new_line != real->line);
1796 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1798 real->line = new_line;
1800 real->line_byte_offset = 0;
1801 real->line_char_offset = 0;
1803 real->segment_byte_offset = 0;
1804 real->segment_char_offset = 0;
1806 /* Find first segments in new line */
1807 real->any_segment = real->line->segments;
1808 real->segment = real->any_segment;
1809 while (real->segment->char_count == 0)
1810 real->segment = real->segment->next;
1816 /* There is no way to move forward a line; we were already at
1817 * the line containing the end iterator.
1818 * However we may not be at the end iterator itself.
1826 /* The return value of this indicates WHETHER WE MOVED.
1827 * The return value of public functions indicates
1828 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1831 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1833 GtkTextLine *new_line;
1835 new_line = _gtk_text_line_previous (real->line);
1837 g_assert (new_line != real->line);
1839 if (new_line != NULL)
1841 real->line = new_line;
1843 real->line_byte_offset = 0;
1844 real->line_char_offset = 0;
1846 real->segment_byte_offset = 0;
1847 real->segment_char_offset = 0;
1849 /* Find first segments in new line */
1850 real->any_segment = real->line->segments;
1851 real->segment = real->any_segment;
1852 while (real->segment->char_count == 0)
1853 real->segment = real->segment->next;
1859 /* There is no way to move backward; we were already
1860 at the first line. */
1862 /* We leave real->line as-is */
1864 /* Note that we didn't clamp to the start of the first line. */
1870 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1874 forward_char (GtkTextRealIter *real)
1876 GtkTextIter *iter = (GtkTextIter*)real;
1878 check_invariants ((GtkTextIter*)real);
1880 ensure_char_offsets (real);
1882 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1884 /* Need to move to the next segment; if no next segment,
1885 need to move to next line. */
1886 return _gtk_text_iter_forward_indexable_segment (iter);
1890 /* Just moving within a segment. Keep byte count
1891 up-to-date, if it was already up-to-date. */
1893 g_assert (real->segment->type == >k_text_char_type);
1895 if (real->line_byte_offset >= 0)
1898 const char * start =
1899 real->segment->body.chars + real->segment_byte_offset;
1901 bytes = g_utf8_next_char (start) - start;
1903 real->line_byte_offset += bytes;
1904 real->segment_byte_offset += bytes;
1906 g_assert (real->segment_byte_offset < real->segment->byte_count);
1909 real->line_char_offset += 1;
1910 real->segment_char_offset += 1;
1912 adjust_char_index (real, 1);
1914 g_assert (real->segment_char_offset < real->segment->char_count);
1916 /* We moved into the middle of a segment, so the any_segment
1917 must now be the segment we're in the middle of. */
1918 real->any_segment = real->segment;
1920 check_invariants ((GtkTextIter*)real);
1922 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1930 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1932 /* Need to move to the next segment; if no next segment,
1933 need to move to next line. */
1934 GtkTextLineSegment *seg;
1935 GtkTextLineSegment *any_seg;
1936 GtkTextRealIter *real;
1940 g_return_val_if_fail (iter != NULL, FALSE);
1942 real = gtk_text_iter_make_real (iter);
1947 check_invariants (iter);
1949 if (real->line_char_offset >= 0)
1951 chars_skipped = real->segment->char_count - real->segment_char_offset;
1952 g_assert (chars_skipped > 0);
1957 if (real->line_byte_offset >= 0)
1959 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1960 g_assert (bytes_skipped > 0);
1965 /* Get first segment of any kind */
1966 any_seg = real->segment->next;
1967 /* skip non-indexable segments, if any */
1969 while (seg != NULL && seg->char_count == 0)
1974 real->any_segment = any_seg;
1975 real->segment = seg;
1977 if (real->line_byte_offset >= 0)
1979 g_assert (bytes_skipped > 0);
1980 real->segment_byte_offset = 0;
1981 real->line_byte_offset += bytes_skipped;
1984 if (real->line_char_offset >= 0)
1986 g_assert (chars_skipped > 0);
1987 real->segment_char_offset = 0;
1988 real->line_char_offset += chars_skipped;
1989 adjust_char_index (real, chars_skipped);
1992 check_invariants (iter);
1994 return !gtk_text_iter_is_end (iter);
1998 /* End of the line */
1999 if (forward_line_leaving_caches_unmodified (real))
2001 adjust_line_number (real, 1);
2002 if (real->line_char_offset >= 0)
2003 adjust_char_index (real, chars_skipped);
2005 g_assert (real->line_byte_offset == 0);
2006 g_assert (real->line_char_offset == 0);
2007 g_assert (real->segment_byte_offset == 0);
2008 g_assert (real->segment_char_offset == 0);
2009 g_assert (gtk_text_iter_starts_line (iter));
2011 check_invariants (iter);
2013 return !gtk_text_iter_is_end (iter);
2017 /* End of buffer, but iter is still at start of last segment,
2018 * not at the end iterator. We put it on the end iterator.
2021 check_invariants (iter);
2023 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2024 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2026 gtk_text_iter_forward_to_line_end (iter);
2028 g_assert (gtk_text_iter_is_end (iter));
2036 at_last_indexable_segment (GtkTextRealIter *real)
2038 GtkTextLineSegment *seg;
2040 /* Return TRUE if there are no indexable segments after
2044 seg = real->segment->next;
2047 if (seg->char_count > 0)
2054 /* Goes back to the start of the next segment, even if
2055 * we're not at the start of the current segment (always
2056 * ends up on a different segment if it returns TRUE)
2059 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2061 /* Move to the start of the previous segment; if no previous
2062 * segment, to the last segment in the previous line. This is
2063 * inherently a bit inefficient due to the singly-linked list and
2064 * tree nodes, but we can't afford the RAM for doubly-linked.
2066 GtkTextRealIter *real;
2067 GtkTextLineSegment *seg;
2068 GtkTextLineSegment *any_seg;
2069 GtkTextLineSegment *prev_seg;
2070 GtkTextLineSegment *prev_any_seg;
2074 g_return_val_if_fail (iter != NULL, FALSE);
2076 real = gtk_text_iter_make_real (iter);
2081 check_invariants (iter);
2083 /* Find first segments in line */
2084 any_seg = real->line->segments;
2086 while (seg->char_count == 0)
2089 if (seg == real->segment)
2091 /* Could probably do this case faster by hand-coding the
2095 /* We were already at the start of a line;
2096 * go back to the previous line.
2098 if (gtk_text_iter_backward_line (iter))
2100 /* Go forward to last indexable segment in line. */
2101 while (!at_last_indexable_segment (real))
2102 _gtk_text_iter_forward_indexable_segment (iter);
2104 check_invariants (iter);
2109 return FALSE; /* We were at the start of the first line. */
2112 /* We must be in the middle of a line; so find the indexable
2113 * segment just before our current segment.
2115 g_assert (seg != real->segment);
2119 prev_any_seg = any_seg;
2121 any_seg = seg->next;
2123 while (seg->char_count == 0)
2126 while (seg != real->segment);
2128 g_assert (prev_seg != NULL);
2129 g_assert (prev_any_seg != NULL);
2130 g_assert (prev_seg->char_count > 0);
2132 /* We skipped the entire previous segment, plus any
2133 * chars we were into the current segment.
2135 if (real->segment_byte_offset >= 0)
2136 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2140 if (real->segment_char_offset >= 0)
2141 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2145 real->segment = prev_seg;
2146 real->any_segment = prev_any_seg;
2147 real->segment_byte_offset = 0;
2148 real->segment_char_offset = 0;
2150 if (bytes_skipped >= 0)
2152 if (real->line_byte_offset >= 0)
2154 real->line_byte_offset -= bytes_skipped;
2155 g_assert (real->line_byte_offset >= 0);
2159 real->line_byte_offset = -1;
2161 if (chars_skipped >= 0)
2163 if (real->line_char_offset >= 0)
2165 real->line_char_offset -= chars_skipped;
2166 g_assert (real->line_char_offset >= 0);
2169 if (real->cached_char_index >= 0)
2171 real->cached_char_index -= chars_skipped;
2172 g_assert (real->cached_char_index >= 0);
2177 real->line_char_offset = -1;
2178 real->cached_char_index = -1;
2181 /* line number is unchanged. */
2183 check_invariants (iter);
2189 * gtk_text_iter_forward_char:
2190 * @iter: an iterator
2192 * Moves @iter forward by one character offset. Note that images
2193 * embedded in the buffer occupy 1 character slot, so
2194 * gtk_text_iter_forward_char () may actually move onto an image instead
2195 * of a character, if you have images in your buffer. If @iter is the
2196 * end iterator or one character before it, @iter will now point at
2197 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2198 * convenience when writing loops.
2200 * Return value: whether @iter moved and is dereferenceable
2203 gtk_text_iter_forward_char (GtkTextIter *iter)
2205 GtkTextRealIter *real;
2207 g_return_val_if_fail (iter != NULL, FALSE);
2209 real = gtk_text_iter_make_real (iter);
2215 check_invariants (iter);
2216 return forward_char (real);
2221 * gtk_text_iter_backward_char:
2222 * @iter: an iterator
2224 * Moves backward by one character offset. Returns %TRUE if movement
2225 * was possible; if @iter was the first in the buffer (character
2226 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2229 * Return value: whether movement was possible
2232 gtk_text_iter_backward_char (GtkTextIter *iter)
2234 g_return_val_if_fail (iter != NULL, FALSE);
2236 check_invariants (iter);
2238 return gtk_text_iter_backward_chars (iter, 1);
2242 Definitely we should try to linear scan as often as possible for
2243 movement within a single line, because we can't use the BTree to
2244 speed within-line searches up; for movement between lines, we would
2245 like to avoid the linear scan probably.
2247 Instead of using this constant, it might be nice to cache the line
2248 length in the iterator and linear scan if motion is within a single
2251 I guess you'd have to profile the various approaches.
2253 #define MAX_LINEAR_SCAN 150
2257 * gtk_text_iter_forward_chars:
2258 * @iter: an iterator
2259 * @count: number of characters to move, may be negative
2261 * Moves @count characters if possible (if @count would move past the
2262 * start or end of the buffer, moves to the start or end of the
2263 * buffer). The return value indicates whether the new position of
2264 * @iter is different from its original position, and dereferenceable
2265 * (the last iterator in the buffer is not dereferenceable). If @count
2266 * is 0, the function does nothing and returns %FALSE.
2268 * Return value: whether @iter moved and is dereferenceable
2271 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2273 GtkTextRealIter *real;
2275 g_return_val_if_fail (iter != NULL, FALSE);
2277 FIX_OVERFLOWS (count);
2279 real = gtk_text_iter_make_real (iter);
2283 else if (count == 0)
2286 return gtk_text_iter_backward_chars (iter, 0 - count);
2287 else if (count < MAX_LINEAR_SCAN)
2289 check_invariants (iter);
2293 if (!forward_char (real))
2298 return forward_char (real);
2302 gint current_char_index;
2303 gint new_char_index;
2305 check_invariants (iter);
2307 current_char_index = gtk_text_iter_get_offset (iter);
2309 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2310 return FALSE; /* can't move forward */
2312 new_char_index = current_char_index + count;
2313 gtk_text_iter_set_offset (iter, new_char_index);
2315 check_invariants (iter);
2317 /* Return FALSE if we're on the non-dereferenceable end
2320 if (gtk_text_iter_is_end (iter))
2328 * gtk_text_iter_backward_chars:
2329 * @iter: an iterator
2330 * @count: number of characters to move
2332 * Moves @count characters backward, if possible (if @count would move
2333 * past the start or end of the buffer, moves to the start or end of
2334 * the buffer). The return value indicates whether the iterator moved
2335 * onto a dereferenceable position; if the iterator didn't move, or
2336 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2337 * the function does nothing and returns %FALSE.
2339 * Return value: whether @iter moved and is dereferenceable
2343 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2345 GtkTextRealIter *real;
2347 g_return_val_if_fail (iter != NULL, FALSE);
2349 FIX_OVERFLOWS (count);
2351 real = gtk_text_iter_make_real (iter);
2355 else if (count == 0)
2358 return gtk_text_iter_forward_chars (iter, 0 - count);
2360 ensure_char_offsets (real);
2361 check_invariants (iter);
2363 /* <, not <=, because if count == segment_char_offset
2364 * we're going to the front of the segment and the any_segment
2367 if (count < real->segment_char_offset)
2369 /* Optimize the within-segment case */
2370 g_assert (real->segment->char_count > 0);
2371 g_assert (real->segment->type == >k_text_char_type);
2373 real->segment_char_offset -= count;
2374 g_assert (real->segment_char_offset >= 0);
2376 if (real->line_byte_offset >= 0)
2378 gint new_byte_offset;
2381 new_byte_offset = 0;
2383 while (i < real->segment_char_offset)
2385 const char * start = real->segment->body.chars + new_byte_offset;
2386 new_byte_offset += g_utf8_next_char (start) - start;
2391 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2392 real->segment_byte_offset = new_byte_offset;
2395 real->line_char_offset -= count;
2397 adjust_char_index (real, 0 - count);
2399 check_invariants (iter);
2405 /* We need to go back into previous segments. For now,
2406 * just keep this really simple. FIXME
2407 * use backward_indexable_segment.
2409 if (TRUE || count > MAX_LINEAR_SCAN)
2411 gint current_char_index;
2412 gint new_char_index;
2414 current_char_index = gtk_text_iter_get_offset (iter);
2416 if (current_char_index == 0)
2417 return FALSE; /* can't move backward */
2419 new_char_index = current_char_index - count;
2420 if (new_char_index < 0)
2423 gtk_text_iter_set_offset (iter, new_char_index);
2425 check_invariants (iter);
2431 /* FIXME backward_indexable_segment here */
2440 /* These two can't be implemented efficiently (always have to use
2441 * a linear scan, since that's the only way to find all the non-text
2446 * gtk_text_iter_forward_text_chars:
2447 * @iter: a #GtkTextIter
2448 * @count: number of chars to move
2450 * Moves forward by @count text characters (pixbufs, widgets,
2451 * etc. do not count as characters for this). Equivalent to moving
2452 * through the results of gtk_text_iter_get_text (), rather than
2453 * gtk_text_iter_get_slice ().
2455 * Return value: whether @iter moved and is dereferenceable
2458 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2467 * gtk_text_iter_forward_text_chars:
2468 * @iter: a #GtkTextIter
2469 * @count: number of chars to move
2471 * Moves backward by @count text characters (pixbufs, widgets,
2472 * etc. do not count as characters for this). Equivalent to moving
2473 * through the results of gtk_text_iter_get_text (), rather than
2474 * gtk_text_iter_get_slice ().
2476 * Return value: whether @iter moved and is dereferenceable
2479 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2488 * gtk_text_iter_forward_line:
2489 * @iter: an iterator
2491 * Moves @iter to the start of the next line. Returns %TRUE if there
2492 * was a next line to move to, and %FALSE if @iter was simply moved to
2493 * the end of the buffer and is now not dereferenceable, or if @iter was
2494 * already at the end of the buffer.
2496 * Return value: whether @iter can be dereferenced
2499 gtk_text_iter_forward_line (GtkTextIter *iter)
2501 GtkTextRealIter *real;
2503 g_return_val_if_fail (iter != NULL, FALSE);
2505 real = gtk_text_iter_make_real (iter);
2510 check_invariants (iter);
2512 if (forward_line_leaving_caches_unmodified (real))
2514 invalidate_char_index (real);
2515 adjust_line_number (real, 1);
2517 check_invariants (iter);
2519 if (gtk_text_iter_is_end (iter))
2526 /* On the last line, move to end of it */
2528 if (!gtk_text_iter_is_end (iter))
2529 gtk_text_iter_forward_to_end (iter);
2531 check_invariants (iter);
2537 * gtk_text_iter_backward_line:
2538 * @iter: an iterator
2540 * Moves @iter to the start of the previous line. Returns %TRUE if
2541 * @iter could be moved; i.e. if @iter was at character offset 0, this
2542 * function returns %FALSE. Therefore if @iter was already on line 0,
2543 * but not at the start of the line, @iter is snapped to the start of
2544 * the line and the function returns %TRUE. (Note that this implies that
2545 * in a loop calling this function, the line number may not change on
2546 * every iteration, if your first iteration is on line 0.)
2548 * Return value: whether @iter moved
2551 gtk_text_iter_backward_line (GtkTextIter *iter)
2553 GtkTextLine *new_line;
2554 GtkTextRealIter *real;
2555 gboolean offset_will_change;
2558 g_return_val_if_fail (iter != NULL, FALSE);
2560 real = gtk_text_iter_make_real (iter);
2565 check_invariants (iter);
2567 new_line = _gtk_text_line_previous (real->line);
2569 offset_will_change = FALSE;
2570 if (real->line_char_offset > 0)
2571 offset_will_change = TRUE;
2573 if (new_line != NULL)
2575 real->line = new_line;
2577 adjust_line_number (real, -1);
2581 if (!offset_will_change)
2585 invalidate_char_index (real);
2587 real->line_byte_offset = 0;
2588 real->line_char_offset = 0;
2590 real->segment_byte_offset = 0;
2591 real->segment_char_offset = 0;
2593 /* Find first segment in line */
2594 real->any_segment = real->line->segments;
2595 real->segment = _gtk_text_line_byte_to_segment (real->line,
2598 g_assert (offset == 0);
2600 /* Note that if we are on the first line, we snap to the start of
2601 * the first line and return TRUE, so TRUE means the iterator
2602 * changed, not that the line changed; this is maybe a bit
2603 * weird. I'm not sure there's an obvious right thing to do though.
2606 check_invariants (iter);
2613 * gtk_text_iter_forward_lines:
2614 * @iter: a #GtkTextIter
2615 * @count: number of lines to move forward
2617 * Moves @count lines forward, if possible (if @count would move
2618 * past the start or end of the buffer, moves to the start or end of
2619 * the buffer). The return value indicates whether the iterator moved
2620 * onto a dereferenceable position; if the iterator didn't move, or
2621 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2622 * the function does nothing and returns %FALSE. If @count is negative,
2623 * moves backward by 0 - @count lines.
2625 * Return value: whether @iter moved and is dereferenceable
2628 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2630 FIX_OVERFLOWS (count);
2633 return gtk_text_iter_backward_lines (iter, 0 - count);
2634 else if (count == 0)
2636 else if (count == 1)
2638 check_invariants (iter);
2639 return gtk_text_iter_forward_line (iter);
2645 if (gtk_text_iter_is_end (iter))
2648 old_line = gtk_text_iter_get_line (iter);
2650 gtk_text_iter_set_line (iter, old_line + count);
2652 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2654 /* count went past the last line, so move to end of last line */
2655 if (!gtk_text_iter_is_end (iter))
2656 gtk_text_iter_forward_to_end (iter);
2659 return !gtk_text_iter_is_end (iter);
2664 * gtk_text_iter_backward_lines:
2665 * @iter: a #GtkTextIter
2666 * @count: number of lines to move backward
2668 * Moves @count lines backward, if possible (if @count would move
2669 * past the start or end of the buffer, moves to the start or end of
2670 * the buffer). The return value indicates whether the iterator moved
2671 * onto a dereferenceable position; if the iterator didn't move, or
2672 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2673 * the function does nothing and returns %FALSE. If @count is negative,
2674 * moves forward by 0 - @count lines.
2676 * Return value: whether @iter moved and is dereferenceable
2679 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2681 FIX_OVERFLOWS (count);
2684 return gtk_text_iter_forward_lines (iter, 0 - count);
2685 else if (count == 0)
2687 else if (count == 1)
2689 return gtk_text_iter_backward_line (iter);
2695 old_line = gtk_text_iter_get_line (iter);
2697 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2699 return (gtk_text_iter_get_line (iter) != old_line);
2703 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2708 gboolean already_moved_initially);
2710 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2718 find_word_end_func (const PangoLogAttr *attrs,
2723 gboolean already_moved_initially)
2725 if (!already_moved_initially)
2728 /* Find end of next word */
2729 while (offset < min_offset + len &&
2730 !attrs[offset].is_word_end)
2733 *found_offset = offset;
2735 return offset < min_offset + len;
2739 is_word_end_func (const PangoLogAttr *attrs,
2744 return attrs[offset].is_word_end;
2748 find_word_start_func (const PangoLogAttr *attrs,
2753 gboolean already_moved_initially)
2755 if (!already_moved_initially)
2758 /* Find start of prev word */
2759 while (offset >= min_offset &&
2760 !attrs[offset].is_word_start)
2763 *found_offset = offset;
2765 return offset >= min_offset;
2769 is_word_start_func (const PangoLogAttr *attrs,
2774 return attrs[offset].is_word_start;
2778 inside_word_func (const PangoLogAttr *attrs,
2783 /* Find next word start or end */
2784 while (offset >= min_offset &&
2785 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2788 return attrs[offset].is_word_start;
2791 /* Sentence funcs */
2794 find_sentence_end_func (const PangoLogAttr *attrs,
2799 gboolean already_moved_initially)
2801 if (!already_moved_initially)
2804 /* Find end of next sentence */
2805 while (offset < min_offset + len &&
2806 !attrs[offset].is_sentence_end)
2809 *found_offset = offset;
2811 return offset < min_offset + len;
2815 is_sentence_end_func (const PangoLogAttr *attrs,
2820 return attrs[offset].is_sentence_end;
2824 find_sentence_start_func (const PangoLogAttr *attrs,
2829 gboolean already_moved_initially)
2831 if (!already_moved_initially)
2834 /* Find start of prev sentence */
2835 while (offset >= min_offset &&
2836 !attrs[offset].is_sentence_start)
2839 *found_offset = offset;
2841 return offset >= min_offset;
2845 is_sentence_start_func (const PangoLogAttr *attrs,
2850 return attrs[offset].is_sentence_start;
2854 inside_sentence_func (const PangoLogAttr *attrs,
2859 /* Find next sentence start or end */
2860 while (offset >= min_offset &&
2861 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2864 return attrs[offset].is_sentence_start;
2868 test_log_attrs (const GtkTextIter *iter,
2869 TestLogAttrFunc func)
2872 const PangoLogAttr *attrs;
2874 gboolean result = FALSE;
2876 g_return_val_if_fail (iter != NULL, FALSE);
2878 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2881 offset = gtk_text_iter_get_line_offset (iter);
2883 /* char_len may be 0 and attrs will be NULL if so, if
2884 * iter is the end iter and the last line is empty.
2886 * offset may be equal to char_len, since attrs contains an entry
2887 * for one past the end
2890 if (attrs && offset <= char_len)
2891 result = (* func) (attrs, offset, 0, char_len);
2897 find_line_log_attrs (const GtkTextIter *iter,
2898 FindLogAttrFunc func,
2900 gboolean already_moved_initially)
2903 const PangoLogAttr *attrs;
2905 gboolean result = FALSE;
2907 g_return_val_if_fail (iter != NULL, FALSE);
2909 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2912 offset = gtk_text_iter_get_line_offset (iter);
2914 /* char_len may be 0 and attrs will be NULL if so, if
2915 * iter is the end iter and the last line is empty
2919 result = (* func) (attrs, offset, 0, char_len, found_offset,
2920 already_moved_initially);
2925 /* FIXME this function is very, very gratuitously slow */
2927 find_by_log_attrs (GtkTextIter *iter,
2928 FindLogAttrFunc func,
2930 gboolean already_moved_initially)
2934 gboolean found = FALSE;
2936 g_return_val_if_fail (iter != NULL, FALSE);
2940 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2946 if (gtk_text_iter_forward_line (iter))
2947 return find_by_log_attrs (iter, func, forward,
2954 /* go to end of previous line. need to check that
2955 * line is > 0 because backward_line snaps to start of
2956 * line 0 if it's on line 0
2958 if (gtk_text_iter_get_line (iter) > 0 &&
2959 gtk_text_iter_backward_line (iter))
2961 if (!gtk_text_iter_ends_line (iter))
2962 gtk_text_iter_forward_to_line_end (iter);
2964 return find_by_log_attrs (iter, func, forward,
2973 gtk_text_iter_set_line_offset (iter, offset);
2976 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2977 !gtk_text_iter_is_end (iter);
2982 * gtk_text_iter_forward_word_end:
2983 * @iter: a #GtkTextIter
2985 * Moves forward to the next word end. (If @iter is currently on a
2986 * word end, moves forward to the next one after that.) Word breaks
2987 * are determined by Pango and should be correct for nearly any
2988 * language (if not, the correct fix would be to the Pango word break
2991 * Return value: %TRUE if @iter moved and is not the end iterator
2994 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2996 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3000 * gtk_text_iter_backward_word_start:
3001 * @iter: a #GtkTextIter
3003 * Moves backward to the previous word start. (If @iter is currently on a
3004 * word start, moves backward to the next one after that.) Word breaks
3005 * are determined by Pango and should be correct for nearly any
3006 * language (if not, the correct fix would be to the Pango word break
3009 * Return value: %TRUE if @iter moved and is not the end iterator
3012 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3014 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3017 /* FIXME a loop around a truly slow function means
3018 * a truly spectacularly slow function.
3022 * gtk_text_iter_forward_word_ends:
3023 * @iter: a #GtkTextIter
3024 * @count: number of times to move
3026 * Calls gtk_text_iter_forward_word_end() up to @count times.
3028 * Return value: %TRUE if @iter moved and is not the end iterator
3031 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3034 g_return_val_if_fail (iter != NULL, FALSE);
3036 FIX_OVERFLOWS (count);
3042 return gtk_text_iter_backward_word_starts (iter, -count);
3044 if (!gtk_text_iter_forward_word_end (iter))
3050 if (!gtk_text_iter_forward_word_end (iter))
3055 return !gtk_text_iter_is_end (iter);
3059 * gtk_text_iter_backward_word_starts
3060 * @iter: a #GtkTextIter
3061 * @count: number of times to move
3063 * Calls gtk_text_iter_backward_word_start() up to @count times.
3065 * Return value: %TRUE if @iter moved and is not the end iterator
3068 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3071 g_return_val_if_fail (iter != NULL, FALSE);
3073 FIX_OVERFLOWS (count);
3076 return gtk_text_iter_forward_word_ends (iter, -count);
3078 if (!gtk_text_iter_backward_word_start (iter))
3084 if (!gtk_text_iter_backward_word_start (iter))
3089 return !gtk_text_iter_is_end (iter);
3093 * gtk_text_iter_starts_word:
3094 * @iter: a #GtkTextIter
3096 * Determines whether @iter begins a natural-language word. Word
3097 * breaks are determined by Pango and should be correct for nearly any
3098 * language (if not, the correct fix would be to the Pango word break
3101 * Return value: %TRUE if @iter is at the start of a word
3104 gtk_text_iter_starts_word (const GtkTextIter *iter)
3106 return test_log_attrs (iter, is_word_start_func);
3110 * gtk_text_iter_ends_word:
3111 * @iter: a #GtkTextIter
3113 * Determines whether @iter ends a natural-language word. Word breaks
3114 * are determined by Pango and should be correct for nearly any
3115 * language (if not, the correct fix would be to the Pango word break
3118 * Return value: %TRUE if @iter is at the end of a word
3121 gtk_text_iter_ends_word (const GtkTextIter *iter)
3123 return test_log_attrs (iter, is_word_end_func);
3127 * gtk_text_iter_inside_word:
3128 * @iter: a #GtkTextIter
3130 * Determines whether @iter is inside a natural-language word (as
3131 * opposed to say inside some whitespace). Word breaks are determined
3132 * by Pango and should be correct for nearly any language (if not, the
3133 * correct fix would be to the Pango word break algorithms).
3135 * Return value: %TRUE if @iter is inside a word
3138 gtk_text_iter_inside_word (const GtkTextIter *iter)
3140 return test_log_attrs (iter, inside_word_func);
3144 * gtk_text_iter_starts_sentence:
3145 * @iter: a #GtkTextIter
3147 * Determines whether @iter begins a sentence. Sentence boundaries are
3148 * determined by Pango and should be correct for nearly any language
3149 * (if not, the correct fix would be to the Pango text boundary
3152 * Return value: %TRUE if @iter is at the start of a sentence.
3155 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3157 return test_log_attrs (iter, is_sentence_start_func);
3161 * gtk_text_iter_ends_sentence:
3162 * @iter: a #GtkTextIter
3164 * Determines whether @iter ends a sentence. Sentence boundaries are
3165 * determined by Pango and should be correct for nearly any language
3166 * (if not, the correct fix would be to the Pango text boundary
3169 * Return value: %TRUE if @iter is at the end of a sentence.
3172 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3174 return test_log_attrs (iter, is_sentence_end_func);
3178 * gtk_text_iter_inside_sentence:
3179 * @iter: a #GtkTextIter
3181 * Determines whether @iter is inside a sentence (as opposed to in
3182 * between two sentences, e.g. after a period and before the first
3183 * letter of the next sentence). Sentence boundaries are determined
3184 * by Pango and should be correct for nearly any language (if not, the
3185 * correct fix would be to the Pango text boundary algorithms).
3187 * Return value: %TRUE if @iter is inside a sentence.
3190 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3192 return test_log_attrs (iter, inside_sentence_func);
3196 * gtk_text_iter_forward_sentence_end:
3197 * @iter: a #GtkTextIter
3199 * Moves forward to the next sentence end. (If @iter is at the end of
3200 * a sentence, moves to the next end of sentence.) Sentence
3201 * boundaries are determined by Pango and should be correct for nearly
3202 * any language (if not, the correct fix would be to the Pango text
3203 * boundary algorithms).
3205 * Return value: %TRUE if @iter moved and is not the end iterator
3208 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3210 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3214 * gtk_text_iter_backward_sentence_start:
3215 * @iter: a #GtkTextIter
3217 * Moves backward to the previous sentence start; if @iter is already at
3218 * the start of a sentence, moves backward to the next one. Sentence
3219 * boundaries are determined by Pango and should be correct for nearly
3220 * any language (if not, the correct fix would be to the Pango text
3221 * boundary algorithms).
3223 * Return value: %TRUE if @iter moved and is not the end iterator
3226 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3228 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3231 /* FIXME a loop around a truly slow function means
3232 * a truly spectacularly slow function.
3235 * gtk_text_iter_forward_sentence_ends:
3236 * @iter: a #GtkTextIter
3237 * @count: number of sentences to move
3239 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3240 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3241 * negative, moves backward instead of forward.
3243 * Return value: %TRUE if @iter moved and is not the end iterator
3246 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3249 g_return_val_if_fail (iter != NULL, FALSE);
3255 return gtk_text_iter_backward_sentence_starts (iter, -count);
3257 if (!gtk_text_iter_forward_sentence_end (iter))
3263 if (!gtk_text_iter_forward_sentence_end (iter))
3268 return !gtk_text_iter_is_end (iter);
3272 * gtk_text_iter_backward_sentence_starts:
3273 * @iter: a #GtkTextIter
3274 * @count: number of sentences to move
3276 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3277 * or until it returns %FALSE. If @count is negative, moves forward
3278 * instead of backward.
3280 * Return value: %TRUE if @iter moved and is not the end iterator
3283 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3286 g_return_val_if_fail (iter != NULL, FALSE);
3289 return gtk_text_iter_forward_sentence_ends (iter, -count);
3291 if (!gtk_text_iter_backward_sentence_start (iter))
3297 if (!gtk_text_iter_backward_sentence_start (iter))
3302 return !gtk_text_iter_is_end (iter);
3306 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3311 gboolean already_moved_initially)
3313 if (!already_moved_initially)
3316 while (offset < (min_offset + len) &&
3317 !attrs[offset].is_cursor_position)
3320 *found_offset = offset;
3322 return offset < (min_offset + len);
3326 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3331 gboolean already_moved_initially)
3333 if (!already_moved_initially)
3336 while (offset > min_offset &&
3337 !attrs[offset].is_cursor_position)
3340 *found_offset = offset;
3342 return offset >= min_offset;
3346 is_cursor_pos_func (const PangoLogAttr *attrs,
3351 return attrs[offset].is_cursor_position;
3355 * gtk_text_iter_forward_cursor_position:
3356 * @iter: a #GtkTextIter
3358 * Moves @iter forward by a single cursor position. Cursor positions
3359 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3360 * surprisingly, there may not be a cursor position between all
3361 * characters. The most common example for European languages would be
3362 * a carriage return/newline sequence. For some Unicode characters,
3363 * the equivalent of say the letter "a" with an accent mark will be
3364 * represented as two characters, first the letter then a "combining
3365 * mark" that causes the accent to be rendered; so the cursor can't go
3366 * between those two characters. See also the #PangoLogAttr structure and
3367 * pango_break() function.
3369 * Return value: %TRUE if we moved and the new position is dereferenceable
3372 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3374 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3378 * gtk_text_iter_backward_cursor_position:
3379 * @iter: a #GtkTextIter
3381 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3383 * Return value: %TRUE if we moved and the new position is dereferenceable
3386 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3388 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3392 * gtk_text_iter_forward_cursor_positions:
3393 * @iter: a #GtkTextIter
3394 * @count: number of positions to move
3396 * Moves up to @count cursor positions. See
3397 * gtk_text_iter_forward_cursor_position() for details.
3399 * Return value: %TRUE if we moved and the new position is dereferenceable
3402 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3405 g_return_val_if_fail (iter != NULL, FALSE);
3407 FIX_OVERFLOWS (count);
3413 return gtk_text_iter_backward_cursor_positions (iter, -count);
3415 if (!gtk_text_iter_forward_cursor_position (iter))
3421 if (!gtk_text_iter_forward_cursor_position (iter))
3426 return !gtk_text_iter_is_end (iter);
3430 * gtk_text_iter_backward_cursor_positions:
3431 * @iter: a #GtkTextIter
3432 * @count: number of positions to move
3434 * Moves up to @count cursor positions. See
3435 * gtk_text_iter_forward_cursor_position() for details.
3437 * Return value: %TRUE if we moved and the new position is dereferenceable
3440 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3443 g_return_val_if_fail (iter != NULL, FALSE);
3445 FIX_OVERFLOWS (count);
3451 return gtk_text_iter_forward_cursor_positions (iter, -count);
3453 if (!gtk_text_iter_backward_cursor_position (iter))
3459 if (!gtk_text_iter_backward_cursor_position (iter))
3464 return !gtk_text_iter_is_end (iter);
3468 * gtk_text_iter_is_cursor_position:
3469 * @iter: a #GtkTextIter
3471 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3472 * pango_break() for details on what a cursor position is.
3474 * Return value: %TRUE if the cursor can be placed at @iter
3477 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3479 return test_log_attrs (iter, is_cursor_pos_func);
3483 * gtk_text_iter_set_line_offset:
3484 * @iter: a #GtkTextIter
3485 * @char_on_line: a character offset relative to the start of @iter's current line
3487 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3488 * (not byte) offset. The given character offset must be less than or
3489 * equal to the number of characters in the line; if equal, @iter
3490 * moves to the start of the next line. See
3491 * gtk_text_iter_set_line_index() if you have a byte index rather than
3492 * a character offset.
3496 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3499 GtkTextRealIter *real;
3502 g_return_if_fail (iter != NULL);
3504 real = gtk_text_iter_make_surreal (iter);
3509 check_invariants (iter);
3511 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3513 g_return_if_fail (char_on_line <= chars_in_line);
3515 if (char_on_line < chars_in_line)
3516 iter_set_from_char_offset (real, real->line, char_on_line);
3518 gtk_text_iter_forward_line (iter); /* set to start of next line */
3520 check_invariants (iter);
3524 * gtk_text_iter_set_line_index:
3525 * @iter: a #GtkTextIter
3526 * @byte_on_line: a byte index relative to the start of @iter's current line
3528 * Same as gtk_text_iter_set_line_offset(), but works with a
3529 * <emphasis>byte</emphasis> index. The given byte index must be at
3530 * the start of a character, it can't be in the middle of a UTF-8
3531 * encoded character.
3535 gtk_text_iter_set_line_index (GtkTextIter *iter,
3538 GtkTextRealIter *real;
3541 g_return_if_fail (iter != NULL);
3543 real = gtk_text_iter_make_surreal (iter);
3548 check_invariants (iter);
3550 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3552 g_return_if_fail (byte_on_line <= bytes_in_line);
3554 if (byte_on_line < bytes_in_line)
3555 iter_set_from_byte_offset (real, real->line, byte_on_line);
3557 gtk_text_iter_forward_line (iter);
3559 if (real->segment->type == >k_text_char_type &&
3560 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3561 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3562 "character; this will crash the text buffer. "
3563 "Byte indexes must refer to the start of a character.",
3564 G_STRLOC, byte_on_line);
3566 check_invariants (iter);
3571 * gtk_text_iter_set_visible_line_offset:
3572 * @iter: a #GtkTextIter
3573 * @char_on_line: a character offset
3575 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3576 * characters, i.e. text with a tag making it invisible is not
3577 * counted in the offset.
3580 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3583 gint chars_seen = 0;
3586 g_return_if_fail (iter != NULL);
3590 /* For now we use a ludicrously slow implementation */
3591 while (chars_seen < char_on_line)
3593 if (!_gtk_text_btree_char_is_invisible (&pos))
3596 if (!gtk_text_iter_forward_char (&pos))
3599 if (chars_seen == char_on_line)
3603 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3606 gtk_text_iter_forward_line (iter);
3610 bytes_in_char (GtkTextIter *iter)
3612 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3616 * gtk_text_iter_set_visible_line_index:
3617 * @iter: a #GtkTextIter
3618 * @byte_on_line: a byte index
3620 * Like gtk_text_iter_set_line_index(), but the index is in visible
3621 * bytes, i.e. text with a tag making it invisible is not counted
3625 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3628 gint bytes_seen = 0;
3631 g_return_if_fail (iter != NULL);
3635 /* For now we use a ludicrously slow implementation */
3636 while (bytes_seen < byte_on_line)
3638 if (!_gtk_text_btree_char_is_invisible (&pos))
3639 bytes_seen += bytes_in_char (&pos);
3641 if (!gtk_text_iter_forward_char (&pos))
3644 if (bytes_seen >= byte_on_line)
3648 if (bytes_seen > byte_on_line)
3649 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3650 "character; this will crash the text buffer. "
3651 "Byte indexes must refer to the start of a character.",
3652 G_STRLOC, byte_on_line);
3654 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3657 gtk_text_iter_forward_line (iter);
3661 * gtk_text_iter_set_line:
3662 * @iter: a #GtkTextIter
3663 * @line_number: line number (counted from 0)
3665 * Moves iterator @iter to the start of the line @line_number. If
3666 * @line_number is negative or larger than the number of lines in the
3667 * buffer, moves @iter to the start of the last line in the buffer.
3671 gtk_text_iter_set_line (GtkTextIter *iter,
3676 GtkTextRealIter *real;
3678 g_return_if_fail (iter != NULL);
3680 real = gtk_text_iter_make_surreal (iter);
3685 check_invariants (iter);
3687 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3689 iter_set_from_char_offset (real, line, 0);
3691 /* We might as well cache this, since we know it. */
3692 real->cached_line_number = real_line;
3694 check_invariants (iter);
3698 * gtk_text_iter_set_offset:
3699 * @iter: a #GtkTextIter
3700 * @char_offset: a character number
3702 * Sets @iter to point to @char_offset. @char_offset counts from the start
3703 * of the entire text buffer, starting with 0.
3706 gtk_text_iter_set_offset (GtkTextIter *iter,
3710 GtkTextRealIter *real;
3712 gint real_char_index;
3714 g_return_if_fail (iter != NULL);
3716 real = gtk_text_iter_make_surreal (iter);
3721 check_invariants (iter);
3723 if (real->cached_char_index >= 0 &&
3724 real->cached_char_index == char_offset)
3727 line = _gtk_text_btree_get_line_at_char (real->tree,
3732 iter_set_from_char_offset (real, line, real_char_index - line_start);
3734 /* Go ahead and cache this since we have it. */
3735 real->cached_char_index = real_char_index;
3737 check_invariants (iter);
3741 * gtk_text_iter_forward_to_end:
3742 * @iter: a #GtkTextIter
3744 * Moves @iter forward to the "end iterator," which points one past the last
3745 * valid character in the buffer. gtk_text_iter_get_char() called on the
3746 * end iterator returns 0, which is convenient for writing loops.
3749 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3751 GtkTextBuffer *buffer;
3752 GtkTextRealIter *real;
3754 g_return_if_fail (iter != NULL);
3756 real = gtk_text_iter_make_surreal (iter);
3761 buffer = _gtk_text_btree_get_buffer (real->tree);
3763 gtk_text_buffer_get_end_iter (buffer, iter);
3766 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3767 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3768 * If all else fails we could cache the para delimiter pos in the iter.
3769 * I think forward_to_line_end() actually gets called fairly often.
3772 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3777 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3778 _gtk_text_iter_get_btree (&end)))
3780 gtk_text_iter_forward_to_end (&end);
3784 /* if we aren't on the last line, go forward to start of next line, then scan
3785 * back for the delimiters on the previous line
3787 gtk_text_iter_forward_line (&end);
3788 gtk_text_iter_backward_char (&end);
3789 while (!gtk_text_iter_ends_line (&end))
3790 gtk_text_iter_backward_char (&end);
3793 return gtk_text_iter_get_line_offset (&end);
3797 * gtk_text_iter_forward_to_line_end:
3798 * @iter: a #GtkTextIter
3800 * Moves the iterator to point to the paragraph delimiter characters,
3801 * which will be either a newline, a carriage return, a carriage
3802 * return/newline in sequence, or the Unicode paragraph separator
3803 * character. If the iterator is already at the paragraph delimiter
3804 * characters, moves to the paragraph delimiter characters for the
3805 * next line. If @iter is on the last line in the buffer, which does
3806 * not end in paragraph delimiters, moves to the end iterator (end of
3807 * the last line), and returns %FALSE.
3809 * Return value: %TRUE if we moved and the new location is not the end iterator
3812 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3814 gint current_offset;
3818 g_return_val_if_fail (iter != NULL, FALSE);
3820 current_offset = gtk_text_iter_get_line_offset (iter);
3821 new_offset = find_paragraph_delimiter_for_line (iter);
3823 if (current_offset < new_offset)
3825 /* Move to end of this line. */
3826 gtk_text_iter_set_line_offset (iter, new_offset);
3827 return !gtk_text_iter_is_end (iter);
3831 /* Move to end of next line. */
3832 if (gtk_text_iter_forward_line (iter))
3834 /* We don't want to move past all
3837 if (!gtk_text_iter_ends_line (iter))
3838 gtk_text_iter_forward_to_line_end (iter);
3839 return !gtk_text_iter_is_end (iter);
3847 * gtk_text_iter_forward_to_tag_toggle:
3848 * @iter: a #GtkTextIter
3849 * @tag: a #GtkTextTag, or %NULL
3851 * Moves forward to the next toggle (on or off) of the
3852 * #GtkTextTag @tag, or to the next toggle of any tag if
3853 * @tag is %NULL. If no matching tag toggles are found,
3854 * returns %FALSE, otherwise %TRUE. Does not return toggles
3855 * located at @iter, only toggles after @iter. Sets @iter to
3856 * the location of the toggle, or to the end of the buffer
3857 * if no toggle is found.
3859 * Return value: whether we found a tag toggle after @iter
3862 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3865 GtkTextLine *next_line;
3866 GtkTextLine *current_line;
3867 GtkTextRealIter *real;
3869 g_return_val_if_fail (iter != NULL, FALSE);
3871 real = gtk_text_iter_make_real (iter);
3876 check_invariants (iter);
3878 current_line = real->line;
3879 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3882 while (_gtk_text_iter_forward_indexable_segment (iter))
3884 /* If we went forward to a line that couldn't contain a toggle
3885 for the tag, then skip forward to a line that could contain
3886 it. This potentially skips huge hunks of the tree, so we
3887 aren't a purely linear search. */
3888 if (real->line != current_line)
3890 if (next_line == NULL)
3892 /* End of search. Set to end of buffer. */
3893 _gtk_text_btree_get_end_iter (real->tree, iter);
3897 if (real->line != next_line)
3898 iter_set_from_byte_offset (real, next_line, 0);
3900 current_line = real->line;
3901 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3906 if (gtk_text_iter_toggles_tag (iter, tag))
3908 /* If there's a toggle here, it isn't indexable so
3909 any_segment can't be the indexable segment. */
3910 g_assert (real->any_segment != real->segment);
3915 /* Check end iterator for tags */
3916 if (gtk_text_iter_toggles_tag (iter, tag))
3918 /* If there's a toggle here, it isn't indexable so
3919 any_segment can't be the indexable segment. */
3920 g_assert (real->any_segment != real->segment);
3924 /* Reached end of buffer */
3929 * gtk_text_iter_backward_to_tag_toggle:
3930 * @iter: a #GtkTextIter
3931 * @tag: a #GtkTextTag, or %NULL
3933 * Moves backward to the next toggle (on or off) of the
3934 * #GtkTextTag @tag, or to the next toggle of any tag if
3935 * @tag is %NULL. If no matching tag toggles are found,
3936 * returns %FALSE, otherwise %TRUE. Does not return toggles
3937 * located at @iter, only toggles before @iter. Sets @iter
3938 * to the location of the toggle, or the start of the buffer
3939 * if no toggle is found.
3941 * Return value: whether we found a tag toggle before @iter
3944 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3947 GtkTextLine *prev_line;
3948 GtkTextLine *current_line;
3949 GtkTextRealIter *real;
3951 g_return_val_if_fail (iter != NULL, FALSE);
3953 real = gtk_text_iter_make_real (iter);
3958 check_invariants (iter);
3960 current_line = real->line;
3961 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3965 /* If we're at segment start, go to the previous segment;
3966 * if mid-segment, snap to start of current segment.
3968 if (is_segment_start (real))
3970 if (!_gtk_text_iter_backward_indexable_segment (iter))
3975 ensure_char_offsets (real);
3977 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3983 /* If we went backward to a line that couldn't contain a toggle
3984 * for the tag, then skip backward further to a line that
3985 * could contain it. This potentially skips huge hunks of the
3986 * tree, so we aren't a purely linear search.
3988 if (real->line != current_line)
3990 if (prev_line == NULL)
3992 /* End of search. Set to start of buffer. */
3993 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3997 if (real->line != prev_line)
3999 /* Set to last segment in prev_line (could do this
4002 iter_set_from_byte_offset (real, prev_line, 0);
4004 while (!at_last_indexable_segment (real))
4005 _gtk_text_iter_forward_indexable_segment (iter);
4008 current_line = real->line;
4009 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4014 if (gtk_text_iter_toggles_tag (iter, tag))
4016 /* If there's a toggle here, it isn't indexable so
4017 * any_segment can't be the indexable segment.
4019 g_assert (real->any_segment != real->segment);
4023 while (_gtk_text_iter_backward_indexable_segment (iter));
4025 /* Reached front of buffer */
4030 matches_pred (GtkTextIter *iter,
4031 GtkTextCharPredicate pred,
4036 ch = gtk_text_iter_get_char (iter);
4038 return (*pred) (ch, user_data);
4042 * gtk_text_iter_forward_find_char:
4043 * @iter: a #GtkTextIter
4044 * @pred: a function to be called on each character
4045 * @user_data: user data for @pred
4046 * @limit: search limit, or %NULL for none
4048 * Advances @iter, calling @pred on each character. If
4049 * @pred returns %TRUE, returns %TRUE and stops scanning.
4050 * If @pred never returns %TRUE, @iter is set to @limit if
4051 * @limit is non-%NULL, otherwise to the end iterator.
4053 * Return value: whether a match was found
4056 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4057 GtkTextCharPredicate pred,
4059 const GtkTextIter *limit)
4061 g_return_val_if_fail (iter != NULL, FALSE);
4062 g_return_val_if_fail (pred != NULL, FALSE);
4065 gtk_text_iter_compare (iter, limit) >= 0)
4068 while ((limit == NULL ||
4069 !gtk_text_iter_equal (limit, iter)) &&
4070 gtk_text_iter_forward_char (iter))
4072 if (matches_pred (iter, pred, user_data))
4080 * gtk_text_iter_backward_find_char:
4081 * @iter: a #GtkTextIter
4082 * @pred: function to be called on each character
4083 * @user_data: user data for @pred
4084 * @limit: search limit, or %NULL for none
4086 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4088 * Return value: whether a match was found
4091 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4092 GtkTextCharPredicate pred,
4094 const GtkTextIter *limit)
4096 g_return_val_if_fail (iter != NULL, FALSE);
4097 g_return_val_if_fail (pred != NULL, FALSE);
4100 gtk_text_iter_compare (iter, limit) <= 0)
4103 while ((limit == NULL ||
4104 !gtk_text_iter_equal (limit, iter)) &&
4105 gtk_text_iter_backward_char (iter))
4107 if (matches_pred (iter, pred, user_data))
4115 forward_chars_with_skipping (GtkTextIter *iter,
4117 gboolean skip_invisible,
4118 gboolean skip_nontext)
4123 g_return_if_fail (count >= 0);
4129 gboolean ignored = FALSE;
4132 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4137 _gtk_text_btree_char_is_invisible (iter))
4140 gtk_text_iter_forward_char (iter);
4148 lines_match (const GtkTextIter *start,
4149 const gchar **lines,
4150 gboolean visible_only,
4152 GtkTextIter *match_start,
4153 GtkTextIter *match_end)
4160 if (*lines == NULL || **lines == '\0')
4163 *match_start = *start;
4166 *match_end = *start;
4171 gtk_text_iter_forward_line (&next);
4173 /* No more text in buffer, but *lines is nonempty */
4174 if (gtk_text_iter_equal (start, &next))
4182 line_text = gtk_text_iter_get_visible_slice (start, &next);
4184 line_text = gtk_text_iter_get_slice (start, &next);
4189 line_text = gtk_text_iter_get_visible_text (start, &next);
4191 line_text = gtk_text_iter_get_text (start, &next);
4194 if (match_start) /* if this is the first line we're matching */
4195 found = strstr (line_text, *lines);
4198 /* If it's not the first line, we have to match from the
4199 * start of the line.
4201 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4213 /* Get offset to start of search string */
4214 offset = g_utf8_strlen (line_text, found - line_text);
4218 /* If match start needs to be returned, set it to the
4219 * start of the search string.
4223 *match_start = next;
4225 forward_chars_with_skipping (match_start, offset,
4226 visible_only, !slice);
4229 /* Go to end of search string */
4230 offset += g_utf8_strlen (*lines, -1);
4232 forward_chars_with_skipping (&next, offset,
4233 visible_only, !slice);
4242 /* pass NULL for match_start, since we don't need to find the
4245 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4248 /* strsplit () that retains the delimiter as part of the string. */
4250 strbreakup (const char *string,
4251 const char *delimiter,
4254 GSList *string_list = NULL, *slist;
4255 gchar **str_array, *s;
4258 g_return_val_if_fail (string != NULL, NULL);
4259 g_return_val_if_fail (delimiter != NULL, NULL);
4262 max_tokens = G_MAXINT;
4264 s = strstr (string, delimiter);
4267 guint delimiter_len = strlen (delimiter);
4274 len = s - string + delimiter_len;
4275 new_string = g_new (gchar, len + 1);
4276 strncpy (new_string, string, len);
4277 new_string[len] = 0;
4278 string_list = g_slist_prepend (string_list, new_string);
4280 string = s + delimiter_len;
4281 s = strstr (string, delimiter);
4283 while (--max_tokens && s);
4288 string_list = g_slist_prepend (string_list, g_strdup (string));
4291 str_array = g_new (gchar*, n);
4295 str_array[i--] = NULL;
4296 for (slist = string_list; slist; slist = slist->next)
4297 str_array[i--] = slist->data;
4299 g_slist_free (string_list);
4305 * gtk_text_iter_forward_search:
4306 * @iter: start of search
4307 * @str: a search string
4308 * @flags: flags affecting how the search is done
4309 * @match_start: return location for start of match, or %NULL
4310 * @match_end: return location for end of match, or %NULL
4311 * @limit: bound for the search, or %NULL for the end of the buffer
4313 * Searches forward for @str. Any match is returned as the range
4314 * @match_start, @match_end. The search will not continue past
4315 * @limit. Note that a search is a linear or O(n) operation, so you
4316 * may wish to use @limit to avoid locking up your UI on large
4319 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4320 * have invisible text interspersed in @str. i.e. @str will be a
4321 * possibly-noncontiguous subsequence of the matched range. similarly,
4322 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4323 * pixbufs or child widgets mixed inside the matched range. If these
4324 * flags are not given, the match must be exact; the special 0xFFFC
4325 * character in @str will match embedded pixbufs or child widgets.
4327 * Return value: whether a match was found
4330 gtk_text_iter_forward_search (const GtkTextIter *iter,
4332 GtkTextSearchFlags flags,
4333 GtkTextIter *match_start,
4334 GtkTextIter *match_end,
4335 const GtkTextIter *limit)
4337 gchar **lines = NULL;
4339 gboolean retval = FALSE;
4341 gboolean visible_only;
4344 g_return_val_if_fail (iter != NULL, FALSE);
4345 g_return_val_if_fail (str != NULL, FALSE);
4348 gtk_text_iter_compare (iter, limit) >= 0)
4353 /* If we can move one char, return the empty string there */
4356 if (gtk_text_iter_forward_char (&match))
4359 gtk_text_iter_equal (&match, limit))
4363 *match_start = match;
4372 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4373 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4375 /* locate all lines */
4377 lines = strbreakup (str, "\n", -1);
4383 /* This loop has an inefficient worst-case, where
4384 * gtk_text_iter_get_text () is called repeatedly on
4390 gtk_text_iter_compare (&search, limit) >= 0)
4393 if (lines_match (&search, (const gchar**)lines,
4394 visible_only, slice, &match, &end))
4396 if (limit == NULL ||
4398 gtk_text_iter_compare (&end, limit) < 0))
4403 *match_start = match;
4412 while (gtk_text_iter_forward_line (&search));
4414 g_strfreev ((gchar**)lines);
4420 vectors_equal_ignoring_trailing (gchar **vec1,
4423 /* Ignores trailing chars in vec2's last line */
4432 if (strcmp (*i1, *i2) != 0)
4434 if (*(i2 + 1) == NULL) /* if this is the last line */
4436 gint len1 = strlen (*i1);
4437 gint len2 = strlen (*i2);
4440 strncmp (*i1, *i2, len1) == 0)
4442 /* We matched ignoring the trailing stuff in vec2 */
4467 typedef struct _LinesWindow LinesWindow;
4473 GtkTextIter first_line_start;
4474 GtkTextIter first_line_end;
4476 gboolean visible_only;
4480 lines_window_init (LinesWindow *win,
4481 const GtkTextIter *start)
4484 GtkTextIter line_start;
4485 GtkTextIter line_end;
4487 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4490 if (gtk_text_iter_is_start (start) ||
4491 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4493 /* Already at the end, or not enough lines to match */
4494 win->lines = g_new0 (gchar*, 1);
4499 line_start = *start;
4502 /* Move to start iter to start of line */
4503 gtk_text_iter_set_line_offset (&line_start, 0);
4505 if (gtk_text_iter_equal (&line_start, &line_end))
4507 /* we were already at the start; so go back one line */
4508 gtk_text_iter_backward_line (&line_start);
4511 win->first_line_start = line_start;
4512 win->first_line_end = line_end;
4514 win->lines = g_new0 (gchar*, win->n_lines + 1);
4516 i = win->n_lines - 1;
4523 if (win->visible_only)
4524 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4526 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4530 if (win->visible_only)
4531 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4533 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4536 win->lines[i] = line_text;
4538 line_end = line_start;
4539 gtk_text_iter_backward_line (&line_start);
4546 lines_window_back (LinesWindow *win)
4548 GtkTextIter new_start;
4551 new_start = win->first_line_start;
4553 if (!gtk_text_iter_backward_line (&new_start))
4557 win->first_line_start = new_start;
4558 win->first_line_end = new_start;
4560 gtk_text_iter_forward_line (&win->first_line_end);
4565 if (win->visible_only)
4566 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4567 &win->first_line_end);
4569 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4570 &win->first_line_end);
4574 if (win->visible_only)
4575 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4576 &win->first_line_end);
4578 line_text = gtk_text_iter_get_text (&win->first_line_start,
4579 &win->first_line_end);
4582 /* Move lines to make room for first line. */
4583 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4585 *win->lines = line_text;
4587 /* Free old last line and NULL-terminate */
4588 g_free (win->lines[win->n_lines]);
4589 win->lines[win->n_lines] = NULL;
4595 lines_window_free (LinesWindow *win)
4597 g_strfreev (win->lines);
4601 my_strrstr (const gchar *haystack,
4602 const gchar *needle)
4604 /* FIXME GLib should have a nice implementation in it, this
4608 gint haystack_len = strlen (haystack);
4609 gint needle_len = strlen (needle);
4610 const gchar *needle_end = needle + needle_len;
4611 const gchar *haystack_rend = haystack - 1;
4612 const gchar *needle_rend = needle - 1;
4615 p = haystack + haystack_len;
4616 while (p != haystack)
4618 const gchar *n = needle_end - 1;
4619 const gchar *s = p - 1;
4620 while (s != haystack_rend &&
4628 if (n == needle_rend)
4638 * gtk_text_iter_backward_search:
4639 * @iter: a #GtkTextIter where the search begins
4640 * @str: search string
4641 * @flags: bitmask of flags affecting the search
4642 * @match_start: return location for start of match, or %NULL
4643 * @match_end: return location for end of match, or %NULL
4644 * @limit: location of last possible @match_start, or %NULL for start of buffer
4646 * Same as gtk_text_iter_forward_search(), but moves backward.
4648 * Return value: whether a match was found
4651 gtk_text_iter_backward_search (const GtkTextIter *iter,
4653 GtkTextSearchFlags flags,
4654 GtkTextIter *match_start,
4655 GtkTextIter *match_end,
4656 const GtkTextIter *limit)
4658 gchar **lines = NULL;
4662 gboolean retval = FALSE;
4663 gboolean visible_only;
4666 g_return_val_if_fail (iter != NULL, FALSE);
4667 g_return_val_if_fail (str != NULL, FALSE);
4670 gtk_text_iter_compare (limit, iter) > 0)
4675 /* If we can move one char, return the empty string there */
4676 GtkTextIter match = *iter;
4678 if (limit && gtk_text_iter_equal (limit, &match))
4681 if (gtk_text_iter_backward_char (&match))
4684 *match_start = match;
4693 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4694 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4696 /* locate all lines */
4698 lines = strbreakup (str, "\n", -1);
4708 win.n_lines = n_lines;
4710 win.visible_only = visible_only;
4712 lines_window_init (&win, iter);
4714 if (*win.lines == NULL)
4719 gchar *first_line_match;
4722 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4724 /* We're now before the search limit, abort. */
4728 /* If there are multiple lines, the first line will
4729 * end in '\n', so this will only match at the
4730 * end of the first line, which is correct.
4732 first_line_match = my_strrstr (*win.lines, *lines);
4734 if (first_line_match &&
4735 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4740 GtkTextIter start_tmp;
4742 /* Offset to start of search string */
4743 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4745 next = win.first_line_start;
4747 forward_chars_with_skipping (&start_tmp, offset,
4748 visible_only, !slice);
4751 gtk_text_iter_compare (limit, &start_tmp) > 0)
4752 goto out; /* match was bogus */
4755 *match_start = start_tmp;
4757 /* Go to end of search string */
4761 offset += g_utf8_strlen (*l, -1);
4765 forward_chars_with_skipping (&next, offset,
4766 visible_only, !slice);
4775 while (lines_window_back (&win));
4778 lines_window_free (&win);
4789 * gtk_text_iter_equal:
4790 * @lhs: a #GtkTextIter
4791 * @rhs: another #GtkTextIter
4793 * Tests whether two iterators are equal, using the fastest possible
4794 * mechanism. This function is very fast; you can expect it to perform
4795 * better than e.g. getting the character offset for each iterator and
4796 * comparing the offsets yourself. Also, it's a bit faster than
4797 * gtk_text_iter_compare().
4799 * Return value: %TRUE if the iterators point to the same place in the buffer
4802 gtk_text_iter_equal (const GtkTextIter *lhs,
4803 const GtkTextIter *rhs)
4805 GtkTextRealIter *real_lhs;
4806 GtkTextRealIter *real_rhs;
4808 real_lhs = (GtkTextRealIter*)lhs;
4809 real_rhs = (GtkTextRealIter*)rhs;
4811 check_invariants (lhs);
4812 check_invariants (rhs);
4814 if (real_lhs->line != real_rhs->line)
4816 else if (real_lhs->line_byte_offset >= 0 &&
4817 real_rhs->line_byte_offset >= 0)
4818 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4821 /* the ensure_char_offsets () calls do nothing if the char offsets
4822 are already up-to-date. */
4823 ensure_char_offsets (real_lhs);
4824 ensure_char_offsets (real_rhs);
4825 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4830 * gtk_text_iter_compare:
4831 * @lhs: a #GtkTextIter
4832 * @rhs: another #GtkTextIter
4834 * A qsort()-style function that returns negative if @lhs is less than
4835 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4836 * Ordering is in character offset order, i.e. the first character in the buffer
4837 * is less than the second character in the buffer.
4839 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4842 gtk_text_iter_compare (const GtkTextIter *lhs,
4843 const GtkTextIter *rhs)
4845 GtkTextRealIter *real_lhs;
4846 GtkTextRealIter *real_rhs;
4848 real_lhs = gtk_text_iter_make_surreal (lhs);
4849 real_rhs = gtk_text_iter_make_surreal (rhs);
4851 if (real_lhs == NULL ||
4853 return -1; /* why not */
4855 check_invariants (lhs);
4856 check_invariants (rhs);
4858 if (real_lhs->line == real_rhs->line)
4860 gint left_index, right_index;
4862 if (real_lhs->line_byte_offset >= 0 &&
4863 real_rhs->line_byte_offset >= 0)
4865 left_index = real_lhs->line_byte_offset;
4866 right_index = real_rhs->line_byte_offset;
4870 /* the ensure_char_offsets () calls do nothing if
4871 the offsets are already up-to-date. */
4872 ensure_char_offsets (real_lhs);
4873 ensure_char_offsets (real_rhs);
4874 left_index = real_lhs->line_char_offset;
4875 right_index = real_rhs->line_char_offset;
4878 if (left_index < right_index)
4880 else if (left_index > right_index)
4889 line1 = gtk_text_iter_get_line (lhs);
4890 line2 = gtk_text_iter_get_line (rhs);
4893 else if (line1 > line2)
4901 * gtk_text_iter_in_range:
4902 * @iter: a #GtkTextIter
4903 * @start: start of range
4904 * @end: end of range
4906 * Checks whether @iter falls in the range [@start, @end).
4907 * @start and @end must be in ascending order.
4909 * Return value: %TRUE if @iter is in the range
4912 gtk_text_iter_in_range (const GtkTextIter *iter,
4913 const GtkTextIter *start,
4914 const GtkTextIter *end)
4916 g_return_val_if_fail (iter != NULL, FALSE);
4917 g_return_val_if_fail (start != NULL, FALSE);
4918 g_return_val_if_fail (end != NULL, FALSE);
4919 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4921 return gtk_text_iter_compare (iter, start) >= 0 &&
4922 gtk_text_iter_compare (iter, end) < 0;
4926 * gtk_text_iter_order:
4927 * @first: a #GtkTextIter
4928 * @second: another #GtkTextIter
4930 * Swaps the value of @first and @second if @second comes before
4931 * @first in the buffer. That is, ensures that @first and @second are
4932 * in sequence. Most text buffer functions that take a range call this
4933 * automatically on your behalf, so there's no real reason to call it yourself
4934 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4935 * that expect a pre-sorted range.
4939 gtk_text_iter_order (GtkTextIter *first,
4940 GtkTextIter *second)
4942 g_return_if_fail (first != NULL);
4943 g_return_if_fail (second != NULL);
4945 if (gtk_text_iter_compare (first, second) > 0)
4956 * Init iterators from the BTree
4960 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4964 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4965 gint real_char_index;
4969 g_return_if_fail (iter != NULL);
4970 g_return_if_fail (tree != NULL);
4972 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4973 &line_start, &real_char_index);
4975 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4977 real->cached_char_index = real_char_index;
4979 check_invariants (iter);
4983 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4988 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4992 g_return_if_fail (iter != NULL);
4993 g_return_if_fail (tree != NULL);
4995 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
4997 iter_init_from_char_offset (iter, tree, line, char_on_line);
4999 /* We might as well cache this, since we know it. */
5000 real->cached_line_number = real_line;
5002 check_invariants (iter);
5006 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5011 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5015 g_return_if_fail (iter != NULL);
5016 g_return_if_fail (tree != NULL);
5018 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5020 iter_init_from_byte_offset (iter, tree, line, byte_index);
5022 /* We might as well cache this, since we know it. */
5023 real->cached_line_number = real_line;
5025 check_invariants (iter);
5029 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5034 g_return_if_fail (iter != NULL);
5035 g_return_if_fail (tree != NULL);
5036 g_return_if_fail (line != NULL);
5038 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5040 check_invariants (iter);
5044 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5050 g_return_val_if_fail (iter != NULL, FALSE);
5051 g_return_val_if_fail (tree != NULL, FALSE);
5053 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5057 /* Set iter to last in tree */
5058 _gtk_text_btree_get_end_iter (tree, iter);
5059 check_invariants (iter);
5064 iter_init_from_byte_offset (iter, tree, line, 0);
5065 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5066 check_invariants (iter);
5072 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5076 g_return_val_if_fail (iter != NULL, FALSE);
5077 g_return_val_if_fail (tree != NULL, FALSE);
5079 _gtk_text_btree_get_end_iter (tree, iter);
5080 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5081 check_invariants (iter);
5087 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5089 const gchar *mark_name)
5093 g_return_val_if_fail (iter != NULL, FALSE);
5094 g_return_val_if_fail (tree != NULL, FALSE);
5096 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5102 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5103 check_invariants (iter);
5109 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5113 GtkTextLineSegment *seg;
5115 g_return_if_fail (iter != NULL);
5116 g_return_if_fail (tree != NULL);
5117 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5119 seg = mark->segment;
5121 iter_init_from_segment (iter, tree,
5122 seg->body.mark.line, seg);
5123 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5124 check_invariants (iter);
5128 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5130 GtkTextChildAnchor *anchor)
5132 GtkTextLineSegment *seg;
5134 g_return_if_fail (iter != NULL);
5135 g_return_if_fail (tree != NULL);
5136 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5138 seg = anchor->segment;
5140 g_assert (seg->body.child.line != NULL);
5142 iter_init_from_segment (iter, tree,
5143 seg->body.child.line, seg);
5144 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5145 check_invariants (iter);
5149 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5152 g_return_if_fail (iter != NULL);
5153 g_return_if_fail (tree != NULL);
5155 _gtk_text_btree_get_iter_at_char (tree,
5157 _gtk_text_btree_char_count (tree));
5158 check_invariants (iter);
5162 _gtk_text_iter_check (const GtkTextIter *iter)
5164 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5165 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5166 GtkTextLineSegment *byte_segment = NULL;
5167 GtkTextLineSegment *byte_any_segment = NULL;
5168 GtkTextLineSegment *char_segment = NULL;
5169 GtkTextLineSegment *char_any_segment = NULL;
5170 gboolean segments_updated;
5172 /* This function checks our class invariants for the Iter class. */
5174 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5176 if (real->chars_changed_stamp !=
5177 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5178 g_error ("iterator check failed: invalid iterator");
5180 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5181 g_error ("iterator check failed: both char and byte offsets are invalid");
5183 segments_updated = (real->segments_changed_stamp ==
5184 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5187 printf ("checking iter, segments %s updated, byte %d char %d\n",
5188 segments_updated ? "are" : "aren't",
5189 real->line_byte_offset,
5190 real->line_char_offset);
5193 if (segments_updated)
5195 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5196 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5198 if (real->segment->char_count == 0)
5199 g_error ("iterator check failed: segment is not indexable.");
5201 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5202 g_error ("segment char offset is not properly up-to-date");
5204 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5205 g_error ("segment byte offset is not properly up-to-date");
5207 if (real->segment_byte_offset >= 0 &&
5208 real->segment_byte_offset >= real->segment->byte_count)
5209 g_error ("segment byte offset is too large.");
5211 if (real->segment_char_offset >= 0 &&
5212 real->segment_char_offset >= real->segment->char_count)
5213 g_error ("segment char offset is too large.");
5216 if (real->line_byte_offset >= 0)
5218 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5219 &byte_segment, &byte_any_segment,
5220 &seg_byte_offset, &line_byte_offset);
5222 if (line_byte_offset != real->line_byte_offset)
5223 g_error ("wrong byte offset was stored in iterator");
5225 if (segments_updated)
5227 if (real->segment != byte_segment)
5228 g_error ("wrong segment was stored in iterator");
5230 if (real->any_segment != byte_any_segment)
5231 g_error ("wrong any_segment was stored in iterator");
5233 if (seg_byte_offset != real->segment_byte_offset)
5234 g_error ("wrong segment byte offset was stored in iterator");
5236 if (byte_segment->type == >k_text_char_type)
5239 p = byte_segment->body.chars + seg_byte_offset;
5241 if (!gtk_text_byte_begins_utf8_char (p))
5242 g_error ("broken iterator byte index pointed into the middle of a character");
5247 if (real->line_char_offset >= 0)
5249 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5250 &char_segment, &char_any_segment,
5251 &seg_char_offset, &line_char_offset);
5253 if (line_char_offset != real->line_char_offset)
5254 g_error ("wrong char offset was stored in iterator");
5256 if (segments_updated)
5258 if (real->segment != char_segment)
5259 g_error ("wrong segment was stored in iterator");
5261 if (real->any_segment != char_any_segment)
5262 g_error ("wrong any_segment was stored in iterator");
5264 if (seg_char_offset != real->segment_char_offset)
5265 g_error ("wrong segment char offset was stored in iterator");
5267 if (char_segment->type == >k_text_char_type)
5270 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5273 /* hmm, not likely to happen eh */
5274 if (!gtk_text_byte_begins_utf8_char (p))
5275 g_error ("broken iterator char offset pointed into the middle of a character");
5280 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5282 if (byte_segment != char_segment)
5283 g_error ("char and byte offsets did not point to the same segment");
5285 if (byte_any_segment != char_any_segment)
5286 g_error ("char and byte offsets did not point to the same any segment");
5288 /* Make sure the segment offsets are equivalent, if it's a char
5290 if (char_segment->type == >k_text_char_type)
5292 gint byte_offset = 0;
5293 gint char_offset = 0;
5294 while (char_offset < seg_char_offset)
5296 const char * start = char_segment->body.chars + byte_offset;
5297 byte_offset += g_utf8_next_char (start) - start;
5301 if (byte_offset != seg_byte_offset)
5302 g_error ("byte offset did not correspond to char offset");
5305 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5307 if (char_offset != seg_char_offset)
5308 g_error ("char offset did not correspond to byte offset");
5310 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5311 g_error ("byte index for iterator does not index the start of a character");
5315 if (real->cached_line_number >= 0)
5319 should_be = _gtk_text_line_get_number (real->line);
5320 if (real->cached_line_number != should_be)
5321 g_error ("wrong line number was cached");
5324 if (real->cached_char_index >= 0)
5326 if (real->line_char_offset >= 0) /* only way we can check it
5327 efficiently, not a real
5332 char_index = _gtk_text_line_char_index (real->line);
5333 char_index += real->line_char_offset;
5335 if (real->cached_char_index != char_index)
5336 g_error ("wrong char index was cached");
5340 if (_gtk_text_line_is_last (real->line, real->tree))
5341 g_error ("Iterator was on last line (past the end iterator)");