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);
2013 /* End of buffer, but iter is still at start of last segment,
2014 * not at the end iterator. We put it on the end iterator.
2017 check_invariants (iter);
2019 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2020 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2022 gtk_text_iter_forward_to_line_end (iter);
2024 g_assert (gtk_text_iter_is_end (iter));
2032 at_last_indexable_segment (GtkTextRealIter *real)
2034 GtkTextLineSegment *seg;
2036 /* Return TRUE if there are no indexable segments after
2040 seg = real->segment->next;
2043 if (seg->char_count > 0)
2050 /* Goes back to the start of the next segment, even if
2051 * we're not at the start of the current segment (always
2052 * ends up on a different segment if it returns TRUE)
2055 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2057 /* Move to the start of the previous segment; if no previous
2058 * segment, to the last segment in the previous line. This is
2059 * inherently a bit inefficient due to the singly-linked list and
2060 * tree nodes, but we can't afford the RAM for doubly-linked.
2062 GtkTextRealIter *real;
2063 GtkTextLineSegment *seg;
2064 GtkTextLineSegment *any_seg;
2065 GtkTextLineSegment *prev_seg;
2066 GtkTextLineSegment *prev_any_seg;
2070 g_return_val_if_fail (iter != NULL, FALSE);
2072 real = gtk_text_iter_make_real (iter);
2077 check_invariants (iter);
2079 /* Find first segments in line */
2080 any_seg = real->line->segments;
2082 while (seg->char_count == 0)
2085 if (seg == real->segment)
2087 /* Could probably do this case faster by hand-coding the
2091 /* We were already at the start of a line;
2092 * go back to the previous line.
2094 if (gtk_text_iter_backward_line (iter))
2096 /* Go forward to last indexable segment in line. */
2097 while (!at_last_indexable_segment (real))
2098 _gtk_text_iter_forward_indexable_segment (iter);
2100 check_invariants (iter);
2105 return FALSE; /* We were at the start of the first line. */
2108 /* We must be in the middle of a line; so find the indexable
2109 * segment just before our current segment.
2111 g_assert (seg != real->segment);
2115 prev_any_seg = any_seg;
2117 any_seg = seg->next;
2119 while (seg->char_count == 0)
2122 while (seg != real->segment);
2124 g_assert (prev_seg != NULL);
2125 g_assert (prev_any_seg != NULL);
2126 g_assert (prev_seg->char_count > 0);
2128 /* We skipped the entire previous segment, plus any
2129 * chars we were into the current segment.
2131 if (real->segment_byte_offset >= 0)
2132 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2136 if (real->segment_char_offset >= 0)
2137 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2141 real->segment = prev_seg;
2142 real->any_segment = prev_any_seg;
2143 real->segment_byte_offset = 0;
2144 real->segment_char_offset = 0;
2146 if (bytes_skipped >= 0)
2148 if (real->line_byte_offset >= 0)
2150 real->line_byte_offset -= bytes_skipped;
2151 g_assert (real->line_byte_offset >= 0);
2155 real->line_byte_offset = -1;
2157 if (chars_skipped >= 0)
2159 if (real->line_char_offset >= 0)
2161 real->line_char_offset -= chars_skipped;
2162 g_assert (real->line_char_offset >= 0);
2165 if (real->cached_char_index >= 0)
2167 real->cached_char_index -= chars_skipped;
2168 g_assert (real->cached_char_index >= 0);
2173 real->line_char_offset = -1;
2174 real->cached_char_index = -1;
2177 /* line number is unchanged. */
2179 check_invariants (iter);
2185 * gtk_text_iter_forward_char:
2186 * @iter: an iterator
2188 * Moves @iter forward by one character offset. Note that images
2189 * embedded in the buffer occupy 1 character slot, so
2190 * gtk_text_iter_forward_char () may actually move onto an image instead
2191 * of a character, if you have images in your buffer. If @iter is the
2192 * end iterator or one character before it, @iter will now point at
2193 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2194 * convenience when writing loops.
2196 * Return value: whether @iter moved and is dereferenceable
2199 gtk_text_iter_forward_char (GtkTextIter *iter)
2201 GtkTextRealIter *real;
2203 g_return_val_if_fail (iter != NULL, FALSE);
2205 real = gtk_text_iter_make_real (iter);
2211 check_invariants (iter);
2212 return forward_char (real);
2217 * gtk_text_iter_backward_char:
2218 * @iter: an iterator
2220 * Moves backward by one character offset. Returns %TRUE if movement
2221 * was possible; if @iter was the first in the buffer (character
2222 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2225 * Return value: whether movement was possible
2228 gtk_text_iter_backward_char (GtkTextIter *iter)
2230 g_return_val_if_fail (iter != NULL, FALSE);
2232 check_invariants (iter);
2234 return gtk_text_iter_backward_chars (iter, 1);
2238 Definitely we should try to linear scan as often as possible for
2239 movement within a single line, because we can't use the BTree to
2240 speed within-line searches up; for movement between lines, we would
2241 like to avoid the linear scan probably.
2243 Instead of using this constant, it might be nice to cache the line
2244 length in the iterator and linear scan if motion is within a single
2247 I guess you'd have to profile the various approaches.
2249 #define MAX_LINEAR_SCAN 150
2253 * gtk_text_iter_forward_chars:
2254 * @iter: an iterator
2255 * @count: number of characters to move, may be negative
2257 * Moves @count characters if possible (if @count would move past the
2258 * start or end of the buffer, moves to the start or end of the
2259 * buffer). The return value indicates whether the new position of
2260 * @iter is different from its original position, and dereferenceable
2261 * (the last iterator in the buffer is not dereferenceable). If @count
2262 * is 0, the function does nothing and returns %FALSE.
2264 * Return value: whether @iter moved and is dereferenceable
2267 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2269 GtkTextRealIter *real;
2271 g_return_val_if_fail (iter != NULL, FALSE);
2273 FIX_OVERFLOWS (count);
2275 real = gtk_text_iter_make_real (iter);
2279 else if (count == 0)
2282 return gtk_text_iter_backward_chars (iter, 0 - count);
2283 else if (count < MAX_LINEAR_SCAN)
2285 check_invariants (iter);
2289 if (!forward_char (real))
2294 return forward_char (real);
2298 gint current_char_index;
2299 gint new_char_index;
2301 check_invariants (iter);
2303 current_char_index = gtk_text_iter_get_offset (iter);
2305 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2306 return FALSE; /* can't move forward */
2308 new_char_index = current_char_index + count;
2309 gtk_text_iter_set_offset (iter, new_char_index);
2311 check_invariants (iter);
2313 /* Return FALSE if we're on the non-dereferenceable end
2316 if (gtk_text_iter_is_end (iter))
2324 * gtk_text_iter_backward_chars:
2325 * @iter: an iterator
2326 * @count: number of characters to move
2328 * Moves @count characters backward, if possible (if @count would move
2329 * past the start or end of the buffer, moves to the start or end of
2330 * the buffer). The return value indicates whether the iterator moved
2331 * onto a dereferenceable position; if the iterator didn't move, or
2332 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2333 * the function does nothing and returns %FALSE.
2335 * Return value: whether @iter moved and is dereferenceable
2339 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2341 GtkTextRealIter *real;
2343 g_return_val_if_fail (iter != NULL, FALSE);
2345 FIX_OVERFLOWS (count);
2347 real = gtk_text_iter_make_real (iter);
2351 else if (count == 0)
2354 return gtk_text_iter_forward_chars (iter, 0 - count);
2356 ensure_char_offsets (real);
2357 check_invariants (iter);
2359 /* <, not <=, because if count == segment_char_offset
2360 * we're going to the front of the segment and the any_segment
2363 if (count < real->segment_char_offset)
2365 /* Optimize the within-segment case */
2366 g_assert (real->segment->char_count > 0);
2367 g_assert (real->segment->type == >k_text_char_type);
2369 real->segment_char_offset -= count;
2370 g_assert (real->segment_char_offset >= 0);
2372 if (real->line_byte_offset >= 0)
2374 gint new_byte_offset;
2377 new_byte_offset = 0;
2379 while (i < real->segment_char_offset)
2381 const char * start = real->segment->body.chars + new_byte_offset;
2382 new_byte_offset += g_utf8_next_char (start) - start;
2387 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2388 real->segment_byte_offset = new_byte_offset;
2391 real->line_char_offset -= count;
2393 adjust_char_index (real, 0 - count);
2395 check_invariants (iter);
2401 /* We need to go back into previous segments. For now,
2402 * just keep this really simple. FIXME
2403 * use backward_indexable_segment.
2405 if (TRUE || count > MAX_LINEAR_SCAN)
2407 gint current_char_index;
2408 gint new_char_index;
2410 current_char_index = gtk_text_iter_get_offset (iter);
2412 if (current_char_index == 0)
2413 return FALSE; /* can't move backward */
2415 new_char_index = current_char_index - count;
2416 if (new_char_index < 0)
2419 gtk_text_iter_set_offset (iter, new_char_index);
2421 check_invariants (iter);
2427 /* FIXME backward_indexable_segment here */
2436 /* These two can't be implemented efficiently (always have to use
2437 * a linear scan, since that's the only way to find all the non-text
2442 * gtk_text_iter_forward_text_chars:
2443 * @iter: a #GtkTextIter
2444 * @count: number of chars to move
2446 * Moves forward by @count text characters (pixbufs, widgets,
2447 * etc. do not count as characters for this). Equivalent to moving
2448 * through the results of gtk_text_iter_get_text (), rather than
2449 * gtk_text_iter_get_slice ().
2451 * Return value: whether @iter moved and is dereferenceable
2454 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2463 * gtk_text_iter_forward_text_chars:
2464 * @iter: a #GtkTextIter
2465 * @count: number of chars to move
2467 * Moves backward by @count text characters (pixbufs, widgets,
2468 * etc. do not count as characters for this). Equivalent to moving
2469 * through the results of gtk_text_iter_get_text (), rather than
2470 * gtk_text_iter_get_slice ().
2472 * Return value: whether @iter moved and is dereferenceable
2475 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2484 * gtk_text_iter_forward_line:
2485 * @iter: an iterator
2487 * Moves @iter to the start of the next line. Returns %TRUE if there
2488 * was a next line to move to, and %FALSE if @iter was simply moved to
2489 * the end of the buffer and is now not dereferenceable, or if @iter was
2490 * already at the end of the buffer.
2492 * Return value: whether @iter can be dereferenced
2495 gtk_text_iter_forward_line (GtkTextIter *iter)
2497 GtkTextRealIter *real;
2499 g_return_val_if_fail (iter != NULL, FALSE);
2501 real = gtk_text_iter_make_real (iter);
2506 check_invariants (iter);
2508 if (forward_line_leaving_caches_unmodified (real))
2510 invalidate_char_index (real);
2511 adjust_line_number (real, 1);
2513 check_invariants (iter);
2515 if (gtk_text_iter_is_end (iter))
2522 /* On the last line, move to end of it */
2524 if (!gtk_text_iter_is_end (iter))
2525 gtk_text_iter_forward_to_end (iter);
2527 check_invariants (iter);
2533 * gtk_text_iter_backward_line:
2534 * @iter: an iterator
2536 * Moves @iter to the start of the previous line. Returns %TRUE if
2537 * @iter could be moved; i.e. if @iter was at character offset 0, this
2538 * function returns %FALSE. Therefore if @iter was already on line 0,
2539 * but not at the start of the line, @iter is snapped to the start of
2540 * the line and the function returns %TRUE. (Note that this implies that
2541 * in a loop calling this function, the line number may not change on
2542 * every iteration, if your first iteration is on line 0.)
2544 * Return value: whether @iter moved
2547 gtk_text_iter_backward_line (GtkTextIter *iter)
2549 GtkTextLine *new_line;
2550 GtkTextRealIter *real;
2551 gboolean offset_will_change;
2554 g_return_val_if_fail (iter != NULL, FALSE);
2556 real = gtk_text_iter_make_real (iter);
2561 check_invariants (iter);
2563 new_line = _gtk_text_line_previous (real->line);
2565 offset_will_change = FALSE;
2566 if (real->line_char_offset > 0)
2567 offset_will_change = TRUE;
2569 if (new_line != NULL)
2571 real->line = new_line;
2573 adjust_line_number (real, -1);
2577 if (!offset_will_change)
2581 invalidate_char_index (real);
2583 real->line_byte_offset = 0;
2584 real->line_char_offset = 0;
2586 real->segment_byte_offset = 0;
2587 real->segment_char_offset = 0;
2589 /* Find first segment in line */
2590 real->any_segment = real->line->segments;
2591 real->segment = _gtk_text_line_byte_to_segment (real->line,
2594 g_assert (offset == 0);
2596 /* Note that if we are on the first line, we snap to the start of
2597 * the first line and return TRUE, so TRUE means the iterator
2598 * changed, not that the line changed; this is maybe a bit
2599 * weird. I'm not sure there's an obvious right thing to do though.
2602 check_invariants (iter);
2609 * gtk_text_iter_forward_lines:
2610 * @iter: a #GtkTextIter
2611 * @count: number of lines to move forward
2613 * Moves @count lines forward, if possible (if @count would move
2614 * past the start or end of the buffer, moves to the start or end of
2615 * the buffer). The return value indicates whether the iterator moved
2616 * onto a dereferenceable position; if the iterator didn't move, or
2617 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2618 * the function does nothing and returns %FALSE. If @count is negative,
2619 * moves backward by 0 - @count lines.
2621 * Return value: whether @iter moved and is dereferenceable
2624 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2626 FIX_OVERFLOWS (count);
2629 return gtk_text_iter_backward_lines (iter, 0 - count);
2630 else if (count == 0)
2632 else if (count == 1)
2634 check_invariants (iter);
2635 return gtk_text_iter_forward_line (iter);
2641 if (gtk_text_iter_is_end (iter))
2644 old_line = gtk_text_iter_get_line (iter);
2646 gtk_text_iter_set_line (iter, old_line + count);
2648 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2650 /* count went past the last line, so move to end of last line */
2651 if (!gtk_text_iter_is_end (iter))
2652 gtk_text_iter_forward_to_end (iter);
2655 return !gtk_text_iter_is_end (iter);
2660 * gtk_text_iter_backward_lines:
2661 * @iter: a #GtkTextIter
2662 * @count: number of lines to move backward
2664 * Moves @count lines backward, if possible (if @count would move
2665 * past the start or end of the buffer, moves to the start or end of
2666 * the buffer). The return value indicates whether the iterator moved
2667 * onto a dereferenceable position; if the iterator didn't move, or
2668 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2669 * the function does nothing and returns %FALSE. If @count is negative,
2670 * moves forward by 0 - @count lines.
2672 * Return value: whether @iter moved and is dereferenceable
2675 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2677 FIX_OVERFLOWS (count);
2680 return gtk_text_iter_forward_lines (iter, 0 - count);
2681 else if (count == 0)
2683 else if (count == 1)
2685 return gtk_text_iter_backward_line (iter);
2691 old_line = gtk_text_iter_get_line (iter);
2693 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2695 return (gtk_text_iter_get_line (iter) != old_line);
2699 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2704 gboolean already_moved_initially);
2706 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2714 find_word_end_func (const PangoLogAttr *attrs,
2719 gboolean already_moved_initially)
2721 if (!already_moved_initially)
2724 /* Find end of next word */
2725 while (offset < min_offset + len &&
2726 !attrs[offset].is_word_end)
2729 *found_offset = offset;
2731 return offset < min_offset + len;
2735 is_word_end_func (const PangoLogAttr *attrs,
2740 return attrs[offset].is_word_end;
2744 find_word_start_func (const PangoLogAttr *attrs,
2749 gboolean already_moved_initially)
2751 if (!already_moved_initially)
2754 /* Find start of prev word */
2755 while (offset >= min_offset &&
2756 !attrs[offset].is_word_start)
2759 *found_offset = offset;
2761 return offset >= min_offset;
2765 is_word_start_func (const PangoLogAttr *attrs,
2770 return attrs[offset].is_word_start;
2774 inside_word_func (const PangoLogAttr *attrs,
2779 /* Find next word start or end */
2780 while (offset >= min_offset &&
2781 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2784 return attrs[offset].is_word_start;
2787 /* Sentence funcs */
2790 find_sentence_end_func (const PangoLogAttr *attrs,
2795 gboolean already_moved_initially)
2797 if (!already_moved_initially)
2800 /* Find end of next sentence */
2801 while (offset < min_offset + len &&
2802 !attrs[offset].is_sentence_end)
2805 *found_offset = offset;
2807 return offset < min_offset + len;
2811 is_sentence_end_func (const PangoLogAttr *attrs,
2816 return attrs[offset].is_sentence_end;
2820 find_sentence_start_func (const PangoLogAttr *attrs,
2825 gboolean already_moved_initially)
2827 if (!already_moved_initially)
2830 /* Find start of prev sentence */
2831 while (offset >= min_offset &&
2832 !attrs[offset].is_sentence_start)
2835 *found_offset = offset;
2837 return offset >= min_offset;
2841 is_sentence_start_func (const PangoLogAttr *attrs,
2846 return attrs[offset].is_sentence_start;
2850 inside_sentence_func (const PangoLogAttr *attrs,
2855 /* Find next sentence start or end */
2856 while (offset >= min_offset &&
2857 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2860 return attrs[offset].is_sentence_start;
2864 test_log_attrs (const GtkTextIter *iter,
2865 TestLogAttrFunc func)
2868 const PangoLogAttr *attrs;
2870 gboolean result = FALSE;
2872 g_return_val_if_fail (iter != NULL, FALSE);
2874 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2877 offset = gtk_text_iter_get_line_offset (iter);
2879 /* char_len may be 0 and attrs will be NULL if so, if
2880 * iter is the end iter and the last line is empty.
2882 * offset may be equal to char_len, since attrs contains an entry
2883 * for one past the end
2886 if (attrs && offset <= char_len)
2887 result = (* func) (attrs, offset, 0, char_len);
2893 find_line_log_attrs (const GtkTextIter *iter,
2894 FindLogAttrFunc func,
2896 gboolean already_moved_initially)
2899 const PangoLogAttr *attrs;
2901 gboolean result = FALSE;
2903 g_return_val_if_fail (iter != NULL, FALSE);
2905 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2908 offset = gtk_text_iter_get_line_offset (iter);
2910 /* char_len may be 0 and attrs will be NULL if so, if
2911 * iter is the end iter and the last line is empty
2915 result = (* func) (attrs, offset, 0, char_len, found_offset,
2916 already_moved_initially);
2921 /* FIXME this function is very, very gratuitously slow */
2923 find_by_log_attrs (GtkTextIter *iter,
2924 FindLogAttrFunc func,
2926 gboolean already_moved_initially)
2930 gboolean found = FALSE;
2932 g_return_val_if_fail (iter != NULL, FALSE);
2936 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2942 if (gtk_text_iter_forward_line (iter))
2943 return find_by_log_attrs (iter, func, forward,
2950 /* go to end of previous line. need to check that
2951 * line is > 0 because backward_line snaps to start of
2952 * line 0 if it's on line 0
2954 if (gtk_text_iter_get_line (iter) > 0 &&
2955 gtk_text_iter_backward_line (iter))
2957 if (!gtk_text_iter_ends_line (iter))
2958 gtk_text_iter_forward_to_line_end (iter);
2960 return find_by_log_attrs (iter, func, forward,
2969 gtk_text_iter_set_line_offset (iter, offset);
2972 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2973 !gtk_text_iter_is_end (iter);
2978 * gtk_text_iter_forward_word_end:
2979 * @iter: a #GtkTextIter
2981 * Moves forward to the next word end. (If @iter is currently on a
2982 * word end, moves forward to the next one after that.) Word breaks
2983 * are determined by Pango and should be correct for nearly any
2984 * language (if not, the correct fix would be to the Pango word break
2987 * Return value: %TRUE if @iter moved and is not the end iterator
2990 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2992 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2996 * gtk_text_iter_backward_word_start:
2997 * @iter: a #GtkTextIter
2999 * Moves backward to the previous word start. (If @iter is currently on a
3000 * word start, moves backward to the next one after that.) Word breaks
3001 * are determined by Pango and should be correct for nearly any
3002 * language (if not, the correct fix would be to the Pango word break
3005 * Return value: %TRUE if @iter moved and is not the end iterator
3008 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3010 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3013 /* FIXME a loop around a truly slow function means
3014 * a truly spectacularly slow function.
3018 * gtk_text_iter_forward_word_ends:
3019 * @iter: a #GtkTextIter
3020 * @count: number of times to move
3022 * Calls gtk_text_iter_forward_word_end() up to @count times.
3024 * Return value: %TRUE if @iter moved and is not the end iterator
3027 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3030 g_return_val_if_fail (iter != NULL, FALSE);
3032 FIX_OVERFLOWS (count);
3038 return gtk_text_iter_backward_word_starts (iter, -count);
3040 if (!gtk_text_iter_forward_word_end (iter))
3046 if (!gtk_text_iter_forward_word_end (iter))
3051 return !gtk_text_iter_is_end (iter);
3055 * gtk_text_iter_backward_word_starts
3056 * @iter: a #GtkTextIter
3057 * @count: number of times to move
3059 * Calls gtk_text_iter_backward_word_starts() up to @count times.
3061 * Return value: %TRUE if @iter moved and is not the end iterator
3064 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3067 g_return_val_if_fail (iter != NULL, FALSE);
3069 FIX_OVERFLOWS (count);
3072 return gtk_text_iter_forward_word_ends (iter, -count);
3074 if (!gtk_text_iter_backward_word_start (iter))
3080 if (!gtk_text_iter_backward_word_start (iter))
3085 return !gtk_text_iter_is_end (iter);
3089 * gtk_text_iter_starts_word:
3090 * @iter: a #GtkTextIter
3092 * Determines whether @iter begins a natural-language word. Word
3093 * breaks are determined by Pango and should be correct for nearly any
3094 * language (if not, the correct fix would be to the Pango word break
3097 * Return value: %TRUE if @iter is at the start of a word
3100 gtk_text_iter_starts_word (const GtkTextIter *iter)
3102 return test_log_attrs (iter, is_word_start_func);
3106 * gtk_text_iter_ends_word:
3107 * @iter: a #GtkTextIter
3109 * Determines whether @iter ends a natural-language word. Word breaks
3110 * are determined by Pango and should be correct for nearly any
3111 * language (if not, the correct fix would be to the Pango word break
3114 * Return value: %TRUE if @iter is at the end of a word
3117 gtk_text_iter_ends_word (const GtkTextIter *iter)
3119 return test_log_attrs (iter, is_word_end_func);
3123 * gtk_text_iter_inside_word:
3124 * @iter: a #GtkTextIter
3126 * Determines whether @iter is inside a natural-language word (as
3127 * opposed to say inside some whitespace). Word breaks are determined
3128 * by Pango and should be correct for nearly any language (if not, the
3129 * correct fix would be to the Pango word break algorithms).
3131 * Return value: %TRUE if @iter is inside a word
3134 gtk_text_iter_inside_word (const GtkTextIter *iter)
3136 return test_log_attrs (iter, inside_word_func);
3140 * gtk_text_iter_starts_sentence:
3141 * @iter: a #GtkTextIter
3143 * Determines whether @iter begins a sentence. Sentence boundaries are
3144 * determined by Pango and should be correct for nearly any language
3145 * (if not, the correct fix would be to the Pango text boundary
3148 * Return value: %TRUE if @iter is at the start of a sentence.
3151 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3153 return test_log_attrs (iter, is_sentence_start_func);
3157 * gtk_text_iter_ends_sentence:
3158 * @iter: a #GtkTextIter
3160 * Determines whether @iter ends a sentence. Sentence boundaries are
3161 * determined by Pango and should be correct for nearly any language
3162 * (if not, the correct fix would be to the Pango text boundary
3165 * Return value: %TRUE if @iter is at the end of a sentence.
3168 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3170 return test_log_attrs (iter, is_sentence_end_func);
3174 * gtk_text_iter_inside_sentence:
3175 * @iter: a #GtkTextIter
3177 * Determines whether @iter is inside a sentence (as opposed to in
3178 * between two sentences, e.g. after a period and before the first
3179 * letter of the next sentence). Sentence boundaries are determined
3180 * by Pango and should be correct for nearly any language (if not, the
3181 * correct fix would be to the Pango text boundary algorithms).
3183 * Return value: %TRUE if @iter is inside a sentence.
3186 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3188 return test_log_attrs (iter, inside_sentence_func);
3192 * gtk_text_iter_forward_sentence_end:
3193 * @iter: a #GtkTextIter
3195 * Moves forward to the next sentence end. (If @iter is at the end of
3196 * a sentence, moves to the next end of sentence.) Sentence
3197 * boundaries are determined by Pango and should be correct for nearly
3198 * any language (if not, the correct fix would be to the Pango text
3199 * boundary algorithms).
3201 * Return value: %TRUE if @iter moved and is not the end iterator
3204 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3206 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3210 * gtk_text_iter_backward_sentence_start:
3211 * @iter: a #GtkTextIter
3213 * Moves backward to the previous sentence start; if @iter is already at
3214 * the start of a sentence, moves backward to the next one. Sentence
3215 * boundaries are determined by Pango and should be correct for nearly
3216 * any language (if not, the correct fix would be to the Pango text
3217 * boundary algorithms).
3219 * Return value: %TRUE if @iter moved and is not the end iterator
3222 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3224 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3227 /* FIXME a loop around a truly slow function means
3228 * a truly spectacularly slow function.
3231 * gtk_text_iter_forward_sentence_ends:
3232 * @iter: a #GtkTextIter
3233 * @count: number of sentences to move
3235 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3236 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3237 * negative, moves backward instead of forward.
3239 * Return value: %TRUE if @iter moved and is not the end iterator
3242 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3245 g_return_val_if_fail (iter != NULL, FALSE);
3251 return gtk_text_iter_backward_sentence_starts (iter, -count);
3253 if (!gtk_text_iter_forward_sentence_end (iter))
3259 if (!gtk_text_iter_forward_sentence_end (iter))
3264 return !gtk_text_iter_is_end (iter);
3268 * gtk_text_iter_backward_sentence_starts:
3269 * @iter: a #GtkTextIter
3270 * @count: number of sentences to move
3272 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3273 * or until it returns %FALSE. If @count is negative, moves forward
3274 * instead of backward.
3276 * Return value: %TRUE if @iter moved and is not the end iterator
3279 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3282 g_return_val_if_fail (iter != NULL, FALSE);
3285 return gtk_text_iter_forward_sentence_ends (iter, -count);
3287 if (!gtk_text_iter_backward_sentence_start (iter))
3293 if (!gtk_text_iter_backward_sentence_start (iter))
3298 return !gtk_text_iter_is_end (iter);
3302 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3307 gboolean already_moved_initially)
3309 if (!already_moved_initially)
3312 while (offset < (min_offset + len) &&
3313 !attrs[offset].is_cursor_position)
3316 *found_offset = offset;
3318 return offset < (min_offset + len);
3322 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3327 gboolean already_moved_initially)
3329 if (!already_moved_initially)
3332 while (offset > min_offset &&
3333 !attrs[offset].is_cursor_position)
3336 *found_offset = offset;
3338 return offset >= min_offset;
3342 is_cursor_pos_func (const PangoLogAttr *attrs,
3347 return attrs[offset].is_cursor_position;
3351 * gtk_text_iter_forward_cursor_position:
3352 * @iter: a #GtkTextIter
3354 * Moves @iter forward by a single cursor position. Cursor positions
3355 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3356 * surprisingly, there may not be a cursor position between all
3357 * characters. The most common example for European languages would be
3358 * a carriage return/newline sequence. For some Unicode characters,
3359 * the equivalent of say the letter "a" with an accent mark will be
3360 * represented as two characters, first the letter then a "combining
3361 * mark" that causes the accent to be rendered; so the cursor can't go
3362 * between those two characters. See also the #PangoLogAttr structure and
3363 * pango_break() function.
3365 * Return value: %TRUE if we moved and the new position is dereferenceable
3368 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3370 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3374 * gtk_text_iter_backward_cursor_position:
3375 * @iter: a #GtkTextIter
3377 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3379 * Return value: %TRUE if we moved and the new position is dereferenceable
3382 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3384 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3388 * gtk_text_iter_forward_cursor_positions:
3389 * @iter: a #GtkTextIter
3390 * @count: number of positions to move
3392 * Moves up to @count cursor positions. See
3393 * gtk_text_iter_forward_cursor_position() for details.
3395 * Return value: %TRUE if we moved and the new position is dereferenceable
3398 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3401 g_return_val_if_fail (iter != NULL, FALSE);
3403 FIX_OVERFLOWS (count);
3409 return gtk_text_iter_backward_cursor_positions (iter, -count);
3411 if (!gtk_text_iter_forward_cursor_position (iter))
3417 if (!gtk_text_iter_forward_cursor_position (iter))
3422 return !gtk_text_iter_is_end (iter);
3426 * gtk_text_iter_backward_cursor_positions:
3427 * @iter: a #GtkTextIter
3428 * @count: number of positions to move
3430 * Moves up to @count cursor positions. See
3431 * gtk_text_iter_forward_cursor_position() for details.
3433 * Return value: %TRUE if we moved and the new position is dereferenceable
3436 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3439 g_return_val_if_fail (iter != NULL, FALSE);
3441 FIX_OVERFLOWS (count);
3447 return gtk_text_iter_forward_cursor_positions (iter, -count);
3449 if (!gtk_text_iter_backward_cursor_position (iter))
3455 if (!gtk_text_iter_backward_cursor_position (iter))
3460 return !gtk_text_iter_is_end (iter);
3464 * gtk_text_iter_is_cursor_position:
3465 * @iter: a #GtkTextIter
3467 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3468 * pango_break() for details on what a cursor position is.
3470 * Return value: %TRUE if the cursor can be placed at @iter
3473 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3475 return test_log_attrs (iter, is_cursor_pos_func);
3479 * gtk_text_iter_set_line_offset:
3480 * @iter: a #GtkTextIter
3481 * @char_on_line: a character offset relative to the start of @iter's current line
3483 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3484 * (not byte) offset. The given character offset must be less than or
3485 * equal to the number of characters in the line; if equal, @iter
3486 * moves to the start of the next line. See
3487 * gtk_text_iter_set_line_index() if you have a byte index rather than
3488 * a character offset.
3492 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3495 GtkTextRealIter *real;
3498 g_return_if_fail (iter != NULL);
3500 real = gtk_text_iter_make_surreal (iter);
3505 check_invariants (iter);
3507 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3509 g_return_if_fail (char_on_line <= chars_in_line);
3511 if (char_on_line < chars_in_line)
3512 iter_set_from_char_offset (real, real->line, char_on_line);
3514 gtk_text_iter_forward_line (iter); /* set to start of next line */
3516 check_invariants (iter);
3520 * gtk_text_iter_set_line_index:
3521 * @iter: a #GtkTextIter
3522 * @byte_on_line: a byte index relative to the start of @iter's current line
3524 * Same as gtk_text_iter_set_line_offset(), but works with a
3525 * <emphasis>byte</emphasis> index. The given byte index must be at
3526 * the start of a character, it can't be in the middle of a UTF-8
3527 * encoded character.
3531 gtk_text_iter_set_line_index (GtkTextIter *iter,
3534 GtkTextRealIter *real;
3537 g_return_if_fail (iter != NULL);
3539 real = gtk_text_iter_make_surreal (iter);
3544 check_invariants (iter);
3546 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3548 g_return_if_fail (byte_on_line <= bytes_in_line);
3550 if (byte_on_line < bytes_in_line)
3551 iter_set_from_byte_offset (real, real->line, byte_on_line);
3553 gtk_text_iter_forward_line (iter);
3555 if (real->segment->type == >k_text_char_type &&
3556 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3557 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3558 "character; this will crash the text buffer. "
3559 "Byte indexes must refer to the start of a character.",
3560 G_STRLOC, byte_on_line);
3562 check_invariants (iter);
3567 * gtk_text_iter_set_visible_line_offset:
3568 * @iter: a #GtkTextIter
3569 * @char_on_line: a character offset
3571 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3572 * characters, i.e. text with a tag making it invisible is not
3573 * counted in the offset.
3576 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3579 gint chars_seen = 0;
3582 g_return_if_fail (iter != NULL);
3586 /* For now we use a ludicrously slow implementation */
3587 while (chars_seen < char_on_line)
3589 if (!_gtk_text_btree_char_is_invisible (&pos))
3592 if (!gtk_text_iter_forward_char (&pos))
3595 if (chars_seen == char_on_line)
3599 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3602 gtk_text_iter_forward_line (iter);
3606 bytes_in_char (GtkTextIter *iter)
3608 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3612 * gtk_text_iter_set_visible_line_index:
3613 * @iter: a #GtkTextIter
3614 * @byte_on_line: a byte index
3616 * Like gtk_text_iter_set_line_index(), but the index is in visible
3617 * bytes, i.e. text with a tag making it invisible is not counted
3621 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3624 gint bytes_seen = 0;
3627 g_return_if_fail (iter != NULL);
3631 /* For now we use a ludicrously slow implementation */
3632 while (bytes_seen < byte_on_line)
3634 if (!_gtk_text_btree_char_is_invisible (&pos))
3635 bytes_seen += bytes_in_char (&pos);
3637 if (!gtk_text_iter_forward_char (&pos))
3640 if (bytes_seen >= byte_on_line)
3644 if (bytes_seen > byte_on_line)
3645 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3646 "character; this will crash the text buffer. "
3647 "Byte indexes must refer to the start of a character.",
3648 G_STRLOC, byte_on_line);
3650 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3653 gtk_text_iter_forward_line (iter);
3657 * gtk_text_iter_set_line:
3658 * @iter: a #GtkTextIter
3659 * @line_number: line number (counted from 0)
3661 * Moves iterator @iter to the start of the line @line_number. If
3662 * @line_number is negative or larger than the number of lines in the
3663 * buffer, moves @iter to the start of the last line in the buffer.
3667 gtk_text_iter_set_line (GtkTextIter *iter,
3672 GtkTextRealIter *real;
3674 g_return_if_fail (iter != NULL);
3676 real = gtk_text_iter_make_surreal (iter);
3681 check_invariants (iter);
3683 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3685 iter_set_from_char_offset (real, line, 0);
3687 /* We might as well cache this, since we know it. */
3688 real->cached_line_number = real_line;
3690 check_invariants (iter);
3694 * gtk_text_iter_set_offset:
3695 * @iter: a #GtkTextIter
3696 * @char_offset: a character number
3698 * Sets @iter to point to @char_offset. @char_offset counts from the start
3699 * of the entire text buffer, starting with 0.
3702 gtk_text_iter_set_offset (GtkTextIter *iter,
3706 GtkTextRealIter *real;
3708 gint real_char_index;
3710 g_return_if_fail (iter != NULL);
3712 real = gtk_text_iter_make_surreal (iter);
3717 check_invariants (iter);
3719 if (real->cached_char_index >= 0 &&
3720 real->cached_char_index == char_offset)
3723 line = _gtk_text_btree_get_line_at_char (real->tree,
3728 iter_set_from_char_offset (real, line, real_char_index - line_start);
3730 /* Go ahead and cache this since we have it. */
3731 real->cached_char_index = real_char_index;
3733 check_invariants (iter);
3737 * gtk_text_iter_forward_to_end:
3738 * @iter: a #GtkTextIter
3740 * Moves @iter forward to the "end iterator," which points one past the last
3741 * valid character in the buffer. gtk_text_iter_get_char() called on the
3742 * end iterator returns 0, which is convenient for writing loops.
3745 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3747 GtkTextBuffer *buffer;
3748 GtkTextRealIter *real;
3750 g_return_if_fail (iter != NULL);
3752 real = gtk_text_iter_make_surreal (iter);
3757 buffer = _gtk_text_btree_get_buffer (real->tree);
3759 gtk_text_buffer_get_end_iter (buffer, iter);
3762 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3763 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3764 * If all else fails we could cache the para delimiter pos in the iter.
3765 * I think forward_to_line_end() actually gets called fairly often.
3768 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3773 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3774 _gtk_text_iter_get_btree (&end)))
3776 gtk_text_iter_forward_to_end (&end);
3780 /* if we aren't on the last line, go forward to start of next line, then scan
3781 * back for the delimiters on the previous line
3783 gtk_text_iter_forward_line (&end);
3784 gtk_text_iter_backward_char (&end);
3785 while (!gtk_text_iter_ends_line (&end))
3786 gtk_text_iter_backward_char (&end);
3789 return gtk_text_iter_get_line_offset (&end);
3793 * gtk_text_iter_forward_to_line_end:
3794 * @iter: a #GtkTextIter
3796 * Moves the iterator to point to the paragraph delimiter characters,
3797 * which will be either a newline, a carriage return, a carriage
3798 * return/newline in sequence, or the Unicode paragraph separator
3799 * character. If the iterator is already at the paragraph delimiter
3800 * characters, moves to the paragraph delimiter characters for the
3801 * next line. If @iter is on the last line in the buffer, which does
3802 * not end in paragraph delimiters, moves to the end iterator (end of
3803 * the last line), and returns %FALSE.
3805 * Return value: %TRUE if we moved and the new location is not the end iterator
3808 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3810 gint current_offset;
3814 g_return_val_if_fail (iter != NULL, FALSE);
3816 current_offset = gtk_text_iter_get_line_offset (iter);
3817 new_offset = find_paragraph_delimiter_for_line (iter);
3819 if (current_offset < new_offset)
3821 /* Move to end of this line. */
3822 gtk_text_iter_set_line_offset (iter, new_offset);
3823 return !gtk_text_iter_is_end (iter);
3827 /* Move to end of next line. */
3828 if (gtk_text_iter_forward_line (iter))
3830 /* We don't want to move past all
3833 if (!gtk_text_iter_ends_line (iter))
3834 gtk_text_iter_forward_to_line_end (iter);
3835 return !gtk_text_iter_is_end (iter);
3843 * gtk_text_iter_forward_to_tag_toggle:
3844 * @iter: a #GtkTextIter
3845 * @tag: a #GtkTextTag, or %NULL
3847 * Moves forward to the next toggle (on or off) of the
3848 * #GtkTextTag @tag, or to the next toggle of any tag if
3849 * @tag is %NULL. If no matching tag toggles are found,
3850 * returns %FALSE, otherwise %TRUE. Does not return toggles
3851 * located at @iter, only toggles after @iter. Sets @iter to
3852 * the location of the toggle, or to the end of the buffer
3853 * if no toggle is found.
3855 * Return value: whether we found a tag toggle after @iter
3858 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3861 GtkTextLine *next_line;
3862 GtkTextLine *current_line;
3863 GtkTextRealIter *real;
3865 g_return_val_if_fail (iter != NULL, FALSE);
3867 real = gtk_text_iter_make_real (iter);
3872 check_invariants (iter);
3874 current_line = real->line;
3875 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3878 while (_gtk_text_iter_forward_indexable_segment (iter))
3880 /* If we went forward to a line that couldn't contain a toggle
3881 for the tag, then skip forward to a line that could contain
3882 it. This potentially skips huge hunks of the tree, so we
3883 aren't a purely linear search. */
3884 if (real->line != current_line)
3886 if (next_line == NULL)
3888 /* End of search. Set to end of buffer. */
3889 _gtk_text_btree_get_end_iter (real->tree, iter);
3893 if (real->line != next_line)
3894 iter_set_from_byte_offset (real, next_line, 0);
3896 current_line = real->line;
3897 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3902 if (gtk_text_iter_toggles_tag (iter, tag))
3904 /* If there's a toggle here, it isn't indexable so
3905 any_segment can't be the indexable segment. */
3906 g_assert (real->any_segment != real->segment);
3911 /* Check end iterator for tags */
3912 if (gtk_text_iter_toggles_tag (iter, tag))
3914 /* If there's a toggle here, it isn't indexable so
3915 any_segment can't be the indexable segment. */
3916 g_assert (real->any_segment != real->segment);
3920 /* Reached end of buffer */
3925 * gtk_text_iter_backward_to_tag_toggle:
3926 * @iter: a #GtkTextIter
3927 * @tag: a #GtkTextTag, or %NULL
3929 * Moves backward to the next toggle (on or off) of the
3930 * #GtkTextTag @tag, or to the next toggle of any tag if
3931 * @tag is %NULL. If no matching tag toggles are found,
3932 * returns %FALSE, otherwise %TRUE. Does not return toggles
3933 * located at @iter, only toggles before @iter. Sets @iter
3934 * to the location of the toggle, or the start of the buffer
3935 * if no toggle is found.
3937 * Return value: whether we found a tag toggle before @iter
3940 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3943 GtkTextLine *prev_line;
3944 GtkTextLine *current_line;
3945 GtkTextRealIter *real;
3947 g_return_val_if_fail (iter != NULL, FALSE);
3949 real = gtk_text_iter_make_real (iter);
3954 check_invariants (iter);
3956 current_line = real->line;
3957 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3961 /* If we're at segment start, go to the previous segment;
3962 * if mid-segment, snap to start of current segment.
3964 if (is_segment_start (real))
3966 if (!_gtk_text_iter_backward_indexable_segment (iter))
3971 ensure_char_offsets (real);
3973 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3979 /* If we went backward to a line that couldn't contain a toggle
3980 * for the tag, then skip backward further to a line that
3981 * could contain it. This potentially skips huge hunks of the
3982 * tree, so we aren't a purely linear search.
3984 if (real->line != current_line)
3986 if (prev_line == NULL)
3988 /* End of search. Set to start of buffer. */
3989 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3993 if (real->line != prev_line)
3995 /* Set to last segment in prev_line (could do this
3998 iter_set_from_byte_offset (real, prev_line, 0);
4000 while (!at_last_indexable_segment (real))
4001 _gtk_text_iter_forward_indexable_segment (iter);
4004 current_line = real->line;
4005 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4010 if (gtk_text_iter_toggles_tag (iter, tag))
4012 /* If there's a toggle here, it isn't indexable so
4013 * any_segment can't be the indexable segment.
4015 g_assert (real->any_segment != real->segment);
4019 while (_gtk_text_iter_backward_indexable_segment (iter));
4021 /* Reached front of buffer */
4026 matches_pred (GtkTextIter *iter,
4027 GtkTextCharPredicate pred,
4032 ch = gtk_text_iter_get_char (iter);
4034 return (*pred) (ch, user_data);
4038 * gtk_text_iter_forward_find_char:
4039 * @iter: a #GtkTextIter
4040 * @pred: a function to be called on each character
4041 * @user_data: user data for @pred
4042 * @limit: search limit, or %NULL for none
4044 * Advances @iter, calling @pred on each character. If
4045 * @pred returns %TRUE, returns %TRUE and stops scanning.
4046 * If @pred never returns %TRUE, @iter is set to @limit if
4047 * @limit is non-%NULL, otherwise to the end iterator.
4049 * Return value: whether a match was found
4052 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4053 GtkTextCharPredicate pred,
4055 const GtkTextIter *limit)
4057 g_return_val_if_fail (iter != NULL, FALSE);
4058 g_return_val_if_fail (pred != NULL, FALSE);
4061 gtk_text_iter_compare (iter, limit) >= 0)
4064 while ((limit == NULL ||
4065 !gtk_text_iter_equal (limit, iter)) &&
4066 gtk_text_iter_forward_char (iter))
4068 if (matches_pred (iter, pred, user_data))
4076 * gtk_text_iter_backward_find_char:
4077 * @iter: a #GtkTextIter
4078 * @pred: function to be called on each character
4079 * @user_data: user data for @pred
4080 * @limit: search limit, or %NULL for none
4082 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4084 * Return value: whether a match was found
4087 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4088 GtkTextCharPredicate pred,
4090 const GtkTextIter *limit)
4092 g_return_val_if_fail (iter != NULL, FALSE);
4093 g_return_val_if_fail (pred != NULL, FALSE);
4096 gtk_text_iter_compare (iter, limit) <= 0)
4099 while ((limit == NULL ||
4100 !gtk_text_iter_equal (limit, iter)) &&
4101 gtk_text_iter_backward_char (iter))
4103 if (matches_pred (iter, pred, user_data))
4111 forward_chars_with_skipping (GtkTextIter *iter,
4113 gboolean skip_invisible,
4114 gboolean skip_nontext)
4119 g_return_if_fail (count >= 0);
4125 gboolean ignored = FALSE;
4128 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4133 _gtk_text_btree_char_is_invisible (iter))
4136 gtk_text_iter_forward_char (iter);
4144 lines_match (const GtkTextIter *start,
4145 const gchar **lines,
4146 gboolean visible_only,
4148 GtkTextIter *match_start,
4149 GtkTextIter *match_end)
4156 if (*lines == NULL || **lines == '\0')
4159 *match_start = *start;
4162 *match_end = *start;
4167 gtk_text_iter_forward_line (&next);
4169 /* No more text in buffer, but *lines is nonempty */
4170 if (gtk_text_iter_equal (start, &next))
4178 line_text = gtk_text_iter_get_visible_slice (start, &next);
4180 line_text = gtk_text_iter_get_slice (start, &next);
4185 line_text = gtk_text_iter_get_visible_text (start, &next);
4187 line_text = gtk_text_iter_get_text (start, &next);
4190 if (match_start) /* if this is the first line we're matching */
4191 found = strstr (line_text, *lines);
4194 /* If it's not the first line, we have to match from the
4195 * start of the line.
4197 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4209 /* Get offset to start of search string */
4210 offset = g_utf8_strlen (line_text, found - line_text);
4214 /* If match start needs to be returned, set it to the
4215 * start of the search string.
4219 *match_start = next;
4221 forward_chars_with_skipping (match_start, offset,
4222 visible_only, !slice);
4225 /* Go to end of search string */
4226 offset += g_utf8_strlen (*lines, -1);
4228 forward_chars_with_skipping (&next, offset,
4229 visible_only, !slice);
4238 /* pass NULL for match_start, since we don't need to find the
4241 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4244 /* strsplit () that retains the delimiter as part of the string. */
4246 strbreakup (const char *string,
4247 const char *delimiter,
4250 GSList *string_list = NULL, *slist;
4251 gchar **str_array, *s;
4254 g_return_val_if_fail (string != NULL, NULL);
4255 g_return_val_if_fail (delimiter != NULL, NULL);
4258 max_tokens = G_MAXINT;
4260 s = strstr (string, delimiter);
4263 guint delimiter_len = strlen (delimiter);
4270 len = s - string + delimiter_len;
4271 new_string = g_new (gchar, len + 1);
4272 strncpy (new_string, string, len);
4273 new_string[len] = 0;
4274 string_list = g_slist_prepend (string_list, new_string);
4276 string = s + delimiter_len;
4277 s = strstr (string, delimiter);
4279 while (--max_tokens && s);
4284 string_list = g_slist_prepend (string_list, g_strdup (string));
4287 str_array = g_new (gchar*, n);
4291 str_array[i--] = NULL;
4292 for (slist = string_list; slist; slist = slist->next)
4293 str_array[i--] = slist->data;
4295 g_slist_free (string_list);
4301 * gtk_text_iter_forward_search:
4302 * @iter: start of search
4303 * @str: a search string
4304 * @flags: flags affecting how the search is done
4305 * @match_start: return location for start of match, or %NULL
4306 * @match_end: return location for end of match, or %NULL
4307 * @limit: bound for the search, or %NULL for the end of the buffer
4309 * Searches forward for @str. Any match is returned as the range
4310 * @match_start, @match_end. The search will not continue past
4311 * @limit. Note that a search is a linear or O(n) operation, so you
4312 * may wish to use @limit to avoid locking up your UI on large
4315 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4316 * have invisible text interspersed in @str. i.e. @str will be a
4317 * possibly-noncontiguous subsequence of the matched range. similarly,
4318 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4319 * pixbufs or child widgets mixed inside the matched range. If these
4320 * flags are not given, the match must be exact; the special 0xFFFC
4321 * character in @str will match embedded pixbufs or child widgets.
4323 * Return value: whether a match was found
4326 gtk_text_iter_forward_search (const GtkTextIter *iter,
4328 GtkTextSearchFlags flags,
4329 GtkTextIter *match_start,
4330 GtkTextIter *match_end,
4331 const GtkTextIter *limit)
4333 gchar **lines = NULL;
4335 gboolean retval = FALSE;
4337 gboolean visible_only;
4340 g_return_val_if_fail (iter != NULL, FALSE);
4341 g_return_val_if_fail (str != NULL, FALSE);
4344 gtk_text_iter_compare (iter, limit) >= 0)
4349 /* If we can move one char, return the empty string there */
4352 if (gtk_text_iter_forward_char (&match))
4355 gtk_text_iter_equal (&match, limit))
4359 *match_start = match;
4368 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4369 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4371 /* locate all lines */
4373 lines = strbreakup (str, "\n", -1);
4379 /* This loop has an inefficient worst-case, where
4380 * gtk_text_iter_get_text () is called repeatedly on
4386 gtk_text_iter_compare (&search, limit) >= 0)
4389 if (lines_match (&search, (const gchar**)lines,
4390 visible_only, slice, &match, &end))
4392 if (limit == NULL ||
4394 gtk_text_iter_compare (&end, limit) < 0))
4399 *match_start = match;
4408 while (gtk_text_iter_forward_line (&search));
4410 g_strfreev ((gchar**)lines);
4416 vectors_equal_ignoring_trailing (gchar **vec1,
4419 /* Ignores trailing chars in vec2's last line */
4428 if (strcmp (*i1, *i2) != 0)
4430 if (*(i2 + 1) == NULL) /* if this is the last line */
4432 gint len1 = strlen (*i1);
4433 gint len2 = strlen (*i2);
4436 strncmp (*i1, *i2, len1) == 0)
4438 /* We matched ignoring the trailing stuff in vec2 */
4463 typedef struct _LinesWindow LinesWindow;
4469 GtkTextIter first_line_start;
4470 GtkTextIter first_line_end;
4472 gboolean visible_only;
4476 lines_window_init (LinesWindow *win,
4477 const GtkTextIter *start)
4480 GtkTextIter line_start;
4481 GtkTextIter line_end;
4483 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4486 if (gtk_text_iter_is_start (start) ||
4487 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4489 /* Already at the end, or not enough lines to match */
4490 win->lines = g_new0 (gchar*, 1);
4495 line_start = *start;
4498 /* Move to start iter to start of line */
4499 gtk_text_iter_set_line_offset (&line_start, 0);
4501 if (gtk_text_iter_equal (&line_start, &line_end))
4503 /* we were already at the start; so go back one line */
4504 gtk_text_iter_backward_line (&line_start);
4507 win->first_line_start = line_start;
4508 win->first_line_end = line_end;
4510 win->lines = g_new0 (gchar*, win->n_lines + 1);
4512 i = win->n_lines - 1;
4519 if (win->visible_only)
4520 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4522 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4526 if (win->visible_only)
4527 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4529 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4532 win->lines[i] = line_text;
4534 line_end = line_start;
4535 gtk_text_iter_backward_line (&line_start);
4542 lines_window_back (LinesWindow *win)
4544 GtkTextIter new_start;
4547 new_start = win->first_line_start;
4549 if (!gtk_text_iter_backward_line (&new_start))
4553 win->first_line_start = new_start;
4554 win->first_line_end = new_start;
4556 gtk_text_iter_forward_line (&win->first_line_end);
4561 if (win->visible_only)
4562 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4563 &win->first_line_end);
4565 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4566 &win->first_line_end);
4570 if (win->visible_only)
4571 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4572 &win->first_line_end);
4574 line_text = gtk_text_iter_get_text (&win->first_line_start,
4575 &win->first_line_end);
4578 /* Move lines to make room for first line. */
4579 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4581 *win->lines = line_text;
4583 /* Free old last line and NULL-terminate */
4584 g_free (win->lines[win->n_lines]);
4585 win->lines[win->n_lines] = NULL;
4591 lines_window_free (LinesWindow *win)
4593 g_strfreev (win->lines);
4597 my_strrstr (const gchar *haystack,
4598 const gchar *needle)
4600 /* FIXME GLib should have a nice implementation in it, this
4604 gint haystack_len = strlen (haystack);
4605 gint needle_len = strlen (needle);
4606 const gchar *needle_end = needle + needle_len;
4607 const gchar *haystack_rend = haystack - 1;
4608 const gchar *needle_rend = needle - 1;
4611 p = haystack + haystack_len;
4612 while (p != haystack)
4614 const gchar *n = needle_end - 1;
4615 const gchar *s = p - 1;
4616 while (s != haystack_rend &&
4624 if (n == needle_rend)
4634 * gtk_text_iter_backward_search:
4635 * @iter: a #GtkTextIter where the search begins
4636 * @str: search string
4637 * @flags: bitmask of flags affecting the search
4638 * @match_start: return location for start of match, or %NULL
4639 * @match_end: return location for end of match, or %NULL
4640 * @limit: location of last possible @match_start, or %NULL for start of buffer
4642 * Same as gtk_text_iter_forward_search(), but moves backward.
4644 * Return value: whether a match was found
4647 gtk_text_iter_backward_search (const GtkTextIter *iter,
4649 GtkTextSearchFlags flags,
4650 GtkTextIter *match_start,
4651 GtkTextIter *match_end,
4652 const GtkTextIter *limit)
4654 gchar **lines = NULL;
4658 gboolean retval = FALSE;
4659 gboolean visible_only;
4662 g_return_val_if_fail (iter != NULL, FALSE);
4663 g_return_val_if_fail (str != NULL, FALSE);
4666 gtk_text_iter_compare (limit, iter) > 0)
4671 /* If we can move one char, return the empty string there */
4672 GtkTextIter match = *iter;
4674 if (limit && gtk_text_iter_equal (limit, &match))
4677 if (gtk_text_iter_backward_char (&match))
4680 *match_start = match;
4689 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4690 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4692 /* locate all lines */
4694 lines = strbreakup (str, "\n", -1);
4704 win.n_lines = n_lines;
4706 win.visible_only = visible_only;
4708 lines_window_init (&win, iter);
4710 if (*win.lines == NULL)
4715 gchar *first_line_match;
4718 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4720 /* We're now before the search limit, abort. */
4724 /* If there are multiple lines, the first line will
4725 * end in '\n', so this will only match at the
4726 * end of the first line, which is correct.
4728 first_line_match = my_strrstr (*win.lines, *lines);
4730 if (first_line_match &&
4731 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4736 GtkTextIter start_tmp;
4738 /* Offset to start of search string */
4739 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4741 next = win.first_line_start;
4743 forward_chars_with_skipping (&start_tmp, offset,
4744 visible_only, !slice);
4747 gtk_text_iter_compare (limit, &start_tmp) > 0)
4748 goto out; /* match was bogus */
4751 *match_start = start_tmp;
4753 /* Go to end of search string */
4757 offset += g_utf8_strlen (*l, -1);
4761 forward_chars_with_skipping (&next, offset,
4762 visible_only, !slice);
4771 while (lines_window_back (&win));
4774 lines_window_free (&win);
4785 * gtk_text_iter_equal:
4786 * @lhs: a #GtkTextIter
4787 * @rhs: another #GtkTextIter
4789 * Tests whether two iterators are equal, using the fastest possible
4790 * mechanism. This function is very fast; you can expect it to perform
4791 * better than e.g. getting the character offset for each iterator and
4792 * comparing the offsets yourself. Also, it's a bit faster than
4793 * gtk_text_iter_compare().
4795 * Return value: %TRUE if the iterators point to the same place in the buffer
4798 gtk_text_iter_equal (const GtkTextIter *lhs,
4799 const GtkTextIter *rhs)
4801 GtkTextRealIter *real_lhs;
4802 GtkTextRealIter *real_rhs;
4804 real_lhs = (GtkTextRealIter*)lhs;
4805 real_rhs = (GtkTextRealIter*)rhs;
4807 check_invariants (lhs);
4808 check_invariants (rhs);
4810 if (real_lhs->line != real_rhs->line)
4812 else if (real_lhs->line_byte_offset >= 0 &&
4813 real_rhs->line_byte_offset >= 0)
4814 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4817 /* the ensure_char_offsets () calls do nothing if the char offsets
4818 are already up-to-date. */
4819 ensure_char_offsets (real_lhs);
4820 ensure_char_offsets (real_rhs);
4821 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4826 * gtk_text_iter_compare:
4827 * @lhs: a #GtkTextIter
4828 * @rhs: another #GtkTextIter
4830 * A qsort()-style function that returns negative if @lhs is less than
4831 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4832 * Ordering is in character offset order, i.e. the first character in the buffer
4833 * is less than the second character in the buffer.
4835 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4838 gtk_text_iter_compare (const GtkTextIter *lhs,
4839 const GtkTextIter *rhs)
4841 GtkTextRealIter *real_lhs;
4842 GtkTextRealIter *real_rhs;
4844 real_lhs = gtk_text_iter_make_surreal (lhs);
4845 real_rhs = gtk_text_iter_make_surreal (rhs);
4847 if (real_lhs == NULL ||
4849 return -1; /* why not */
4851 check_invariants (lhs);
4852 check_invariants (rhs);
4854 if (real_lhs->line == real_rhs->line)
4856 gint left_index, right_index;
4858 if (real_lhs->line_byte_offset >= 0 &&
4859 real_rhs->line_byte_offset >= 0)
4861 left_index = real_lhs->line_byte_offset;
4862 right_index = real_rhs->line_byte_offset;
4866 /* the ensure_char_offsets () calls do nothing if
4867 the offsets are already up-to-date. */
4868 ensure_char_offsets (real_lhs);
4869 ensure_char_offsets (real_rhs);
4870 left_index = real_lhs->line_char_offset;
4871 right_index = real_rhs->line_char_offset;
4874 if (left_index < right_index)
4876 else if (left_index > right_index)
4885 line1 = gtk_text_iter_get_line (lhs);
4886 line2 = gtk_text_iter_get_line (rhs);
4889 else if (line1 > line2)
4897 * gtk_text_iter_in_range:
4898 * @iter: a #GtkTextIter
4899 * @start: start of range
4900 * @end: end of range
4902 * Checks whether @iter falls in the range [@start, @end).
4903 * @start and @end must be in ascending order.
4905 * Return value: %TRUE if @iter is in the range
4908 gtk_text_iter_in_range (const GtkTextIter *iter,
4909 const GtkTextIter *start,
4910 const GtkTextIter *end)
4912 g_return_val_if_fail (iter != NULL, FALSE);
4913 g_return_val_if_fail (start != NULL, FALSE);
4914 g_return_val_if_fail (end != NULL, FALSE);
4915 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4917 return gtk_text_iter_compare (iter, start) >= 0 &&
4918 gtk_text_iter_compare (iter, end) < 0;
4922 * gtk_text_iter_order:
4923 * @first: a #GtkTextIter
4924 * @second: another #GtkTextIter
4926 * Swaps the value of @first and @second if @second comes before
4927 * @first in the buffer. That is, ensures that @first and @second are
4928 * in sequence. Most text buffer functions that take a range call this
4929 * automatically on your behalf, so there's no real reason to call it yourself
4930 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4931 * that expect a pre-sorted range.
4935 gtk_text_iter_order (GtkTextIter *first,
4936 GtkTextIter *second)
4938 g_return_if_fail (first != NULL);
4939 g_return_if_fail (second != NULL);
4941 if (gtk_text_iter_compare (first, second) > 0)
4952 * Init iterators from the BTree
4956 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4960 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4961 gint real_char_index;
4965 g_return_if_fail (iter != NULL);
4966 g_return_if_fail (tree != NULL);
4968 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4969 &line_start, &real_char_index);
4971 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4973 real->cached_char_index = real_char_index;
4975 check_invariants (iter);
4979 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4984 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4988 g_return_if_fail (iter != NULL);
4989 g_return_if_fail (tree != NULL);
4991 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
4993 iter_init_from_char_offset (iter, tree, line, char_on_line);
4995 /* We might as well cache this, since we know it. */
4996 real->cached_line_number = real_line;
4998 check_invariants (iter);
5002 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5007 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5011 g_return_if_fail (iter != NULL);
5012 g_return_if_fail (tree != NULL);
5014 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5016 iter_init_from_byte_offset (iter, tree, line, byte_index);
5018 /* We might as well cache this, since we know it. */
5019 real->cached_line_number = real_line;
5021 check_invariants (iter);
5025 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5030 g_return_if_fail (iter != NULL);
5031 g_return_if_fail (tree != NULL);
5032 g_return_if_fail (line != NULL);
5034 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5036 check_invariants (iter);
5040 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5046 g_return_val_if_fail (iter != NULL, FALSE);
5047 g_return_val_if_fail (tree != NULL, FALSE);
5049 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5053 /* Set iter to last in tree */
5054 _gtk_text_btree_get_end_iter (tree, iter);
5055 check_invariants (iter);
5060 iter_init_from_byte_offset (iter, tree, line, 0);
5061 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5062 check_invariants (iter);
5068 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5072 g_return_val_if_fail (iter != NULL, FALSE);
5073 g_return_val_if_fail (tree != NULL, FALSE);
5075 _gtk_text_btree_get_end_iter (tree, iter);
5076 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5077 check_invariants (iter);
5083 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5085 const gchar *mark_name)
5089 g_return_val_if_fail (iter != NULL, FALSE);
5090 g_return_val_if_fail (tree != NULL, FALSE);
5092 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5098 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5099 check_invariants (iter);
5105 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5109 GtkTextLineSegment *seg;
5111 g_return_if_fail (iter != NULL);
5112 g_return_if_fail (tree != NULL);
5113 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5115 seg = mark->segment;
5117 iter_init_from_segment (iter, tree,
5118 seg->body.mark.line, seg);
5119 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5120 check_invariants (iter);
5124 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5126 GtkTextChildAnchor *anchor)
5128 GtkTextLineSegment *seg;
5130 g_return_if_fail (iter != NULL);
5131 g_return_if_fail (tree != NULL);
5132 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5134 seg = anchor->segment;
5136 iter_init_from_segment (iter, tree,
5137 seg->body.child.line, seg);
5138 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5139 check_invariants (iter);
5143 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5146 g_return_if_fail (iter != NULL);
5147 g_return_if_fail (tree != NULL);
5149 _gtk_text_btree_get_iter_at_char (tree,
5151 _gtk_text_btree_char_count (tree));
5152 check_invariants (iter);
5156 _gtk_text_iter_check (const GtkTextIter *iter)
5158 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5159 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5160 GtkTextLineSegment *byte_segment = NULL;
5161 GtkTextLineSegment *byte_any_segment = NULL;
5162 GtkTextLineSegment *char_segment = NULL;
5163 GtkTextLineSegment *char_any_segment = NULL;
5164 gboolean segments_updated;
5166 /* This function checks our class invariants for the Iter class. */
5168 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5170 if (real->chars_changed_stamp !=
5171 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5172 g_error ("iterator check failed: invalid iterator");
5174 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5175 g_error ("iterator check failed: both char and byte offsets are invalid");
5177 segments_updated = (real->segments_changed_stamp ==
5178 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5181 printf ("checking iter, segments %s updated, byte %d char %d\n",
5182 segments_updated ? "are" : "aren't",
5183 real->line_byte_offset,
5184 real->line_char_offset);
5187 if (segments_updated)
5189 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5190 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5192 if (real->segment->char_count == 0)
5193 g_error ("iterator check failed: segment is not indexable.");
5195 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5196 g_error ("segment char offset is not properly up-to-date");
5198 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5199 g_error ("segment byte offset is not properly up-to-date");
5201 if (real->segment_byte_offset >= 0 &&
5202 real->segment_byte_offset >= real->segment->byte_count)
5203 g_error ("segment byte offset is too large.");
5205 if (real->segment_char_offset >= 0 &&
5206 real->segment_char_offset >= real->segment->char_count)
5207 g_error ("segment char offset is too large.");
5210 if (real->line_byte_offset >= 0)
5212 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5213 &byte_segment, &byte_any_segment,
5214 &seg_byte_offset, &line_byte_offset);
5216 if (line_byte_offset != real->line_byte_offset)
5217 g_error ("wrong byte offset was stored in iterator");
5219 if (segments_updated)
5221 if (real->segment != byte_segment)
5222 g_error ("wrong segment was stored in iterator");
5224 if (real->any_segment != byte_any_segment)
5225 g_error ("wrong any_segment was stored in iterator");
5227 if (seg_byte_offset != real->segment_byte_offset)
5228 g_error ("wrong segment byte offset was stored in iterator");
5230 if (byte_segment->type == >k_text_char_type)
5233 p = byte_segment->body.chars + seg_byte_offset;
5235 if (!gtk_text_byte_begins_utf8_char (p))
5236 g_error ("broken iterator byte index pointed into the middle of a character");
5241 if (real->line_char_offset >= 0)
5243 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5244 &char_segment, &char_any_segment,
5245 &seg_char_offset, &line_char_offset);
5247 if (line_char_offset != real->line_char_offset)
5248 g_error ("wrong char offset was stored in iterator");
5250 if (segments_updated)
5252 if (real->segment != char_segment)
5253 g_error ("wrong segment was stored in iterator");
5255 if (real->any_segment != char_any_segment)
5256 g_error ("wrong any_segment was stored in iterator");
5258 if (seg_char_offset != real->segment_char_offset)
5259 g_error ("wrong segment char offset was stored in iterator");
5261 if (char_segment->type == >k_text_char_type)
5264 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5267 /* hmm, not likely to happen eh */
5268 if (!gtk_text_byte_begins_utf8_char (p))
5269 g_error ("broken iterator char offset pointed into the middle of a character");
5274 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5276 if (byte_segment != char_segment)
5277 g_error ("char and byte offsets did not point to the same segment");
5279 if (byte_any_segment != char_any_segment)
5280 g_error ("char and byte offsets did not point to the same any segment");
5282 /* Make sure the segment offsets are equivalent, if it's a char
5284 if (char_segment->type == >k_text_char_type)
5286 gint byte_offset = 0;
5287 gint char_offset = 0;
5288 while (char_offset < seg_char_offset)
5290 const char * start = char_segment->body.chars + byte_offset;
5291 byte_offset += g_utf8_next_char (start) - start;
5295 if (byte_offset != seg_byte_offset)
5296 g_error ("byte offset did not correspond to char offset");
5299 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5301 if (char_offset != seg_char_offset)
5302 g_error ("char offset did not correspond to byte offset");
5304 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5305 g_error ("byte index for iterator does not index the start of a character");
5309 if (real->cached_line_number >= 0)
5313 should_be = _gtk_text_line_get_number (real->line);
5314 if (real->cached_line_number != should_be)
5315 g_error ("wrong line number was cached");
5318 if (real->cached_char_index >= 0)
5320 if (real->line_char_offset >= 0) /* only way we can check it
5321 efficiently, not a real
5326 char_index = _gtk_text_line_char_index (real->line);
5327 char_index += real->line_char_offset;
5329 if (real->cached_char_index != char_index)
5330 g_error ("wrong char index was cached");
5334 if (_gtk_text_line_is_last (real->line, real->tree))
5335 g_error ("Iterator was on last line (past the end iterator)");