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 _gtk_text_btree_get_iter_at_line (real->tree,
743 seg = _gtk_text_iter_get_indexable_segment (&pos);
745 while (seg != real->segment)
747 /* This is a pretty expensive call, making the
748 * whole function pretty lame; we could keep track
749 * of current invisibility state by looking at toggle
750 * segments as we loop, and then call this function
751 * only once per line, in order to speed up the loop
754 if (_gtk_text_btree_char_is_invisible (&pos))
755 vis_offset -= seg->char_count;
757 _gtk_text_iter_forward_indexable_segment (&pos);
759 seg = _gtk_text_iter_get_indexable_segment (&pos);
762 if (_gtk_text_btree_char_is_invisible (&pos))
763 vis_offset -= real->segment_char_offset;
770 * gtk_text_iter_get_visible_line_index:
771 * @iter: a #GtkTextIter
773 * Returns the number of bytes from the start of the
774 * line to the given @iter, not counting bytes that
775 * are invisible due to tags with the "invisible" flag
778 * Return value: byte index of @iter with respect to the start of the line
781 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
783 GtkTextRealIter *real;
785 GtkTextLineSegment *seg;
788 g_return_val_if_fail (iter != NULL, 0);
790 real = gtk_text_iter_make_real (iter);
795 ensure_char_offsets (real);
797 check_invariants (iter);
799 vis_offset = real->line_byte_offset;
801 _gtk_text_btree_get_iter_at_line (real->tree,
806 seg = _gtk_text_iter_get_indexable_segment (&pos);
808 while (seg != real->segment)
810 /* This is a pretty expensive call, making the
811 * whole function pretty lame; we could keep track
812 * of current invisibility state by looking at toggle
813 * segments as we loop, and then call this function
814 * only once per line, in order to speed up the loop
817 if (_gtk_text_btree_char_is_invisible (&pos))
818 vis_offset -= seg->byte_count;
820 _gtk_text_iter_forward_indexable_segment (&pos);
822 seg = _gtk_text_iter_get_indexable_segment (&pos);
825 if (_gtk_text_btree_char_is_invisible (&pos))
826 vis_offset -= real->segment_byte_offset;
836 * gtk_text_iter_get_char:
839 * Returns the Unicode character at this iterator. (Equivalent to
840 * operator* on a C++ iterator.) If the iterator points at a
841 * non-character element, such as an image embedded in the buffer, the
842 * Unicode "unknown" character 0xFFFC is returned. If invoked on
843 * the end iterator, zero is returned; zero is not a valid Unicode character.
844 * So you can write a loop which ends when gtk_text_iter_get_char ()
847 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
850 gtk_text_iter_get_char (const GtkTextIter *iter)
852 GtkTextRealIter *real;
854 g_return_val_if_fail (iter != NULL, 0);
856 real = gtk_text_iter_make_real (iter);
861 check_invariants (iter);
863 if (gtk_text_iter_is_end (iter))
865 else if (real->segment->type == >k_text_char_type)
867 ensure_byte_offsets (real);
869 return g_utf8_get_char (real->segment->body.chars +
870 real->segment_byte_offset);
874 /* Unicode "unknown character" 0xFFFC */
875 return GTK_TEXT_UNKNOWN_CHAR;
880 * gtk_text_iter_get_slice:
881 * @start: iterator at start of a range
882 * @end: iterator at end of a range
884 * Returns the text in the given range. A "slice" is an array of
885 * characters encoded in UTF-8 format, including the Unicode "unknown"
886 * character 0xFFFC for iterable non-character elements in the buffer,
887 * such as images. Because images are encoded in the slice, byte and
888 * character offsets in the returned array will correspond to byte
889 * offsets in the text buffer. Note that 0xFFFC can occur in normal
890 * text as well, so it is not a reliable indicator that a pixbuf or
891 * widget is in the buffer.
893 * Return value: slice of text from the buffer
896 gtk_text_iter_get_slice (const GtkTextIter *start,
897 const GtkTextIter *end)
899 g_return_val_if_fail (start != NULL, NULL);
900 g_return_val_if_fail (end != NULL, NULL);
902 check_invariants (start);
903 check_invariants (end);
905 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
909 * gtk_text_iter_get_text:
910 * @start: iterator at start of a range
911 * @end: iterator at end of a range
913 * Returns <emphasis>text</emphasis> in the given range. If the range
914 * contains non-text elements such as images, the character and byte
915 * offsets in the returned string will not correspond to character and
916 * byte offsets in the buffer. If you want offsets to correspond, see
917 * gtk_text_iter_get_slice ().
919 * Return value: array of characters from the buffer
922 gtk_text_iter_get_text (const GtkTextIter *start,
923 const GtkTextIter *end)
925 g_return_val_if_fail (start != NULL, NULL);
926 g_return_val_if_fail (end != NULL, NULL);
928 check_invariants (start);
929 check_invariants (end);
931 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
935 * gtk_text_iter_get_visible_slice:
936 * @start: iterator at start of range
937 * @end: iterator at end of range
939 * Like gtk_text_iter_get_slice (), but invisible text is not included.
940 * Invisible text is usually invisible because a #GtkTextTag with the
941 * "invisible" attribute turned on has been applied to it.
943 * Return value: slice of text from the buffer
946 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
947 const GtkTextIter *end)
949 g_return_val_if_fail (start != NULL, NULL);
950 g_return_val_if_fail (end != NULL, NULL);
952 check_invariants (start);
953 check_invariants (end);
955 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
959 * gtk_text_iter_get_visible_text:
960 * @start: iterator at start of range
961 * @end: iterator at end of range
963 * Like gtk_text_iter_get_text (), but invisible text is not included.
964 * Invisible text is usually invisible because a #GtkTextTag with the
965 * "invisible" attribute turned on has been applied to it.
967 * Return value: string containing visible text in the range
970 gtk_text_iter_get_visible_text (const GtkTextIter *start,
971 const GtkTextIter *end)
973 g_return_val_if_fail (start != NULL, NULL);
974 g_return_val_if_fail (end != NULL, NULL);
976 check_invariants (start);
977 check_invariants (end);
979 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
983 * gtk_text_iter_get_pixbuf:
986 * If the location pointed to by @iter contains a pixbuf, the pixbuf
987 * is returned (with no new reference count added). Otherwise,
990 * Return value: the pixbuf at @iter
993 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
995 GtkTextRealIter *real;
997 g_return_val_if_fail (iter != NULL, NULL);
999 real = gtk_text_iter_make_real (iter);
1004 check_invariants (iter);
1006 if (real->segment->type != >k_text_pixbuf_type)
1009 return real->segment->body.pixbuf.pixbuf;
1013 * gtk_text_iter_get_child_anchor:
1014 * @iter: an iterator
1016 * If the location pointed to by @iter contains a child anchor, the
1017 * anchor is returned (with no new reference count added). Otherwise,
1018 * %NULL is returned.
1020 * Return value: the anchor at @iter
1023 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1025 GtkTextRealIter *real;
1027 g_return_val_if_fail (iter != NULL, NULL);
1029 real = gtk_text_iter_make_real (iter);
1034 check_invariants (iter);
1036 if (real->segment->type != >k_text_child_type)
1039 return real->segment->body.child.obj;
1043 * gtk_text_iter_get_marks:
1044 * @iter: an iterator
1046 * Returns a list of all #GtkTextMark at this location. Because marks
1047 * are not iterable (they don't take up any "space" in the buffer,
1048 * they are just marks in between iterable locations), multiple marks
1049 * can exist in the same place. The returned list is not in any
1052 * Return value: list of #GtkTextMark
1055 gtk_text_iter_get_marks (const GtkTextIter *iter)
1057 GtkTextRealIter *real;
1058 GtkTextLineSegment *seg;
1061 g_return_val_if_fail (iter != NULL, NULL);
1063 real = gtk_text_iter_make_real (iter);
1068 check_invariants (iter);
1071 seg = real->any_segment;
1072 while (seg != real->segment)
1074 if (seg->type == >k_text_left_mark_type ||
1075 seg->type == >k_text_right_mark_type)
1076 retval = g_slist_prepend (retval, seg->body.mark.obj);
1081 /* The returned list isn't guaranteed to be in any special order,
1087 * gtk_text_iter_get_toggled_tags:
1088 * @iter: an iterator
1089 * @toggled_on: %TRUE to get toggled-on tags
1091 * Returns a list of #GtkTextTag that are toggled on or off at this
1092 * point. (If @toggled_on is %TRUE, the list contains tags that are
1093 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1094 * range of characters following @iter has that tag applied to it. If
1095 * a tag is toggled off, then some non-empty range following @iter
1096 * does <emphasis>not</emphasis> have the tag applied to it.
1098 * Return value: tags toggled at this point
1101 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1102 gboolean toggled_on)
1104 GtkTextRealIter *real;
1105 GtkTextLineSegment *seg;
1108 g_return_val_if_fail (iter != NULL, NULL);
1110 real = gtk_text_iter_make_real (iter);
1115 check_invariants (iter);
1118 seg = real->any_segment;
1119 while (seg != real->segment)
1123 if (seg->type == >k_text_toggle_on_type)
1125 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1130 if (seg->type == >k_text_toggle_off_type)
1132 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1139 /* The returned list isn't guaranteed to be in any special order,
1145 * gtk_text_iter_begins_tag:
1146 * @iter: an iterator
1147 * @tag: a #GtkTextTag, or %NULL
1149 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1150 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1151 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1152 * <emphasis>start</emphasis> of the tagged range;
1153 * gtk_text_iter_has_tag () tells you whether an iterator is
1154 * <emphasis>within</emphasis> a tagged range.
1156 * Return value: whether @iter is the start of a range tagged with @tag
1159 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1162 GtkTextRealIter *real;
1163 GtkTextLineSegment *seg;
1165 g_return_val_if_fail (iter != NULL, FALSE);
1167 real = gtk_text_iter_make_real (iter);
1172 check_invariants (iter);
1174 seg = real->any_segment;
1175 while (seg != real->segment)
1177 if (seg->type == >k_text_toggle_on_type)
1180 seg->body.toggle.info->tag == tag)
1191 * gtk_text_iter_ends_tag:
1192 * @iter: an iterator
1193 * @tag: a #GtkTextTag, or %NULL
1195 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1196 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1197 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1198 * <emphasis>end</emphasis> of the tagged range;
1199 * gtk_text_iter_has_tag () tells you whether an iterator is
1200 * <emphasis>within</emphasis> a tagged range.
1202 * Return value: whether @iter is the end of a range tagged with @tag
1206 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1209 GtkTextRealIter *real;
1210 GtkTextLineSegment *seg;
1212 g_return_val_if_fail (iter != NULL, FALSE);
1214 real = gtk_text_iter_make_real (iter);
1219 check_invariants (iter);
1221 seg = real->any_segment;
1222 while (seg != real->segment)
1224 if (seg->type == >k_text_toggle_off_type)
1227 seg->body.toggle.info->tag == tag)
1238 * gtk_text_iter_toggles_tag:
1239 * @iter: an iterator
1240 * @tag: a #GtkTextTag, or %NULL
1242 * This is equivalent to (gtk_text_iter_begins_tag () ||
1243 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1244 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1246 * Return value: whether @tag is toggled on or off at @iter
1249 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1252 GtkTextRealIter *real;
1253 GtkTextLineSegment *seg;
1255 g_return_val_if_fail (iter != NULL, FALSE);
1257 real = gtk_text_iter_make_real (iter);
1262 check_invariants (iter);
1264 seg = real->any_segment;
1265 while (seg != real->segment)
1267 if ( (seg->type == >k_text_toggle_off_type ||
1268 seg->type == >k_text_toggle_on_type) &&
1270 seg->body.toggle.info->tag == tag) )
1280 * gtk_text_iter_has_tag:
1281 * @iter: an iterator
1282 * @tag: a #GtkTextTag
1284 * Returns %TRUE if @iter is within a range tagged with @tag.
1286 * Return value: whether @iter is tagged with @tag
1289 gtk_text_iter_has_tag (const GtkTextIter *iter,
1292 GtkTextRealIter *real;
1294 g_return_val_if_fail (iter != NULL, FALSE);
1295 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1297 real = gtk_text_iter_make_surreal (iter);
1302 check_invariants (iter);
1304 if (real->line_byte_offset >= 0)
1306 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1307 real->line_byte_offset, tag);
1311 g_assert (real->line_char_offset >= 0);
1312 return _gtk_text_line_char_has_tag (real->line, real->tree,
1313 real->line_char_offset, tag);
1318 * gtk_text_iter_get_tags:
1319 * @iter: a #GtkTextIter
1321 * Returns a list of tags that apply to @iter, in ascending order of
1322 * priority (highest-priority tags are last). The #GtkTextTag in the
1323 * list don't have a reference added, but you have to free the list
1326 * Return value: list of #GtkTextTag
1329 gtk_text_iter_get_tags (const GtkTextIter *iter)
1336 g_return_val_if_fail (iter != NULL, NULL);
1338 /* Get the tags at this spot */
1339 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1341 /* No tags, use default style */
1342 if (tags == NULL || tag_count == 0)
1350 /* Sort tags in ascending order of priority */
1351 _gtk_text_tag_array_sort (tags, tag_count);
1355 while (i < tag_count)
1357 retval = g_slist_prepend (retval, tags[i]);
1363 /* Return tags in ascending order of priority */
1364 return g_slist_reverse (retval);
1368 * gtk_text_iter_editable:
1369 * @iter: an iterator
1370 * @default_setting: %TRUE if text is editable by default
1372 * Returns whether the character at @iter is within an editable region
1373 * of text. Non-editable text is "locked" and can't be changed by the
1374 * user via #GtkTextView. This function is simply a convenience
1375 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1376 * to this text affect editability, @default_setting will be returned.
1378 * You don't want to use this function to decide whether text can be
1379 * inserted at @iter, because for insertion you don't want to know
1380 * whether the char at @iter is inside an editable range, you want to
1381 * know whether a new character inserted at @iter would be inside an
1382 * editable range. Use gtk_text_iter_can_insert() to handle this
1385 * Return value: whether @iter is inside an editable range
1388 gtk_text_iter_editable (const GtkTextIter *iter,
1389 gboolean default_setting)
1391 GtkTextAttributes *values;
1394 g_return_val_if_fail (iter != NULL, FALSE);
1396 values = gtk_text_attributes_new ();
1398 values->editable = default_setting;
1400 gtk_text_iter_get_attributes (iter, values);
1402 retval = values->editable;
1404 gtk_text_attributes_unref (values);
1410 * gtk_text_iter_can_insert:
1411 * @iter: an iterator
1412 * @default_editability: %TRUE if text is editable by default
1414 * Considering the default editability of the buffer, and tags that
1415 * affect editability, determines whether text inserted at @iter would
1416 * be editable. If text inserted at @iter would be editable then the
1417 * user should be allowed to insert text at @iter.
1418 * gtk_text_buffer_insert_interactive() uses this function to decide
1419 * whether insertions are allowed at a given position.
1421 * Return value: whether text inserted at @iter would be editable
1424 gtk_text_iter_can_insert (const GtkTextIter *iter,
1425 gboolean default_editability)
1427 g_return_val_if_fail (iter != NULL, FALSE);
1429 if (gtk_text_iter_editable (iter, default_editability))
1431 /* If at start/end of buffer, default editability is used */
1432 else if ((gtk_text_iter_is_start (iter) ||
1433 gtk_text_iter_is_end (iter)) &&
1434 default_editability)
1438 /* if iter isn't editable, and the char before iter is,
1439 * then iter is the first char in an editable region
1440 * and thus insertion at iter results in editable text.
1442 GtkTextIter prev = *iter;
1443 gtk_text_iter_backward_char (&prev);
1444 return gtk_text_iter_editable (&prev, default_editability);
1450 * gtk_text_iter_get_language:
1451 * @iter: an iterator
1453 * A convenience wrapper around gtk_text_iter_get_attributes (),
1454 * which returns the language in effect at @iter. If no tags affecting
1455 * language apply to @iter, the return value is identical to that of
1456 * gtk_get_default_language ().
1458 * Return value: language in effect at @iter
1461 gtk_text_iter_get_language (const GtkTextIter *iter)
1463 GtkTextAttributes *values;
1464 PangoLanguage *retval;
1466 values = gtk_text_attributes_new ();
1468 gtk_text_iter_get_attributes (iter, values);
1470 retval = values->language;
1472 gtk_text_attributes_unref (values);
1478 * gtk_text_iter_starts_line:
1479 * @iter: an iterator
1481 * Returns %TRUE if @iter begins a paragraph,
1482 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1483 * However this function is potentially more efficient than
1484 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1485 * the offset, it just has to see whether it's 0.
1487 * Return value: whether @iter begins a line
1490 gtk_text_iter_starts_line (const GtkTextIter *iter)
1492 GtkTextRealIter *real;
1494 g_return_val_if_fail (iter != NULL, FALSE);
1496 real = gtk_text_iter_make_surreal (iter);
1501 check_invariants (iter);
1503 if (real->line_byte_offset >= 0)
1505 return (real->line_byte_offset == 0);
1509 g_assert (real->line_char_offset >= 0);
1510 return (real->line_char_offset == 0);
1515 * gtk_text_iter_ends_line:
1516 * @iter: an iterator
1518 * Returns %TRUE if @iter points to the start of the paragraph
1519 * delimiter characters for a line (delimiters will be either a
1520 * newline, a carriage return, a carriage return followed by a
1521 * newline, or a Unicode paragraph separator character). Note that an
1522 * iterator pointing to the \n of a \r\n pair will not be counted as
1523 * the end of a line, the line ends before the \r. The end iterator is
1524 * considered to be at the end of a line, even though there are no
1525 * paragraph delimiter chars there.
1527 * Return value: whether @iter is at the end of a line
1530 gtk_text_iter_ends_line (const GtkTextIter *iter)
1532 GtkTextRealIter *real;
1535 g_return_val_if_fail (iter != NULL, FALSE);
1537 real = gtk_text_iter_make_real (iter);
1539 check_invariants (iter);
1541 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1542 * Unicode 3.0; update this if that changes.
1544 #define PARAGRAPH_SEPARATOR 0x2029
1546 wc = gtk_text_iter_get_char (iter);
1548 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1550 else if (wc == '\n')
1552 /* need to determine if a \r precedes the \n, in which case
1553 * we aren't the end of the line
1555 GtkTextIter tmp = *iter;
1556 if (!gtk_text_iter_backward_char (&tmp))
1559 return gtk_text_iter_get_char (&tmp) != '\r';
1566 * gtk_text_iter_is_end:
1567 * @iter: an iterator
1569 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1570 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1571 * the most efficient way to check whether an iterator is the end
1574 * Return value: whether @iter is the end iterator
1577 gtk_text_iter_is_end (const GtkTextIter *iter)
1579 GtkTextRealIter *real;
1581 g_return_val_if_fail (iter != NULL, FALSE);
1583 real = gtk_text_iter_make_surreal (iter);
1588 check_invariants (iter);
1590 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1593 /* Now we need the segments validated */
1594 real = gtk_text_iter_make_real (iter);
1599 return _gtk_text_btree_is_end (real->tree, real->line,
1601 real->segment_byte_offset,
1602 real->segment_char_offset);
1606 * gtk_text_iter_is_start:
1607 * @iter: an iterator
1609 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1610 * if @iter has a character offset of 0.
1612 * Return value: whether @iter is the first in the buffer
1615 gtk_text_iter_is_start (const GtkTextIter *iter)
1617 return gtk_text_iter_get_offset (iter) == 0;
1621 * gtk_text_iter_get_chars_in_line:
1622 * @iter: an iterator
1624 * Returns the number of characters in the line containing @iter,
1625 * including the paragraph delimiters.
1627 * Return value: number of characters in the line
1630 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1632 GtkTextRealIter *real;
1634 GtkTextLineSegment *seg;
1636 g_return_val_if_fail (iter != NULL, FALSE);
1638 real = gtk_text_iter_make_surreal (iter);
1643 check_invariants (iter);
1645 if (real->line_char_offset >= 0)
1647 /* We can start at the segments we've already found. */
1648 count = real->line_char_offset - real->segment_char_offset;
1649 seg = _gtk_text_iter_get_indexable_segment (iter);
1653 /* count whole line. */
1654 seg = real->line->segments;
1661 count += seg->char_count;
1666 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1667 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1673 * gtk_text_iter_get_bytes_in_line:
1674 * @iter: an iterator
1676 * Returns the number of bytes in the line containing @iter,
1677 * including the paragraph delimiters.
1679 * Return value: number of bytes in the line
1682 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1684 GtkTextRealIter *real;
1686 GtkTextLineSegment *seg;
1688 g_return_val_if_fail (iter != NULL, FALSE);
1690 real = gtk_text_iter_make_surreal (iter);
1695 check_invariants (iter);
1697 if (real->line_byte_offset >= 0)
1699 /* We can start at the segments we've already found. */
1700 count = real->line_byte_offset - real->segment_byte_offset;
1701 seg = _gtk_text_iter_get_indexable_segment (iter);
1705 /* count whole line. */
1706 seg = real->line->segments;
1712 count += seg->byte_count;
1717 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1718 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1724 * gtk_text_iter_get_attributes:
1725 * @iter: an iterator
1726 * @values: a #GtkTextAttributes to be filled in
1728 * Computes the effect of any tags applied to this spot in the
1729 * text. The @values parameter should be initialized to the default
1730 * settings you wish to use if no tags are in effect. You'd typically
1731 * obtain the defaults from gtk_text_view_get_default_attributes().
1733 * gtk_text_iter_get_attributes () will modify @values, applying the
1734 * effects of any tags present at @iter. If any tags affected @values,
1735 * the function returns %TRUE.
1737 * Return value: %TRUE if @values was modified
1740 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1741 GtkTextAttributes *values)
1746 /* Get the tags at this spot */
1747 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1749 /* No tags, use default style */
1750 if (tags == NULL || tag_count == 0)
1758 /* Sort tags in ascending order of priority */
1759 _gtk_text_tag_array_sort (tags, tag_count);
1761 _gtk_text_attributes_fill_from_tags (values,
1771 * Increments/decrements
1774 /* The return value of this indicates WHETHER WE MOVED.
1775 * The return value of public functions indicates
1776 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1778 * This function will not change the iterator if
1779 * it's already on the last (end iter) line, i.e. it
1780 * won't move to the end of the last line.
1783 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1785 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1787 GtkTextLine *new_line;
1789 new_line = _gtk_text_line_next (real->line);
1790 g_assert (new_line);
1791 g_assert (new_line != real->line);
1792 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1794 real->line = new_line;
1796 real->line_byte_offset = 0;
1797 real->line_char_offset = 0;
1799 real->segment_byte_offset = 0;
1800 real->segment_char_offset = 0;
1802 /* Find first segments in new line */
1803 real->any_segment = real->line->segments;
1804 real->segment = real->any_segment;
1805 while (real->segment->char_count == 0)
1806 real->segment = real->segment->next;
1812 /* There is no way to move forward a line; we were already at
1813 * the line containing the end iterator.
1814 * However we may not be at the end iterator itself.
1822 /* The return value of this indicates WHETHER WE MOVED.
1823 * The return value of public functions indicates
1824 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1827 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1829 GtkTextLine *new_line;
1831 new_line = _gtk_text_line_previous (real->line);
1833 g_assert (new_line != real->line);
1835 if (new_line != NULL)
1837 real->line = new_line;
1839 real->line_byte_offset = 0;
1840 real->line_char_offset = 0;
1842 real->segment_byte_offset = 0;
1843 real->segment_char_offset = 0;
1845 /* Find first segments in new line */
1846 real->any_segment = real->line->segments;
1847 real->segment = real->any_segment;
1848 while (real->segment->char_count == 0)
1849 real->segment = real->segment->next;
1855 /* There is no way to move backward; we were already
1856 at the first line. */
1858 /* We leave real->line as-is */
1860 /* Note that we didn't clamp to the start of the first line. */
1866 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1870 forward_char (GtkTextRealIter *real)
1872 GtkTextIter *iter = (GtkTextIter*)real;
1874 check_invariants ((GtkTextIter*)real);
1876 ensure_char_offsets (real);
1878 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1880 /* Need to move to the next segment; if no next segment,
1881 need to move to next line. */
1882 return _gtk_text_iter_forward_indexable_segment (iter);
1886 /* Just moving within a segment. Keep byte count
1887 up-to-date, if it was already up-to-date. */
1889 g_assert (real->segment->type == >k_text_char_type);
1891 if (real->line_byte_offset >= 0)
1894 const char * start =
1895 real->segment->body.chars + real->segment_byte_offset;
1897 bytes = g_utf8_next_char (start) - start;
1899 real->line_byte_offset += bytes;
1900 real->segment_byte_offset += bytes;
1902 g_assert (real->segment_byte_offset < real->segment->byte_count);
1905 real->line_char_offset += 1;
1906 real->segment_char_offset += 1;
1908 adjust_char_index (real, 1);
1910 g_assert (real->segment_char_offset < real->segment->char_count);
1912 /* We moved into the middle of a segment, so the any_segment
1913 must now be the segment we're in the middle of. */
1914 real->any_segment = real->segment;
1916 check_invariants ((GtkTextIter*)real);
1918 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1926 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1928 /* Need to move to the next segment; if no next segment,
1929 need to move to next line. */
1930 GtkTextLineSegment *seg;
1931 GtkTextLineSegment *any_seg;
1932 GtkTextRealIter *real;
1936 g_return_val_if_fail (iter != NULL, FALSE);
1938 real = gtk_text_iter_make_real (iter);
1943 check_invariants (iter);
1945 if (real->line_char_offset >= 0)
1947 chars_skipped = real->segment->char_count - real->segment_char_offset;
1948 g_assert (chars_skipped > 0);
1953 if (real->line_byte_offset >= 0)
1955 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1956 g_assert (bytes_skipped > 0);
1961 /* Get first segment of any kind */
1962 any_seg = real->segment->next;
1963 /* skip non-indexable segments, if any */
1965 while (seg != NULL && seg->char_count == 0)
1970 real->any_segment = any_seg;
1971 real->segment = seg;
1973 if (real->line_byte_offset >= 0)
1975 g_assert (bytes_skipped > 0);
1976 real->segment_byte_offset = 0;
1977 real->line_byte_offset += bytes_skipped;
1980 if (real->line_char_offset >= 0)
1982 g_assert (chars_skipped > 0);
1983 real->segment_char_offset = 0;
1984 real->line_char_offset += chars_skipped;
1985 adjust_char_index (real, chars_skipped);
1988 check_invariants (iter);
1990 return !gtk_text_iter_is_end (iter);
1994 /* End of the line */
1995 if (forward_line_leaving_caches_unmodified (real))
1997 adjust_line_number (real, 1);
1998 if (real->line_char_offset >= 0)
1999 adjust_char_index (real, chars_skipped);
2001 g_assert (real->line_byte_offset == 0);
2002 g_assert (real->line_char_offset == 0);
2003 g_assert (real->segment_byte_offset == 0);
2004 g_assert (real->segment_char_offset == 0);
2005 g_assert (gtk_text_iter_starts_line (iter));
2007 check_invariants (iter);
2009 return !gtk_text_iter_is_end (iter);
2015 check_invariants (iter);
2017 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2018 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2019 if (!gtk_text_iter_is_end (iter))
2020 _gtk_text_btree_spew (_gtk_text_iter_get_btree (iter));
2021 g_assert (gtk_text_iter_is_end (iter));
2029 at_last_indexable_segment (GtkTextRealIter *real)
2031 GtkTextLineSegment *seg;
2033 /* Return TRUE if there are no indexable segments after
2037 seg = real->segment->next;
2040 if (seg->char_count > 0)
2047 /* Goes back to the start of the next segment, even if
2048 * we're not at the start of the current segment (always
2049 * ends up on a different segment if it returns TRUE)
2052 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2054 /* Move to the start of the previous segment; if no previous
2055 * segment, to the last segment in the previous line. This is
2056 * inherently a bit inefficient due to the singly-linked list and
2057 * tree nodes, but we can't afford the RAM for doubly-linked.
2059 GtkTextRealIter *real;
2060 GtkTextLineSegment *seg;
2061 GtkTextLineSegment *any_seg;
2062 GtkTextLineSegment *prev_seg;
2063 GtkTextLineSegment *prev_any_seg;
2067 g_return_val_if_fail (iter != NULL, FALSE);
2069 real = gtk_text_iter_make_real (iter);
2074 check_invariants (iter);
2076 /* Find first segments in line */
2077 any_seg = real->line->segments;
2079 while (seg->char_count == 0)
2082 if (seg == real->segment)
2084 /* Could probably do this case faster by hand-coding the
2088 /* We were already at the start of a line;
2089 * go back to the previous line.
2091 if (gtk_text_iter_backward_line (iter))
2093 /* Go forward to last indexable segment in line. */
2094 while (!at_last_indexable_segment (real))
2095 _gtk_text_iter_forward_indexable_segment (iter);
2097 check_invariants (iter);
2102 return FALSE; /* We were at the start of the first line. */
2105 /* We must be in the middle of a line; so find the indexable
2106 * segment just before our current segment.
2108 g_assert (seg != real->segment);
2109 while (seg != real->segment)
2112 prev_any_seg = any_seg;
2114 any_seg = seg->next;
2116 while (seg->char_count == 0)
2120 g_assert (prev_seg != NULL);
2121 g_assert (prev_any_seg != NULL);
2122 g_assert (prev_seg->char_count > 0);
2124 /* We skipped the entire previous segment, plus any
2125 * chars we were into the current segment.
2127 if (real->segment_byte_offset >= 0)
2128 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2132 if (real->segment_char_offset >= 0)
2133 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2137 real->segment = prev_seg;
2138 real->any_segment = prev_any_seg;
2139 real->segment_byte_offset = 0;
2140 real->segment_char_offset = 0;
2142 if (bytes_skipped >= 0)
2144 if (real->line_byte_offset >= 0)
2146 real->line_byte_offset -= bytes_skipped;
2147 g_assert (real->line_byte_offset >= 0);
2151 real->line_byte_offset = -1;
2153 if (chars_skipped >= 0)
2155 if (real->line_char_offset >= 0)
2157 real->line_char_offset -= chars_skipped;
2158 g_assert (real->line_char_offset >= 0);
2161 if (real->cached_char_index >= 0)
2163 real->cached_char_index -= chars_skipped;
2164 g_assert (real->cached_char_index >= 0);
2169 real->line_char_offset = -1;
2170 real->cached_char_index = -1;
2173 /* line number is unchanged. */
2175 check_invariants (iter);
2181 * gtk_text_iter_forward_char:
2182 * @iter: an iterator
2184 * Moves @iter forward by one character offset. Note that images
2185 * embedded in the buffer occupy 1 character slot, so
2186 * gtk_text_iter_forward_char () may actually move onto an image instead
2187 * of a character, if you have images in your buffer. If @iter is the
2188 * end iterator or one character before it, @iter will now point at
2189 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2190 * convenience when writing loops.
2192 * Return value: whether @iter moved and is dereferenceable
2195 gtk_text_iter_forward_char (GtkTextIter *iter)
2197 GtkTextRealIter *real;
2199 g_return_val_if_fail (iter != NULL, FALSE);
2201 real = gtk_text_iter_make_real (iter);
2207 check_invariants (iter);
2208 return forward_char (real);
2213 * gtk_text_iter_backward_char:
2214 * @iter: an iterator
2216 * Moves backward by one character offset. Returns %TRUE if movement
2217 * was possible; if @iter was the first in the buffer (character
2218 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2221 * Return value: whether movement was possible
2224 gtk_text_iter_backward_char (GtkTextIter *iter)
2226 g_return_val_if_fail (iter != NULL, FALSE);
2228 check_invariants (iter);
2230 return gtk_text_iter_backward_chars (iter, 1);
2234 Definitely we should try to linear scan as often as possible for
2235 movement within a single line, because we can't use the BTree to
2236 speed within-line searches up; for movement between lines, we would
2237 like to avoid the linear scan probably.
2239 Instead of using this constant, it might be nice to cache the line
2240 length in the iterator and linear scan if motion is within a single
2243 I guess you'd have to profile the various approaches.
2245 #define MAX_LINEAR_SCAN 150
2249 * gtk_text_iter_forward_chars:
2250 * @iter: an iterator
2251 * @count: number of characters to move, may be negative
2253 * Moves @count characters if possible (if @count would move past the
2254 * start or end of the buffer, moves to the start or end of the
2255 * buffer). The return value indicates whether the new position of
2256 * @iter is different from its original position, and dereferenceable
2257 * (the last iterator in the buffer is not dereferenceable). If @count
2258 * is 0, the function does nothing and returns %FALSE.
2260 * Return value: whether @iter moved and is dereferenceable
2263 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2265 GtkTextRealIter *real;
2267 g_return_val_if_fail (iter != NULL, FALSE);
2269 FIX_OVERFLOWS (count);
2271 real = gtk_text_iter_make_real (iter);
2275 else if (count == 0)
2278 return gtk_text_iter_backward_chars (iter, 0 - count);
2279 else if (count < MAX_LINEAR_SCAN)
2281 check_invariants (iter);
2285 if (!forward_char (real))
2290 return forward_char (real);
2294 gint current_char_index;
2295 gint new_char_index;
2297 check_invariants (iter);
2299 current_char_index = gtk_text_iter_get_offset (iter);
2301 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2302 return FALSE; /* can't move forward */
2304 new_char_index = current_char_index + count;
2305 gtk_text_iter_set_offset (iter, new_char_index);
2307 check_invariants (iter);
2309 /* Return FALSE if we're on the non-dereferenceable end
2312 if (gtk_text_iter_is_end (iter))
2320 * gtk_text_iter_backward_chars:
2321 * @iter: an iterator
2322 * @count: number of characters to move
2324 * Moves @count characters backward, if possible (if @count would move
2325 * past the start or end of the buffer, moves to the start or end of
2326 * the buffer). The return value indicates whether the iterator moved
2327 * onto a dereferenceable position; if the iterator didn't move, or
2328 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2329 * the function does nothing and returns %FALSE.
2331 * Return value: whether @iter moved and is dereferenceable
2335 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2337 GtkTextRealIter *real;
2339 g_return_val_if_fail (iter != NULL, FALSE);
2341 FIX_OVERFLOWS (count);
2343 real = gtk_text_iter_make_real (iter);
2347 else if (count == 0)
2350 return gtk_text_iter_forward_chars (iter, 0 - count);
2352 ensure_char_offsets (real);
2353 check_invariants (iter);
2355 /* <, not <=, because if count == segment_char_offset
2356 * we're going to the front of the segment and the any_segment
2359 if (count < real->segment_char_offset)
2361 /* Optimize the within-segment case */
2362 g_assert (real->segment->char_count > 0);
2363 g_assert (real->segment->type == >k_text_char_type);
2365 real->segment_char_offset -= count;
2366 g_assert (real->segment_char_offset >= 0);
2368 if (real->line_byte_offset >= 0)
2370 gint new_byte_offset;
2373 new_byte_offset = 0;
2375 while (i < real->segment_char_offset)
2377 const char * start = real->segment->body.chars + new_byte_offset;
2378 new_byte_offset += g_utf8_next_char (start) - start;
2383 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2384 real->segment_byte_offset = new_byte_offset;
2387 real->line_char_offset -= count;
2389 adjust_char_index (real, 0 - count);
2391 check_invariants (iter);
2397 /* We need to go back into previous segments. For now,
2398 * just keep this really simple. FIXME
2399 * use backward_indexable_segment.
2401 if (TRUE || count > MAX_LINEAR_SCAN)
2403 gint current_char_index;
2404 gint new_char_index;
2406 current_char_index = gtk_text_iter_get_offset (iter);
2408 if (current_char_index == 0)
2409 return FALSE; /* can't move backward */
2411 new_char_index = current_char_index - count;
2412 if (new_char_index < 0)
2415 gtk_text_iter_set_offset (iter, new_char_index);
2417 check_invariants (iter);
2423 /* FIXME backward_indexable_segment here */
2432 /* These two can't be implemented efficiently (always have to use
2433 * a linear scan, since that's the only way to find all the non-text
2438 * gtk_text_iter_forward_text_chars:
2439 * @iter: a #GtkTextIter
2440 * @count: number of chars to move
2442 * Moves forward by @count text characters (pixbufs, widgets,
2443 * etc. do not count as characters for this). Equivalent to moving
2444 * through the results of gtk_text_iter_get_text (), rather than
2445 * gtk_text_iter_get_slice ().
2447 * Return value: whether @iter moved and is dereferenceable
2450 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2459 * gtk_text_iter_forward_text_chars:
2460 * @iter: a #GtkTextIter
2461 * @count: number of chars to move
2463 * Moves backward by @count text characters (pixbufs, widgets,
2464 * etc. do not count as characters for this). Equivalent to moving
2465 * through the results of gtk_text_iter_get_text (), rather than
2466 * gtk_text_iter_get_slice ().
2468 * Return value: whether @iter moved and is dereferenceable
2471 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2480 * gtk_text_iter_forward_line:
2481 * @iter: an iterator
2483 * Moves @iter to the start of the next line. Returns %TRUE if there
2484 * was a next line to move to, and %FALSE if @iter was simply moved to
2485 * the end of the buffer and is now not dereferenceable, or if @iter was
2486 * already at the end of the buffer.
2488 * Return value: whether @iter can be dereferenced
2491 gtk_text_iter_forward_line (GtkTextIter *iter)
2493 GtkTextRealIter *real;
2495 g_return_val_if_fail (iter != NULL, FALSE);
2497 real = gtk_text_iter_make_real (iter);
2502 check_invariants (iter);
2504 if (forward_line_leaving_caches_unmodified (real))
2506 invalidate_char_index (real);
2507 adjust_line_number (real, 1);
2509 check_invariants (iter);
2511 if (gtk_text_iter_is_end (iter))
2518 /* On the last line, move to end of it */
2520 if (!gtk_text_iter_is_end (iter))
2521 gtk_text_iter_forward_to_end (iter);
2523 check_invariants (iter);
2529 * gtk_text_iter_backward_line:
2530 * @iter: an iterator
2532 * Moves @iter to the start of the previous line. Returns %TRUE if
2533 * @iter could be moved; i.e. if @iter was at character offset 0, this
2534 * function returns %FALSE. Therefore if @iter was already on line 0,
2535 * but not at the start of the line, @iter is snapped to the start of
2536 * the line and the function returns %TRUE. (Note that this implies that
2537 * in a loop calling this function, the line number may not change on
2538 * every iteration, if your first iteration is on line 0.)
2540 * Return value: whether @iter moved
2543 gtk_text_iter_backward_line (GtkTextIter *iter)
2545 GtkTextLine *new_line;
2546 GtkTextRealIter *real;
2547 gboolean offset_will_change;
2550 g_return_val_if_fail (iter != NULL, FALSE);
2552 real = gtk_text_iter_make_real (iter);
2557 check_invariants (iter);
2559 new_line = _gtk_text_line_previous (real->line);
2561 offset_will_change = FALSE;
2562 if (real->line_char_offset > 0)
2563 offset_will_change = TRUE;
2565 if (new_line != NULL)
2567 real->line = new_line;
2569 adjust_line_number (real, -1);
2573 if (!offset_will_change)
2577 invalidate_char_index (real);
2579 real->line_byte_offset = 0;
2580 real->line_char_offset = 0;
2582 real->segment_byte_offset = 0;
2583 real->segment_char_offset = 0;
2585 /* Find first segment in line */
2586 real->any_segment = real->line->segments;
2587 real->segment = _gtk_text_line_byte_to_segment (real->line,
2590 g_assert (offset == 0);
2592 /* Note that if we are on the first line, we snap to the start of
2593 * the first line and return TRUE, so TRUE means the iterator
2594 * changed, not that the line changed; this is maybe a bit
2595 * weird. I'm not sure there's an obvious right thing to do though.
2598 check_invariants (iter);
2605 * gtk_text_iter_forward_lines:
2606 * @iter: a #GtkTextIter
2607 * @count: number of lines to move forward
2609 * Moves @count lines forward, if possible (if @count would move
2610 * past the start or end of the buffer, moves to the start or end of
2611 * the buffer). The return value indicates whether the iterator moved
2612 * onto a dereferenceable position; if the iterator didn't move, or
2613 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2614 * the function does nothing and returns %FALSE. If @count is negative,
2615 * moves backward by 0 - @count lines.
2617 * Return value: whether @iter moved and is dereferenceable
2620 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2622 FIX_OVERFLOWS (count);
2625 return gtk_text_iter_backward_lines (iter, 0 - count);
2626 else if (count == 0)
2628 else if (count == 1)
2630 check_invariants (iter);
2631 return gtk_text_iter_forward_line (iter);
2637 if (gtk_text_iter_is_end (iter))
2640 old_line = gtk_text_iter_get_line (iter);
2642 gtk_text_iter_set_line (iter, old_line + count);
2644 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2646 /* count went past the last line, so move to end of last line */
2647 if (!gtk_text_iter_is_end (iter))
2648 gtk_text_iter_forward_to_end (iter);
2651 return !gtk_text_iter_is_end (iter);
2656 * gtk_text_iter_backward_lines:
2657 * @iter: a #GtkTextIter
2658 * @count: number of lines to move backward
2660 * Moves @count lines backward, if possible (if @count would move
2661 * past the start or end of the buffer, moves to the start or end of
2662 * the buffer). The return value indicates whether the iterator moved
2663 * onto a dereferenceable position; if the iterator didn't move, or
2664 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2665 * the function does nothing and returns %FALSE. If @count is negative,
2666 * moves forward by 0 - @count lines.
2668 * Return value: whether @iter moved and is dereferenceable
2671 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2673 FIX_OVERFLOWS (count);
2676 return gtk_text_iter_forward_lines (iter, 0 - count);
2677 else if (count == 0)
2679 else if (count == 1)
2681 return gtk_text_iter_backward_line (iter);
2687 old_line = gtk_text_iter_get_line (iter);
2689 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2691 return (gtk_text_iter_get_line (iter) != old_line);
2695 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2700 gboolean already_moved_initially);
2702 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2710 find_word_end_func (const PangoLogAttr *attrs,
2715 gboolean already_moved_initially)
2717 if (!already_moved_initially)
2720 /* Find end of next word */
2721 while (offset < min_offset + len &&
2722 !attrs[offset].is_word_end)
2725 *found_offset = offset;
2727 return offset < min_offset + len;
2731 is_word_end_func (const PangoLogAttr *attrs,
2736 return attrs[offset].is_word_end;
2740 find_word_start_func (const PangoLogAttr *attrs,
2745 gboolean already_moved_initially)
2747 if (!already_moved_initially)
2750 /* Find start of prev word */
2751 while (offset >= min_offset &&
2752 !attrs[offset].is_word_start)
2755 *found_offset = offset;
2757 return offset >= min_offset;
2761 is_word_start_func (const PangoLogAttr *attrs,
2766 return attrs[offset].is_word_start;
2770 inside_word_func (const PangoLogAttr *attrs,
2775 /* Find next word start or end */
2776 while (offset >= min_offset &&
2777 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2780 return attrs[offset].is_word_start;
2783 /* Sentence funcs */
2786 find_sentence_end_func (const PangoLogAttr *attrs,
2791 gboolean already_moved_initially)
2793 if (!already_moved_initially)
2796 /* Find end of next sentence */
2797 while (offset < min_offset + len &&
2798 !attrs[offset].is_sentence_end)
2801 *found_offset = offset;
2803 return offset < min_offset + len;
2807 is_sentence_end_func (const PangoLogAttr *attrs,
2812 return attrs[offset].is_sentence_end;
2816 find_sentence_start_func (const PangoLogAttr *attrs,
2821 gboolean already_moved_initially)
2823 if (!already_moved_initially)
2826 /* Find start of prev sentence */
2827 while (offset >= min_offset &&
2828 !attrs[offset].is_sentence_start)
2831 *found_offset = offset;
2833 return offset >= min_offset;
2837 is_sentence_start_func (const PangoLogAttr *attrs,
2842 return attrs[offset].is_sentence_start;
2846 inside_sentence_func (const PangoLogAttr *attrs,
2851 /* Find next sentence start or end */
2852 while (offset >= min_offset &&
2853 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2856 return attrs[offset].is_sentence_start;
2860 test_log_attrs (const GtkTextIter *iter,
2861 TestLogAttrFunc func)
2864 const PangoLogAttr *attrs;
2866 gboolean result = FALSE;
2868 g_return_val_if_fail (iter != NULL, FALSE);
2870 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2873 offset = gtk_text_iter_get_line_offset (iter);
2875 /* char_len may be 0 and attrs will be NULL if so, if
2876 * iter is the end iter and the last line is empty.
2878 * offset may be equal to char_len, since attrs contains an entry
2879 * for one past the end
2882 if (attrs && offset <= char_len)
2883 result = (* func) (attrs, offset, 0, char_len);
2889 find_line_log_attrs (const GtkTextIter *iter,
2890 FindLogAttrFunc func,
2892 gboolean already_moved_initially)
2895 const PangoLogAttr *attrs;
2897 gboolean result = FALSE;
2899 g_return_val_if_fail (iter != NULL, FALSE);
2901 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2904 offset = gtk_text_iter_get_line_offset (iter);
2906 /* char_len may be 0 and attrs will be NULL if so, if
2907 * iter is the end iter and the last line is empty
2911 result = (* func) (attrs, offset, 0, char_len, found_offset,
2912 already_moved_initially);
2917 /* FIXME this function is very, very gratuitously slow */
2919 find_by_log_attrs (GtkTextIter *iter,
2920 FindLogAttrFunc func,
2922 gboolean already_moved_initially)
2926 gboolean found = FALSE;
2928 g_return_val_if_fail (iter != NULL, FALSE);
2932 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2938 if (gtk_text_iter_forward_line (iter))
2939 return find_by_log_attrs (iter, func, forward,
2946 /* go to end of previous line. need to check that
2947 * line is > 0 because backward_line snaps to start of
2948 * line 0 if it's on line 0
2950 if (gtk_text_iter_get_line (iter) > 0 &&
2951 gtk_text_iter_backward_line (iter))
2953 if (!gtk_text_iter_ends_line (iter))
2954 gtk_text_iter_forward_to_line_end (iter);
2956 return find_by_log_attrs (iter, func, forward,
2965 gtk_text_iter_set_line_offset (iter, offset);
2968 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2969 !gtk_text_iter_is_end (iter);
2974 * gtk_text_iter_forward_word_end:
2975 * @iter: a #GtkTextIter
2977 * Moves forward to the next word end. (If @iter is currently on a
2978 * word end, moves forward to the next one after that.) Word breaks
2979 * are determined by Pango and should be correct for nearly any
2980 * language (if not, the correct fix would be to the Pango word break
2983 * Return value: %TRUE if @iter moved and is not the end iterator
2986 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2988 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2992 * gtk_text_iter_backward_word_start:
2993 * @iter: a #GtkTextIter
2995 * Moves backward to the previous word start. (If @iter is currently on a
2996 * word start, moves backward to the next one after that.) Word breaks
2997 * are determined by Pango and should be correct for nearly any
2998 * language (if not, the correct fix would be to the Pango word break
3001 * Return value: %TRUE if @iter moved and is not the end iterator
3004 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3006 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3009 /* FIXME a loop around a truly slow function means
3010 * a truly spectacularly slow function.
3014 * gtk_text_iter_forward_word_ends:
3015 * @iter: a #GtkTextIter
3016 * @count: number of times to move
3018 * Calls gtk_text_iter_forward_word_end() up to @count times.
3020 * Return value: %TRUE if @iter moved and is not the end iterator
3023 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3026 g_return_val_if_fail (iter != NULL, FALSE);
3028 FIX_OVERFLOWS (count);
3034 return gtk_text_iter_backward_word_starts (iter, -count);
3036 if (!gtk_text_iter_forward_word_end (iter))
3042 if (!gtk_text_iter_forward_word_end (iter))
3047 return !gtk_text_iter_is_end (iter);
3051 * gtk_text_iter_backward_word_starts
3052 * @iter: a #GtkTextIter
3053 * @count: number of times to move
3055 * Calls gtk_text_iter_backward_word_starts() up to @count times.
3057 * Return value: %TRUE if @iter moved and is not the end iterator
3060 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3063 g_return_val_if_fail (iter != NULL, FALSE);
3065 FIX_OVERFLOWS (count);
3068 return gtk_text_iter_forward_word_ends (iter, -count);
3070 if (!gtk_text_iter_backward_word_start (iter))
3076 if (!gtk_text_iter_backward_word_start (iter))
3081 return !gtk_text_iter_is_end (iter);
3085 * gtk_text_iter_starts_word:
3086 * @iter: a #GtkTextIter
3088 * Determines whether @iter begins a natural-language word. Word
3089 * breaks are determined by Pango and should be correct for nearly any
3090 * language (if not, the correct fix would be to the Pango word break
3093 * Return value: %TRUE if @iter is at the start of a word
3096 gtk_text_iter_starts_word (const GtkTextIter *iter)
3098 return test_log_attrs (iter, is_word_start_func);
3102 * gtk_text_iter_ends_word:
3103 * @iter: a #GtkTextIter
3105 * Determines whether @iter ends a natural-language word. Word breaks
3106 * are determined by Pango and should be correct for nearly any
3107 * language (if not, the correct fix would be to the Pango word break
3110 * Return value: %TRUE if @iter is at the end of a word
3113 gtk_text_iter_ends_word (const GtkTextIter *iter)
3115 return test_log_attrs (iter, is_word_end_func);
3119 * gtk_text_iter_inside_word:
3120 * @iter: a #GtkTextIter
3122 * Determines whether @iter is inside a natural-language word (as
3123 * opposed to say inside some whitespace). Word breaks are determined
3124 * by Pango and should be correct for nearly any language (if not, the
3125 * correct fix would be to the Pango word break algorithms).
3127 * Return value: %TRUE if @iter is inside a word
3130 gtk_text_iter_inside_word (const GtkTextIter *iter)
3132 return test_log_attrs (iter, inside_word_func);
3136 * gtk_text_iter_starts_sentence:
3137 * @iter: a #GtkTextIter
3139 * Determines whether @iter begins a sentence. Sentence boundaries are
3140 * determined by Pango and should be correct for nearly any language
3141 * (if not, the correct fix would be to the Pango text boundary
3144 * Return value: %TRUE if @iter is at the start of a sentence.
3147 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3149 return test_log_attrs (iter, is_sentence_start_func);
3153 * gtk_text_iter_ends_sentence:
3154 * @iter: a #GtkTextIter
3156 * Determines whether @iter ends a sentence. Sentence boundaries are
3157 * determined by Pango and should be correct for nearly any language
3158 * (if not, the correct fix would be to the Pango text boundary
3161 * Return value: %TRUE if @iter is at the end of a sentence.
3164 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3166 return test_log_attrs (iter, is_sentence_end_func);
3170 * gtk_text_iter_inside_sentence:
3171 * @iter: a #GtkTextIter
3173 * Determines whether @iter is inside a sentence (as opposed to in
3174 * between two sentences, e.g. after a period and before the first
3175 * letter of the next sentence). Sentence boundaries are determined
3176 * by Pango and should be correct for nearly any language (if not, the
3177 * correct fix would be to the Pango text boundary algorithms).
3179 * Return value: %TRUE if @iter is inside a sentence.
3182 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3184 return test_log_attrs (iter, inside_sentence_func);
3188 * gtk_text_iter_forward_sentence_end:
3189 * @iter: a #GtkTextIter
3191 * Moves forward to the next sentence end. (If @iter is at the end of
3192 * a sentence, moves to the next end of sentence.) Sentence
3193 * boundaries are determined by Pango and should be correct for nearly
3194 * any language (if not, the correct fix would be to the Pango text
3195 * boundary algorithms).
3197 * Return value: %TRUE if @iter moved and is not the end iterator
3200 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3202 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3206 * gtk_text_iter_backward_sentence_start:
3207 * @iter: a #GtkTextIter
3209 * Moves backward to the previous sentence start; if @iter is already at
3210 * the start of a sentence, moves backward to the next one. Sentence
3211 * boundaries are determined by Pango and should be correct for nearly
3212 * any language (if not, the correct fix would be to the Pango text
3213 * boundary algorithms).
3215 * Return value: %TRUE if @iter moved and is not the end iterator
3218 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3220 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3223 /* FIXME a loop around a truly slow function means
3224 * a truly spectacularly slow function.
3227 * gtk_text_iter_forward_sentence_ends:
3228 * @iter: a #GtkTextIter
3229 * @count: number of sentences to move
3231 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3232 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3233 * negative, moves backward instead of forward.
3235 * Return value: %TRUE if @iter moved and is not the end iterator
3238 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3241 g_return_val_if_fail (iter != NULL, FALSE);
3247 return gtk_text_iter_backward_sentence_starts (iter, -count);
3249 if (!gtk_text_iter_forward_sentence_end (iter))
3255 if (!gtk_text_iter_forward_sentence_end (iter))
3260 return !gtk_text_iter_is_end (iter);
3264 * gtk_text_iter_backward_sentence_starts:
3265 * @iter: a #GtkTextIter
3266 * @count: number of sentences to move
3268 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3269 * or until it returns %FALSE. If @count is negative, moves forward
3270 * instead of backward.
3272 * Return value: %TRUE if @iter moved and is not the end iterator
3275 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3278 g_return_val_if_fail (iter != NULL, FALSE);
3281 return gtk_text_iter_forward_sentence_ends (iter, -count);
3283 if (!gtk_text_iter_backward_sentence_start (iter))
3289 if (!gtk_text_iter_backward_sentence_start (iter))
3294 return !gtk_text_iter_is_end (iter);
3298 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3303 gboolean already_moved_initially)
3305 if (!already_moved_initially)
3308 while (offset < (min_offset + len) &&
3309 !attrs[offset].is_cursor_position)
3312 *found_offset = offset;
3314 return offset < (min_offset + len);
3318 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3323 gboolean already_moved_initially)
3325 if (!already_moved_initially)
3328 while (offset > min_offset &&
3329 !attrs[offset].is_cursor_position)
3332 *found_offset = offset;
3334 return offset >= min_offset;
3338 is_cursor_pos_func (const PangoLogAttr *attrs,
3343 return attrs[offset].is_cursor_position;
3347 * gtk_text_iter_forward_cursor_position:
3348 * @iter: a #GtkTextIter
3350 * Moves @iter forward by a single cursor position. Cursor positions
3351 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3352 * surprisingly, there may not be a cursor position between all
3353 * characters. The most common example for European languages would be
3354 * a carriage return/newline sequence. For some Unicode characters,
3355 * the equivalent of say the letter "a" with an accent mark will be
3356 * represented as two characters, first the letter then a "combining
3357 * mark" that causes the accent to be rendered; so the cursor can't go
3358 * between those two characters. See also the #PangoLogAttr structure and
3359 * pango_break() function.
3361 * Return value: %TRUE if we moved and the new position is dereferenceable
3364 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3366 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3370 * gtk_text_iter_backward_cursor_position:
3371 * @iter: a #GtkTextIter
3373 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3375 * Return value: %TRUE if we moved and the new position is dereferenceable
3378 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3380 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3384 * gtk_text_iter_forward_cursor_positions:
3385 * @iter: a #GtkTextIter
3386 * @count: number of positions to move
3388 * Moves up to @count cursor positions. See
3389 * gtk_text_iter_forward_cursor_position() for details.
3391 * Return value: %TRUE if we moved and the new position is dereferenceable
3394 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3397 g_return_val_if_fail (iter != NULL, FALSE);
3399 FIX_OVERFLOWS (count);
3405 return gtk_text_iter_backward_cursor_positions (iter, -count);
3407 if (!gtk_text_iter_forward_cursor_position (iter))
3413 if (!gtk_text_iter_forward_cursor_position (iter))
3418 return !gtk_text_iter_is_end (iter);
3422 * gtk_text_iter_backward_cursor_positions:
3423 * @iter: a #GtkTextIter
3424 * @count: number of positions to move
3426 * Moves up to @count cursor positions. See
3427 * gtk_text_iter_forward_cursor_position() for details.
3429 * Return value: %TRUE if we moved and the new position is dereferenceable
3432 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3435 g_return_val_if_fail (iter != NULL, FALSE);
3437 FIX_OVERFLOWS (count);
3443 return gtk_text_iter_forward_cursor_positions (iter, -count);
3445 if (!gtk_text_iter_backward_cursor_position (iter))
3451 if (!gtk_text_iter_backward_cursor_position (iter))
3456 return !gtk_text_iter_is_end (iter);
3460 * gtk_text_iter_is_cursor_position:
3461 * @iter: a #GtkTextIter
3463 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3464 * pango_break() for details on what a cursor position is.
3466 * Return value: %TRUE if the cursor can be placed at @iter
3469 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3471 return test_log_attrs (iter, is_cursor_pos_func);
3475 * gtk_text_iter_set_line_offset:
3476 * @iter: a #GtkTextIter
3477 * @char_on_line: a character offset relative to the start of @iter's current line
3479 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3480 * (not byte) offset. The given character offset must be less than or
3481 * equal to the number of characters in the line; if equal, @iter
3482 * moves to the start of the next line. See
3483 * gtk_text_iter_set_line_index() if you have a byte index rather than
3484 * a character offset.
3488 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3491 GtkTextRealIter *real;
3494 g_return_if_fail (iter != NULL);
3496 real = gtk_text_iter_make_surreal (iter);
3501 check_invariants (iter);
3503 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3505 g_return_if_fail (char_on_line <= chars_in_line);
3507 if (char_on_line < chars_in_line)
3508 iter_set_from_char_offset (real, real->line, char_on_line);
3510 gtk_text_iter_forward_line (iter); /* set to start of next line */
3512 check_invariants (iter);
3516 * gtk_text_iter_set_line_index:
3517 * @iter: a #GtkTextIter
3518 * @byte_on_line: a byte index relative to the start of @iter's current line
3520 * Same as gtk_text_iter_set_line_offset(), but works with a
3521 * <emphasis>byte</emphasis> index. The given byte index must be at
3522 * the start of a character, it can't be in the middle of a UTF-8
3523 * encoded character.
3527 gtk_text_iter_set_line_index (GtkTextIter *iter,
3530 GtkTextRealIter *real;
3533 g_return_if_fail (iter != NULL);
3535 real = gtk_text_iter_make_surreal (iter);
3540 check_invariants (iter);
3542 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3544 g_return_if_fail (byte_on_line <= bytes_in_line);
3546 if (byte_on_line < bytes_in_line)
3547 iter_set_from_byte_offset (real, real->line, byte_on_line);
3549 gtk_text_iter_forward_line (iter);
3551 if (real->segment->type == >k_text_char_type &&
3552 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3553 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3554 "character; this will crash the text buffer. "
3555 "Byte indexes must refer to the start of a character.",
3556 G_STRLOC, byte_on_line);
3558 check_invariants (iter);
3563 * gtk_text_iter_set_visible_line_offset:
3564 * @iter: a #GtkTextIter
3565 * @char_on_line: a character offset
3567 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3568 * characters, i.e. text with a tag making it invisible is not
3569 * counted in the offset.
3572 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3575 gint chars_seen = 0;
3578 g_return_if_fail (iter != NULL);
3582 /* For now we use a ludicrously slow implementation */
3583 while (chars_seen < char_on_line)
3585 if (!_gtk_text_btree_char_is_invisible (&pos))
3588 if (!gtk_text_iter_forward_char (&pos))
3591 if (chars_seen == char_on_line)
3595 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3598 gtk_text_iter_forward_line (iter);
3602 bytes_in_char (GtkTextIter *iter)
3604 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3608 * gtk_text_iter_set_visible_line_index:
3609 * @iter: a #GtkTextIter
3610 * @byte_on_line: a byte index
3612 * Like gtk_text_iter_set_line_index(), but the index is in visible
3613 * bytes, i.e. text with a tag making it invisible is not counted
3617 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3620 gint bytes_seen = 0;
3623 g_return_if_fail (iter != NULL);
3627 /* For now we use a ludicrously slow implementation */
3628 while (bytes_seen < byte_on_line)
3630 if (!_gtk_text_btree_char_is_invisible (&pos))
3631 bytes_seen += bytes_in_char (&pos);
3633 if (!gtk_text_iter_forward_char (&pos))
3636 if (bytes_seen >= byte_on_line)
3640 if (bytes_seen > byte_on_line)
3641 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3642 "character; this will crash the text buffer. "
3643 "Byte indexes must refer to the start of a character.",
3644 G_STRLOC, byte_on_line);
3646 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3649 gtk_text_iter_forward_line (iter);
3653 * gtk_text_iter_set_line:
3654 * @iter: a #GtkTextIter
3655 * @line_number: line number (counted from 0)
3657 * Moves iterator @iter to the start of the line @line_number. If
3658 * @line_number is negative or larger than the number of lines in the
3659 * buffer, moves @iter to the start of the last line in the buffer.
3663 gtk_text_iter_set_line (GtkTextIter *iter,
3668 GtkTextRealIter *real;
3670 g_return_if_fail (iter != NULL);
3672 real = gtk_text_iter_make_surreal (iter);
3677 check_invariants (iter);
3679 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3681 iter_set_from_char_offset (real, line, 0);
3683 /* We might as well cache this, since we know it. */
3684 real->cached_line_number = real_line;
3686 check_invariants (iter);
3690 * gtk_text_iter_set_offset:
3691 * @iter: a #GtkTextIter
3692 * @char_offset: a character number
3694 * Sets @iter to point to @char_offset. @char_offset counts from the start
3695 * of the entire text buffer, starting with 0.
3698 gtk_text_iter_set_offset (GtkTextIter *iter,
3702 GtkTextRealIter *real;
3704 gint real_char_index;
3706 g_return_if_fail (iter != NULL);
3708 real = gtk_text_iter_make_surreal (iter);
3713 check_invariants (iter);
3715 if (real->cached_char_index >= 0 &&
3716 real->cached_char_index == char_offset)
3719 line = _gtk_text_btree_get_line_at_char (real->tree,
3724 iter_set_from_char_offset (real, line, real_char_index - line_start);
3726 /* Go ahead and cache this since we have it. */
3727 real->cached_char_index = real_char_index;
3729 check_invariants (iter);
3733 * gtk_text_iter_forward_to_end:
3734 * @iter: a #GtkTextIter
3736 * Moves @iter forward to the "end iterator," which points one past the last
3737 * valid character in the buffer. gtk_text_iter_get_char() called on the
3738 * end iterator returns 0, which is convenient for writing loops.
3741 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3743 GtkTextBuffer *buffer;
3744 GtkTextRealIter *real;
3746 g_return_if_fail (iter != NULL);
3748 real = gtk_text_iter_make_surreal (iter);
3753 buffer = _gtk_text_btree_get_buffer (real->tree);
3755 gtk_text_buffer_get_end_iter (buffer, iter);
3758 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3759 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3760 * If all else fails we could cache the para delimiter pos in the iter.
3761 * I think forward_to_line_end() actually gets called fairly often.
3764 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3769 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3770 _gtk_text_iter_get_btree (&end)))
3772 gtk_text_iter_forward_to_end (&end);
3776 /* if we aren't on the last line, go forward to start of next line, then scan
3777 * back for the delimiters on the previous line
3779 gtk_text_iter_forward_line (&end);
3780 gtk_text_iter_backward_char (&end);
3781 while (!gtk_text_iter_ends_line (&end))
3782 gtk_text_iter_backward_char (&end);
3785 return gtk_text_iter_get_line_offset (&end);
3789 * gtk_text_iter_forward_to_line_end:
3790 * @iter: a #GtkTextIter
3792 * Moves the iterator to point to the paragraph delimiter characters,
3793 * which will be either a newline, a carriage return, a carriage
3794 * return/newline in sequence, or the Unicode paragraph separator
3795 * character. If the iterator is already at the paragraph delimiter
3796 * characters, moves to the paragraph delimiter characters for the
3797 * next line. If @iter is on the last line in the buffer, which does
3798 * not end in paragraph delimiters, moves to the end iterator (end of
3799 * the last line), and returns %FALSE.
3801 * Return value: %TRUE if we moved and the new location is not the end iterator
3804 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3806 gint current_offset;
3810 g_return_val_if_fail (iter != NULL, FALSE);
3812 current_offset = gtk_text_iter_get_line_offset (iter);
3813 new_offset = find_paragraph_delimiter_for_line (iter);
3815 if (current_offset < new_offset)
3817 /* Move to end of this line. */
3818 gtk_text_iter_set_line_offset (iter, new_offset);
3823 /* Move to end of next line. */
3824 if (gtk_text_iter_forward_line (iter))
3826 /* We don't want to move past all
3829 if (!gtk_text_iter_ends_line (iter))
3830 gtk_text_iter_forward_to_line_end (iter);
3839 * gtk_text_iter_forward_to_tag_toggle:
3840 * @iter: a #GtkTextIter
3841 * @tag: a #GtkTextTag, or %NULL
3843 * Moves forward to the next toggle (on or off) of the
3844 * #GtkTextTag @tag, or to the next toggle of any tag if
3845 * @tag is %NULL. If no matching tag toggles are found,
3846 * returns %FALSE, otherwise %TRUE. Does not return toggles
3847 * located at @iter, only toggles after @iter. Sets @iter to
3848 * the location of the toggle, or to the end of the buffer
3849 * if no toggle is found.
3851 * Return value: whether we found a tag toggle after @iter
3854 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3857 GtkTextLine *next_line;
3858 GtkTextLine *current_line;
3859 GtkTextRealIter *real;
3861 g_return_val_if_fail (iter != NULL, FALSE);
3863 real = gtk_text_iter_make_real (iter);
3868 check_invariants (iter);
3870 current_line = real->line;
3871 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3874 while (_gtk_text_iter_forward_indexable_segment (iter))
3876 /* If we went forward to a line that couldn't contain a toggle
3877 for the tag, then skip forward to a line that could contain
3878 it. This potentially skips huge hunks of the tree, so we
3879 aren't a purely linear search. */
3880 if (real->line != current_line)
3882 if (next_line == NULL)
3884 /* End of search. Set to end of buffer. */
3885 _gtk_text_btree_get_end_iter (real->tree, iter);
3889 if (real->line != next_line)
3890 iter_set_from_byte_offset (real, next_line, 0);
3892 current_line = real->line;
3893 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3898 if (gtk_text_iter_toggles_tag (iter, tag))
3900 /* If there's a toggle here, it isn't indexable so
3901 any_segment can't be the indexable segment. */
3902 g_assert (real->any_segment != real->segment);
3907 /* Check end iterator for tags */
3908 if (gtk_text_iter_toggles_tag (iter, tag))
3910 /* If there's a toggle here, it isn't indexable so
3911 any_segment can't be the indexable segment. */
3912 g_assert (real->any_segment != real->segment);
3916 /* Reached end of buffer */
3921 * gtk_text_iter_backward_to_tag_toggle:
3922 * @iter: a #GtkTextIter
3923 * @tag: a #GtkTextTag, or %NULL
3925 * Moves backward to the next toggle (on or off) of the
3926 * #GtkTextTag @tag, or to the next toggle of any tag if
3927 * @tag is %NULL. If no matching tag toggles are found,
3928 * returns %FALSE, otherwise %TRUE. Does not return toggles
3929 * located at @iter, only toggles before @iter. Sets @iter
3930 * to the location of the toggle, or the start of the buffer
3931 * if no toggle is found.
3933 * Return value: whether we found a tag toggle before @iter
3936 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3939 GtkTextLine *prev_line;
3940 GtkTextLine *current_line;
3941 GtkTextRealIter *real;
3943 g_return_val_if_fail (iter != NULL, FALSE);
3945 real = gtk_text_iter_make_real (iter);
3950 check_invariants (iter);
3952 current_line = real->line;
3953 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3957 /* If we're at segment start, go to the previous segment;
3958 * if mid-segment, snap to start of current segment.
3960 if (is_segment_start (real))
3962 if (!_gtk_text_iter_backward_indexable_segment (iter))
3967 ensure_char_offsets (real);
3969 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3975 /* If we went backward to a line that couldn't contain a toggle
3976 * for the tag, then skip backward further to a line that
3977 * could contain it. This potentially skips huge hunks of the
3978 * tree, so we aren't a purely linear search.
3980 if (real->line != current_line)
3982 if (prev_line == NULL)
3984 /* End of search. Set to start of buffer. */
3985 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3989 if (real->line != prev_line)
3991 /* Set to last segment in prev_line (could do this
3994 iter_set_from_byte_offset (real, prev_line, 0);
3996 while (!at_last_indexable_segment (real))
3997 _gtk_text_iter_forward_indexable_segment (iter);
4000 current_line = real->line;
4001 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4006 if (gtk_text_iter_toggles_tag (iter, tag))
4008 /* If there's a toggle here, it isn't indexable so
4009 * any_segment can't be the indexable segment.
4011 g_assert (real->any_segment != real->segment);
4015 while (_gtk_text_iter_backward_indexable_segment (iter));
4017 /* Reached front of buffer */
4022 matches_pred (GtkTextIter *iter,
4023 GtkTextCharPredicate pred,
4028 ch = gtk_text_iter_get_char (iter);
4030 return (*pred) (ch, user_data);
4034 * gtk_text_iter_forward_find_char:
4035 * @iter: a #GtkTextIter
4036 * @pred: a function to be called on each character
4037 * @user_data: user data for @pred
4038 * @limit: search limit, or %NULL for none
4040 * Advances @iter, calling @pred on each character. If
4041 * @pred returns %TRUE, returns %TRUE and stops scanning.
4042 * If @pred never returns %TRUE, @iter is set to @limit if
4043 * @limit is non-%NULL, otherwise to the end iterator.
4045 * Return value: whether a match was found
4048 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4049 GtkTextCharPredicate pred,
4051 const GtkTextIter *limit)
4053 g_return_val_if_fail (iter != NULL, FALSE);
4054 g_return_val_if_fail (pred != NULL, FALSE);
4057 gtk_text_iter_compare (iter, limit) >= 0)
4060 while ((limit == NULL ||
4061 !gtk_text_iter_equal (limit, iter)) &&
4062 gtk_text_iter_forward_char (iter))
4064 if (matches_pred (iter, pred, user_data))
4072 * gtk_text_iter_backward_find_char:
4073 * @iter: a #GtkTextIter
4074 * @pred: function to be called on each character
4075 * @user_data: user data for @pred
4076 * @limit: search limit, or %NULL for none
4078 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4080 * Return value: whether a match was found
4083 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4084 GtkTextCharPredicate pred,
4086 const GtkTextIter *limit)
4088 g_return_val_if_fail (iter != NULL, FALSE);
4089 g_return_val_if_fail (pred != NULL, FALSE);
4092 gtk_text_iter_compare (iter, limit) <= 0)
4095 while ((limit == NULL ||
4096 !gtk_text_iter_equal (limit, iter)) &&
4097 gtk_text_iter_backward_char (iter))
4099 if (matches_pred (iter, pred, user_data))
4107 forward_chars_with_skipping (GtkTextIter *iter,
4109 gboolean skip_invisible,
4110 gboolean skip_nontext)
4115 g_return_if_fail (count >= 0);
4121 gboolean ignored = FALSE;
4124 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4129 _gtk_text_btree_char_is_invisible (iter))
4132 gtk_text_iter_forward_char (iter);
4140 lines_match (const GtkTextIter *start,
4141 const gchar **lines,
4142 gboolean visible_only,
4144 GtkTextIter *match_start,
4145 GtkTextIter *match_end)
4152 if (*lines == NULL || **lines == '\0')
4155 *match_start = *start;
4158 *match_end = *start;
4163 gtk_text_iter_forward_line (&next);
4165 /* No more text in buffer, but *lines is nonempty */
4166 if (gtk_text_iter_equal (start, &next))
4174 line_text = gtk_text_iter_get_visible_slice (start, &next);
4176 line_text = gtk_text_iter_get_slice (start, &next);
4181 line_text = gtk_text_iter_get_visible_text (start, &next);
4183 line_text = gtk_text_iter_get_text (start, &next);
4186 if (match_start) /* if this is the first line we're matching */
4187 found = strstr (line_text, *lines);
4190 /* If it's not the first line, we have to match from the
4191 * start of the line.
4193 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4205 /* Get offset to start of search string */
4206 offset = g_utf8_strlen (line_text, found - line_text);
4210 /* If match start needs to be returned, set it to the
4211 * start of the search string.
4215 *match_start = next;
4217 forward_chars_with_skipping (match_start, offset,
4218 visible_only, !slice);
4221 /* Go to end of search string */
4222 offset += g_utf8_strlen (*lines, -1);
4224 forward_chars_with_skipping (&next, offset,
4225 visible_only, !slice);
4234 /* pass NULL for match_start, since we don't need to find the
4237 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4240 /* strsplit () that retains the delimiter as part of the string. */
4242 strbreakup (const char *string,
4243 const char *delimiter,
4246 GSList *string_list = NULL, *slist;
4247 gchar **str_array, *s;
4250 g_return_val_if_fail (string != NULL, NULL);
4251 g_return_val_if_fail (delimiter != NULL, NULL);
4254 max_tokens = G_MAXINT;
4256 s = strstr (string, delimiter);
4259 guint delimiter_len = strlen (delimiter);
4266 len = s - string + delimiter_len;
4267 new_string = g_new (gchar, len + 1);
4268 strncpy (new_string, string, len);
4269 new_string[len] = 0;
4270 string_list = g_slist_prepend (string_list, new_string);
4272 string = s + delimiter_len;
4273 s = strstr (string, delimiter);
4275 while (--max_tokens && s);
4280 string_list = g_slist_prepend (string_list, g_strdup (string));
4283 str_array = g_new (gchar*, n);
4287 str_array[i--] = NULL;
4288 for (slist = string_list; slist; slist = slist->next)
4289 str_array[i--] = slist->data;
4291 g_slist_free (string_list);
4297 * gtk_text_iter_forward_search:
4298 * @iter: start of search
4299 * @str: a search string
4300 * @flags: flags affecting how the search is done
4301 * @match_start: return location for start of match, or %NULL
4302 * @match_end: return location for end of match, or %NULL
4303 * @limit: bound for the search, or %NULL for the end of the buffer
4305 * Searches forward for @str. Any match is returned as the range
4306 * @match_start, @match_end. The search will not continue past
4307 * @limit. Note that a search is a linear or O(n) operation, so you
4308 * may wish to use @limit to avoid locking up your UI on large
4311 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4312 * have invisible text interspersed in @str. i.e. @str will be a
4313 * possibly-noncontiguous subsequence of the matched range. similarly,
4314 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4315 * pixbufs or child widgets mixed inside the matched range. If these
4316 * flags are not given, the match must be exact; the special 0xFFFC
4317 * character in @str will match embedded pixbufs or child widgets.
4319 * Return value: whether a match was found
4322 gtk_text_iter_forward_search (const GtkTextIter *iter,
4324 GtkTextSearchFlags flags,
4325 GtkTextIter *match_start,
4326 GtkTextIter *match_end,
4327 const GtkTextIter *limit)
4329 gchar **lines = NULL;
4331 gboolean retval = FALSE;
4333 gboolean visible_only;
4336 g_return_val_if_fail (iter != NULL, FALSE);
4337 g_return_val_if_fail (str != NULL, FALSE);
4340 gtk_text_iter_compare (iter, limit) >= 0)
4345 /* If we can move one char, return the empty string there */
4348 if (gtk_text_iter_forward_char (&match))
4351 gtk_text_iter_equal (&match, limit))
4355 *match_start = match;
4364 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4365 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4367 /* locate all lines */
4369 lines = strbreakup (str, "\n", -1);
4375 /* This loop has an inefficient worst-case, where
4376 * gtk_text_iter_get_text () is called repeatedly on
4382 gtk_text_iter_compare (&search, limit) >= 0)
4385 if (lines_match (&search, (const gchar**)lines,
4386 visible_only, slice, &match, &end))
4388 if (limit == NULL ||
4390 gtk_text_iter_compare (&end, limit) < 0))
4395 *match_start = match;
4404 while (gtk_text_iter_forward_line (&search));
4406 g_strfreev ((gchar**)lines);
4412 vectors_equal_ignoring_trailing (gchar **vec1,
4415 /* Ignores trailing chars in vec2's last line */
4424 if (strcmp (*i1, *i2) != 0)
4426 if (*(i2 + 1) == NULL) /* if this is the last line */
4428 gint len1 = strlen (*i1);
4429 gint len2 = strlen (*i2);
4432 strncmp (*i1, *i2, len1) == 0)
4434 /* We matched ignoring the trailing stuff in vec2 */
4459 typedef struct _LinesWindow LinesWindow;
4465 GtkTextIter first_line_start;
4466 GtkTextIter first_line_end;
4468 gboolean visible_only;
4472 lines_window_init (LinesWindow *win,
4473 const GtkTextIter *start)
4476 GtkTextIter line_start;
4477 GtkTextIter line_end;
4479 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4482 if (gtk_text_iter_is_start (start) ||
4483 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4485 /* Already at the end, or not enough lines to match */
4486 win->lines = g_new0 (gchar*, 1);
4491 line_start = *start;
4494 /* Move to start iter to start of line */
4495 gtk_text_iter_set_line_offset (&line_start, 0);
4497 if (gtk_text_iter_equal (&line_start, &line_end))
4499 /* we were already at the start; so go back one line */
4500 gtk_text_iter_backward_line (&line_start);
4503 win->first_line_start = line_start;
4504 win->first_line_end = line_end;
4506 win->lines = g_new0 (gchar*, win->n_lines + 1);
4508 i = win->n_lines - 1;
4515 if (win->visible_only)
4516 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4518 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4522 if (win->visible_only)
4523 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4525 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4528 win->lines[i] = line_text;
4530 line_end = line_start;
4531 gtk_text_iter_backward_line (&line_start);
4538 lines_window_back (LinesWindow *win)
4540 GtkTextIter new_start;
4543 new_start = win->first_line_start;
4545 if (!gtk_text_iter_backward_line (&new_start))
4549 win->first_line_start = new_start;
4550 win->first_line_end = new_start;
4552 gtk_text_iter_forward_line (&win->first_line_end);
4557 if (win->visible_only)
4558 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4559 &win->first_line_end);
4561 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4562 &win->first_line_end);
4566 if (win->visible_only)
4567 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4568 &win->first_line_end);
4570 line_text = gtk_text_iter_get_text (&win->first_line_start,
4571 &win->first_line_end);
4574 /* Move lines to make room for first line. */
4575 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4577 *win->lines = line_text;
4579 /* Free old last line and NULL-terminate */
4580 g_free (win->lines[win->n_lines]);
4581 win->lines[win->n_lines] = NULL;
4587 lines_window_free (LinesWindow *win)
4589 g_strfreev (win->lines);
4593 my_strrstr (const gchar *haystack,
4594 const gchar *needle)
4596 /* FIXME GLib should have a nice implementation in it, this
4600 gint haystack_len = strlen (haystack);
4601 gint needle_len = strlen (needle);
4602 const gchar *needle_end = needle + needle_len;
4603 const gchar *haystack_rend = haystack - 1;
4604 const gchar *needle_rend = needle - 1;
4607 p = haystack + haystack_len;
4608 while (p != haystack)
4610 const gchar *n = needle_end - 1;
4611 const gchar *s = p - 1;
4612 while (s != haystack_rend &&
4620 if (n == needle_rend)
4630 * gtk_text_iter_backward_search:
4631 * @iter: a #GtkTextIter where the search begins
4632 * @str: search string
4633 * @flags: bitmask of flags affecting the search
4634 * @match_start: return location for start of match, or %NULL
4635 * @match_end: return location for end of match, or %NULL
4636 * @limit: location of last possible @match_start, or %NULL for start of buffer
4638 * Same as gtk_text_iter_forward_search(), but moves backward.
4640 * Return value: whether a match was found
4643 gtk_text_iter_backward_search (const GtkTextIter *iter,
4645 GtkTextSearchFlags flags,
4646 GtkTextIter *match_start,
4647 GtkTextIter *match_end,
4648 const GtkTextIter *limit)
4650 gchar **lines = NULL;
4654 gboolean retval = FALSE;
4655 gboolean visible_only;
4658 g_return_val_if_fail (iter != NULL, FALSE);
4659 g_return_val_if_fail (str != NULL, FALSE);
4662 gtk_text_iter_compare (limit, iter) > 0)
4667 /* If we can move one char, return the empty string there */
4668 GtkTextIter match = *iter;
4670 if (limit && gtk_text_iter_equal (limit, &match))
4673 if (gtk_text_iter_backward_char (&match))
4676 *match_start = match;
4685 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4686 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4688 /* locate all lines */
4690 lines = strbreakup (str, "\n", -1);
4700 win.n_lines = n_lines;
4702 win.visible_only = visible_only;
4704 lines_window_init (&win, iter);
4706 if (*win.lines == NULL)
4711 gchar *first_line_match;
4714 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4716 /* We're now before the search limit, abort. */
4720 /* If there are multiple lines, the first line will
4721 * end in '\n', so this will only match at the
4722 * end of the first line, which is correct.
4724 first_line_match = my_strrstr (*win.lines, *lines);
4726 if (first_line_match &&
4727 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4732 GtkTextIter start_tmp;
4734 /* Offset to start of search string */
4735 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4737 next = win.first_line_start;
4739 forward_chars_with_skipping (&start_tmp, offset,
4740 visible_only, !slice);
4743 gtk_text_iter_compare (limit, &start_tmp) > 0)
4744 goto out; /* match was bogus */
4747 *match_start = start_tmp;
4749 /* Go to end of search string */
4753 offset += g_utf8_strlen (*l, -1);
4757 forward_chars_with_skipping (&next, offset,
4758 visible_only, !slice);
4767 while (lines_window_back (&win));
4770 lines_window_free (&win);
4781 * gtk_text_iter_equal:
4782 * @lhs: a #GtkTextIter
4783 * @rhs: another #GtkTextIter
4785 * Tests whether two iterators are equal, using the fastest possible
4786 * mechanism. This function is very fast; you can expect it to perform
4787 * better than e.g. getting the character offset for each iterator and
4788 * comparing the offsets yourself. Also, it's a bit faster than
4789 * gtk_text_iter_compare().
4791 * Return value: %TRUE if the iterators point to the same place in the buffer
4794 gtk_text_iter_equal (const GtkTextIter *lhs,
4795 const GtkTextIter *rhs)
4797 GtkTextRealIter *real_lhs;
4798 GtkTextRealIter *real_rhs;
4800 real_lhs = (GtkTextRealIter*)lhs;
4801 real_rhs = (GtkTextRealIter*)rhs;
4803 check_invariants (lhs);
4804 check_invariants (rhs);
4806 if (real_lhs->line != real_rhs->line)
4808 else if (real_lhs->line_byte_offset >= 0 &&
4809 real_rhs->line_byte_offset >= 0)
4810 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4813 /* the ensure_char_offsets () calls do nothing if the char offsets
4814 are already up-to-date. */
4815 ensure_char_offsets (real_lhs);
4816 ensure_char_offsets (real_rhs);
4817 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4822 * gtk_text_iter_compare:
4823 * @lhs: a #GtkTextIter
4824 * @rhs: another #GtkTextIter
4826 * A qsort()-style function that returns negative if @lhs is less than
4827 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4828 * Ordering is in character offset order, i.e. the first character in the buffer
4829 * is less than the second character in the buffer.
4831 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4834 gtk_text_iter_compare (const GtkTextIter *lhs,
4835 const GtkTextIter *rhs)
4837 GtkTextRealIter *real_lhs;
4838 GtkTextRealIter *real_rhs;
4840 real_lhs = gtk_text_iter_make_surreal (lhs);
4841 real_rhs = gtk_text_iter_make_surreal (rhs);
4843 if (real_lhs == NULL ||
4845 return -1; /* why not */
4847 check_invariants (lhs);
4848 check_invariants (rhs);
4850 if (real_lhs->line == real_rhs->line)
4852 gint left_index, right_index;
4854 if (real_lhs->line_byte_offset >= 0 &&
4855 real_rhs->line_byte_offset >= 0)
4857 left_index = real_lhs->line_byte_offset;
4858 right_index = real_rhs->line_byte_offset;
4862 /* the ensure_char_offsets () calls do nothing if
4863 the offsets are already up-to-date. */
4864 ensure_char_offsets (real_lhs);
4865 ensure_char_offsets (real_rhs);
4866 left_index = real_lhs->line_char_offset;
4867 right_index = real_rhs->line_char_offset;
4870 if (left_index < right_index)
4872 else if (left_index > right_index)
4881 line1 = gtk_text_iter_get_line (lhs);
4882 line2 = gtk_text_iter_get_line (rhs);
4885 else if (line1 > line2)
4893 * gtk_text_iter_in_range:
4894 * @iter: a #GtkTextIter
4895 * @start: start of range
4896 * @end: end of range
4898 * Checks whether @iter falls in the range [@start, @end).
4899 * @start and @end must be in ascending order.
4901 * Return value: %TRUE if @iter is in the range
4904 gtk_text_iter_in_range (const GtkTextIter *iter,
4905 const GtkTextIter *start,
4906 const GtkTextIter *end)
4908 g_return_val_if_fail (iter != NULL, FALSE);
4909 g_return_val_if_fail (start != NULL, FALSE);
4910 g_return_val_if_fail (end != NULL, FALSE);
4911 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4913 return gtk_text_iter_compare (iter, start) >= 0 &&
4914 gtk_text_iter_compare (iter, end) < 0;
4918 * gtk_text_iter_order:
4919 * @first: a #GtkTextIter
4920 * @second: another #GtkTextIter
4922 * Swaps the value of @first and @second if @second comes before
4923 * @first in the buffer. That is, ensures that @first and @second are
4924 * in sequence. Most text buffer functions that take a range call this
4925 * automatically on your behalf, so there's no real reason to call it yourself
4926 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4927 * that expect a pre-sorted range.
4931 gtk_text_iter_order (GtkTextIter *first,
4932 GtkTextIter *second)
4934 g_return_if_fail (first != NULL);
4935 g_return_if_fail (second != NULL);
4937 if (gtk_text_iter_compare (first, second) > 0)
4948 * Init iterators from the BTree
4952 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4956 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4957 gint real_char_index;
4961 g_return_if_fail (iter != NULL);
4962 g_return_if_fail (tree != NULL);
4964 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4965 &line_start, &real_char_index);
4967 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4969 real->cached_char_index = real_char_index;
4971 check_invariants (iter);
4975 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4980 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4984 g_return_if_fail (iter != NULL);
4985 g_return_if_fail (tree != NULL);
4987 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
4989 iter_init_from_char_offset (iter, tree, line, char_on_line);
4991 /* We might as well cache this, since we know it. */
4992 real->cached_line_number = real_line;
4994 check_invariants (iter);
4998 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5003 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5007 g_return_if_fail (iter != NULL);
5008 g_return_if_fail (tree != NULL);
5010 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5012 iter_init_from_byte_offset (iter, tree, line, byte_index);
5014 /* We might as well cache this, since we know it. */
5015 real->cached_line_number = real_line;
5017 check_invariants (iter);
5021 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5026 g_return_if_fail (iter != NULL);
5027 g_return_if_fail (tree != NULL);
5028 g_return_if_fail (line != NULL);
5030 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5032 check_invariants (iter);
5036 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5042 g_return_val_if_fail (iter != NULL, FALSE);
5043 g_return_val_if_fail (tree != NULL, FALSE);
5045 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5049 /* Set iter to last in tree */
5050 _gtk_text_btree_get_end_iter (tree, iter);
5051 check_invariants (iter);
5056 iter_init_from_byte_offset (iter, tree, line, 0);
5057 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5058 check_invariants (iter);
5064 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5068 g_return_val_if_fail (iter != NULL, FALSE);
5069 g_return_val_if_fail (tree != NULL, FALSE);
5071 _gtk_text_btree_get_end_iter (tree, iter);
5072 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5073 check_invariants (iter);
5079 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5081 const gchar *mark_name)
5085 g_return_val_if_fail (iter != NULL, FALSE);
5086 g_return_val_if_fail (tree != NULL, FALSE);
5088 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5094 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5095 check_invariants (iter);
5101 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5105 GtkTextLineSegment *seg;
5107 g_return_if_fail (iter != NULL);
5108 g_return_if_fail (tree != NULL);
5109 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5111 seg = mark->segment;
5113 iter_init_from_segment (iter, tree,
5114 seg->body.mark.line, seg);
5115 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5116 check_invariants (iter);
5120 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5122 GtkTextChildAnchor *anchor)
5124 GtkTextLineSegment *seg;
5126 g_return_if_fail (iter != NULL);
5127 g_return_if_fail (tree != NULL);
5128 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5130 seg = anchor->segment;
5132 iter_init_from_segment (iter, tree,
5133 seg->body.child.line, seg);
5134 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5135 check_invariants (iter);
5139 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5142 g_return_if_fail (iter != NULL);
5143 g_return_if_fail (tree != NULL);
5145 _gtk_text_btree_get_iter_at_char (tree,
5147 _gtk_text_btree_char_count (tree));
5148 check_invariants (iter);
5152 _gtk_text_iter_check (const GtkTextIter *iter)
5154 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5155 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5156 GtkTextLineSegment *byte_segment = NULL;
5157 GtkTextLineSegment *byte_any_segment = NULL;
5158 GtkTextLineSegment *char_segment = NULL;
5159 GtkTextLineSegment *char_any_segment = NULL;
5160 gboolean segments_updated;
5162 /* This function checks our class invariants for the Iter class. */
5164 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5166 if (real->chars_changed_stamp !=
5167 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5168 g_error ("iterator check failed: invalid iterator");
5170 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5171 g_error ("iterator check failed: both char and byte offsets are invalid");
5173 segments_updated = (real->segments_changed_stamp ==
5174 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5177 printf ("checking iter, segments %s updated, byte %d char %d\n",
5178 segments_updated ? "are" : "aren't",
5179 real->line_byte_offset,
5180 real->line_char_offset);
5183 if (segments_updated)
5185 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5186 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5188 if (real->segment->char_count == 0)
5189 g_error ("iterator check failed: segment is not indexable.");
5191 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5192 g_error ("segment char offset is not properly up-to-date");
5194 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5195 g_error ("segment byte offset is not properly up-to-date");
5197 if (real->segment_byte_offset >= 0 &&
5198 real->segment_byte_offset >= real->segment->byte_count)
5199 g_error ("segment byte offset is too large.");
5201 if (real->segment_char_offset >= 0 &&
5202 real->segment_char_offset >= real->segment->char_count)
5203 g_error ("segment char offset is too large.");
5206 if (real->line_byte_offset >= 0)
5208 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5209 &byte_segment, &byte_any_segment,
5210 &seg_byte_offset, &line_byte_offset);
5212 if (line_byte_offset != real->line_byte_offset)
5213 g_error ("wrong byte offset was stored in iterator");
5215 if (segments_updated)
5217 if (real->segment != byte_segment)
5218 g_error ("wrong segment was stored in iterator");
5220 if (real->any_segment != byte_any_segment)
5221 g_error ("wrong any_segment was stored in iterator");
5223 if (seg_byte_offset != real->segment_byte_offset)
5224 g_error ("wrong segment byte offset was stored in iterator");
5226 if (byte_segment->type == >k_text_char_type)
5229 p = byte_segment->body.chars + seg_byte_offset;
5231 if (!gtk_text_byte_begins_utf8_char (p))
5232 g_error ("broken iterator byte index pointed into the middle of a character");
5237 if (real->line_char_offset >= 0)
5239 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5240 &char_segment, &char_any_segment,
5241 &seg_char_offset, &line_char_offset);
5243 if (line_char_offset != real->line_char_offset)
5244 g_error ("wrong char offset was stored in iterator");
5246 if (segments_updated)
5248 if (real->segment != char_segment)
5249 g_error ("wrong segment was stored in iterator");
5251 if (real->any_segment != char_any_segment)
5252 g_error ("wrong any_segment was stored in iterator");
5254 if (seg_char_offset != real->segment_char_offset)
5255 g_error ("wrong segment char offset was stored in iterator");
5257 if (char_segment->type == >k_text_char_type)
5260 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5263 /* hmm, not likely to happen eh */
5264 if (!gtk_text_byte_begins_utf8_char (p))
5265 g_error ("broken iterator char offset pointed into the middle of a character");
5270 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5272 if (byte_segment != char_segment)
5273 g_error ("char and byte offsets did not point to the same segment");
5275 if (byte_any_segment != char_any_segment)
5276 g_error ("char and byte offsets did not point to the same any segment");
5278 /* Make sure the segment offsets are equivalent, if it's a char
5280 if (char_segment->type == >k_text_char_type)
5282 gint byte_offset = 0;
5283 gint char_offset = 0;
5284 while (char_offset < seg_char_offset)
5286 const char * start = char_segment->body.chars + byte_offset;
5287 byte_offset += g_utf8_next_char (start) - start;
5291 if (byte_offset != seg_byte_offset)
5292 g_error ("byte offset did not correspond to char offset");
5295 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5297 if (char_offset != seg_char_offset)
5298 g_error ("char offset did not correspond to byte offset");
5300 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5301 g_error ("byte index for iterator does not index the start of a character");
5305 if (real->cached_line_number >= 0)
5309 should_be = _gtk_text_line_get_number (real->line);
5310 if (real->cached_line_number != should_be)
5311 g_error ("wrong line number was cached");
5314 if (real->cached_char_index >= 0)
5316 if (real->line_char_offset >= 0) /* only way we can check it
5317 efficiently, not a real
5322 char_index = _gtk_text_line_char_index (real->line);
5323 char_index += real->line_char_offset;
5325 if (real->cached_char_index != char_index)
5326 g_error ("wrong char index was cached");
5330 if (_gtk_text_line_is_last (real->line, real->tree))
5331 g_error ("Iterator was on last line (past the end iterator)");