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
30 #include "gtktextiter.h"
31 #include "gtktextbtree.h"
32 #include "gtktextiterprivate.h"
36 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
38 typedef struct _GtkTextRealIter GtkTextRealIter;
40 struct _GtkTextRealIter
42 /* Always-valid information */
45 /* At least one of these is always valid;
46 if invalid, they are -1.
48 If the line byte offset is valid, so is the segment byte offset;
49 and ditto for char offsets. */
50 gint line_byte_offset;
51 gint line_char_offset;
52 /* These two are valid if >= 0 */
53 gint cached_char_index;
54 gint cached_line_number;
55 /* Stamps to detect the buffer changing under us */
56 gint chars_changed_stamp;
57 gint segments_changed_stamp;
58 /* Valid if the segments_changed_stamp is up-to-date */
59 GtkTextLineSegment *segment; /* indexable segment we index */
60 GtkTextLineSegment *any_segment; /* first segment in our location,
61 maybe same as "segment" */
62 /* One of these will always be valid if segments_changed_stamp is
63 up-to-date. If invalid, they are -1.
65 If the line byte offset is valid, so is the segment byte offset;
66 and ditto for char offsets. */
67 gint segment_byte_offset;
68 gint segment_char_offset;
75 /* These "set" functions should not assume any fields
76 other than the char stamp and the tree are valid.
79 iter_set_common (GtkTextRealIter *iter,
82 /* Update segments stamp */
83 iter->segments_changed_stamp =
84 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
88 iter->line_byte_offset = -1;
89 iter->line_char_offset = -1;
90 iter->segment_byte_offset = -1;
91 iter->segment_char_offset = -1;
92 iter->cached_char_index = -1;
93 iter->cached_line_number = -1;
97 iter_set_from_byte_offset (GtkTextRealIter *iter,
101 iter_set_common (iter, line);
103 if (!_gtk_text_line_byte_locate (iter->line,
107 &iter->segment_byte_offset,
108 &iter->line_byte_offset))
109 g_error ("Byte index %d is off the end of the line",
114 iter_set_from_char_offset (GtkTextRealIter *iter,
118 iter_set_common (iter, line);
120 if (!_gtk_text_line_char_locate (iter->line,
124 &iter->segment_char_offset,
125 &iter->line_char_offset))
126 g_error ("Char offset %d is off the end of the line",
131 iter_set_from_segment (GtkTextRealIter *iter,
133 GtkTextLineSegment *segment)
135 GtkTextLineSegment *seg;
138 /* This could theoretically be optimized by computing all the iter
139 fields in this same loop, but I'm skipping it for now. */
141 seg = line->segments;
142 while (seg != segment)
144 byte_offset += seg->byte_count;
148 iter_set_from_byte_offset (iter, line, byte_offset);
151 /* This function ensures that the segment-dependent information is
152 truly computed lazily; often we don't need to do the full make_real
153 work. This ensures the btree and line are valid, but doesn't
154 update the segments. */
155 static GtkTextRealIter*
156 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
158 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
160 if (iter->chars_changed_stamp !=
161 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
163 g_warning ("Invalid text buffer iterator: either the iterator "
164 "is uninitialized, or the characters/pixbufs/widgets "
165 "in the buffer have been modified since the iterator "
166 "was created.\nYou must use marks, character numbers, "
167 "or line numbers to preserve a position across buffer "
168 "modifications.\nYou can apply tags and insert marks "
169 "without invalidating your iterators,\n"
170 "but any mutation that affects 'indexable' buffer contents "
171 "(contents that can be referred to by character offset)\n"
172 "will invalidate all outstanding iterators");
176 /* We don't update the segments information since we are becoming
177 only surreal. However we do invalidate the segments information
178 if appropriate, to be sure we segfault if we try to use it and we
179 should have used make_real. */
181 if (iter->segments_changed_stamp !=
182 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
184 iter->segment = NULL;
185 iter->any_segment = NULL;
186 /* set to segfault-causing values. */
187 iter->segment_byte_offset = -10000;
188 iter->segment_char_offset = -10000;
194 static GtkTextRealIter*
195 gtk_text_iter_make_real (const GtkTextIter *_iter)
197 GtkTextRealIter *iter;
199 iter = gtk_text_iter_make_surreal (_iter);
201 if (iter->segments_changed_stamp !=
202 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
204 if (iter->line_byte_offset >= 0)
206 iter_set_from_byte_offset (iter,
208 iter->line_byte_offset);
212 g_assert (iter->line_char_offset >= 0);
214 iter_set_from_char_offset (iter,
216 iter->line_char_offset);
220 g_assert (iter->segment != NULL);
221 g_assert (iter->any_segment != NULL);
222 g_assert (iter->segment->char_count > 0);
227 static GtkTextRealIter*
228 iter_init_common (GtkTextIter *_iter,
231 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
233 g_return_val_if_fail (iter != NULL, NULL);
234 g_return_val_if_fail (tree != NULL, NULL);
238 iter->chars_changed_stamp =
239 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
244 static GtkTextRealIter*
245 iter_init_from_segment (GtkTextIter *iter,
248 GtkTextLineSegment *segment)
250 GtkTextRealIter *real;
252 g_return_val_if_fail (line != NULL, NULL);
254 real = iter_init_common (iter, tree);
256 iter_set_from_segment (real, line, segment);
261 static GtkTextRealIter*
262 iter_init_from_byte_offset (GtkTextIter *iter,
265 gint line_byte_offset)
267 GtkTextRealIter *real;
269 g_return_val_if_fail (line != NULL, NULL);
271 real = iter_init_common (iter, tree);
273 iter_set_from_byte_offset (real, line, line_byte_offset);
275 if (real->segment->type == >k_text_char_type &&
276 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
277 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
278 "character; this will crash the text buffer. "
279 "Byte indexes must refer to the start of a character.",
285 static GtkTextRealIter*
286 iter_init_from_char_offset (GtkTextIter *iter,
289 gint line_char_offset)
291 GtkTextRealIter *real;
293 g_return_val_if_fail (line != NULL, NULL);
295 real = iter_init_common (iter, tree);
297 iter_set_from_char_offset (real, line, line_char_offset);
303 invalidate_segment (GtkTextRealIter *iter)
305 iter->segments_changed_stamp -= 1;
309 invalidate_char_index (GtkTextRealIter *iter)
311 iter->cached_char_index = -1;
315 invalidate_line_number (GtkTextRealIter *iter)
317 iter->cached_line_number = -1;
321 adjust_char_index (GtkTextRealIter *iter, gint count)
323 if (iter->cached_char_index >= 0)
324 iter->cached_char_index += count;
328 adjust_line_number (GtkTextRealIter *iter, gint count)
330 if (iter->cached_line_number >= 0)
331 iter->cached_line_number += count;
335 adjust_char_offsets (GtkTextRealIter *iter, gint count)
337 if (iter->line_char_offset >= 0)
339 iter->line_char_offset += count;
340 g_assert (iter->segment_char_offset >= 0);
341 iter->segment_char_offset += count;
346 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
348 if (iter->line_byte_offset >= 0)
350 iter->line_byte_offset += count;
351 g_assert (iter->segment_byte_offset >= 0);
352 iter->segment_byte_offset += count;
357 ensure_char_offsets (GtkTextRealIter *iter)
359 if (iter->line_char_offset < 0)
361 g_assert (iter->line_byte_offset >= 0);
363 _gtk_text_line_byte_to_char_offsets (iter->line,
364 iter->line_byte_offset,
365 &iter->line_char_offset,
366 &iter->segment_char_offset);
371 ensure_byte_offsets (GtkTextRealIter *iter)
373 if (iter->line_byte_offset < 0)
375 g_assert (iter->line_char_offset >= 0);
377 _gtk_text_line_char_to_byte_offsets (iter->line,
378 iter->line_char_offset,
379 &iter->line_byte_offset,
380 &iter->segment_byte_offset);
384 static inline gboolean
385 is_segment_start (GtkTextRealIter *real)
387 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
392 check_invariants (const GtkTextIter *iter)
394 if (gtk_debug_flags & GTK_DEBUG_TEXT)
395 _gtk_text_iter_check (iter);
398 #define check_invariants (x)
402 * gtk_text_iter_get_buffer:
405 * Returns the #GtkTextBuffer this iterator is associated with.
407 * Return value: the buffer
410 gtk_text_iter_get_buffer (const GtkTextIter *iter)
412 GtkTextRealIter *real;
414 g_return_val_if_fail (iter != NULL, NULL);
416 real = gtk_text_iter_make_surreal (iter);
421 check_invariants (iter);
423 return _gtk_text_btree_get_buffer (real->tree);
427 * gtk_text_iter_copy:
430 * Creates a dynamically-allocated copy of an iterator. This function
431 * is not useful in applications, because iterators can be copied with a
432 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
433 * function is used by language bindings.
435 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
438 gtk_text_iter_copy (const GtkTextIter *iter)
440 GtkTextIter *new_iter;
442 g_return_val_if_fail (iter != NULL, NULL);
444 new_iter = g_new (GtkTextIter, 1);
452 * gtk_text_iter_free:
453 * @iter: a dynamically-allocated iterator
455 * Free an iterator allocated on the heap. This function
456 * is intended for use in language bindings, and is not
457 * especially useful for applications, because iterators can
458 * simply be allocated on the stack.
461 gtk_text_iter_free (GtkTextIter *iter)
463 g_return_if_fail (iter != NULL);
469 gtk_text_iter_get_type (void)
471 static GType our_type = 0;
474 our_type = g_boxed_type_register_static ("GtkTextIter",
475 (GBoxedCopyFunc) gtk_text_iter_copy,
476 (GBoxedFreeFunc) gtk_text_iter_free);
482 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
484 GtkTextRealIter *real;
486 g_return_val_if_fail (iter != NULL, NULL);
488 real = gtk_text_iter_make_real (iter);
493 check_invariants (iter);
495 g_assert (real->segment != NULL);
497 return real->segment;
501 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
503 GtkTextRealIter *real;
505 g_return_val_if_fail (iter != NULL, NULL);
507 real = gtk_text_iter_make_real (iter);
512 check_invariants (iter);
514 g_assert (real->any_segment != NULL);
516 return real->any_segment;
520 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
522 GtkTextRealIter *real;
524 g_return_val_if_fail (iter != NULL, 0);
526 real = gtk_text_iter_make_real (iter);
531 ensure_byte_offsets (real);
533 check_invariants (iter);
535 return real->segment_byte_offset;
539 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
541 GtkTextRealIter *real;
543 g_return_val_if_fail (iter != NULL, 0);
545 real = gtk_text_iter_make_real (iter);
550 ensure_char_offsets (real);
552 check_invariants (iter);
554 return real->segment_char_offset;
557 /* This function does not require a still-valid
560 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
562 const GtkTextRealIter *real;
564 g_return_val_if_fail (iter != NULL, NULL);
566 real = (const GtkTextRealIter*)iter;
571 /* This function does not require a still-valid
574 _gtk_text_iter_get_btree (const GtkTextIter *iter)
576 const GtkTextRealIter *real;
578 g_return_val_if_fail (iter != NULL, NULL);
580 real = (const GtkTextRealIter*)iter;
590 * gtk_text_iter_get_offset:
593 * Returns the character offset of an iterator.
594 * Each character in a #GtkTextBuffer has an offset,
595 * starting with 0 for the first character in the buffer.
596 * Use gtk_text_buffer_get_iter_at_offset () to convert an
597 * offset back into an iterator.
599 * Return value: a character offset
602 gtk_text_iter_get_offset (const GtkTextIter *iter)
604 GtkTextRealIter *real;
606 g_return_val_if_fail (iter != NULL, 0);
608 real = gtk_text_iter_make_surreal (iter);
613 check_invariants (iter);
615 if (real->cached_char_index < 0)
617 ensure_char_offsets (real);
619 real->cached_char_index =
620 _gtk_text_line_char_index (real->line);
621 real->cached_char_index += real->line_char_offset;
624 check_invariants (iter);
626 return real->cached_char_index;
630 * gtk_text_iter_get_line:
633 * Returns the line number containing the iterator. Lines in
634 * a #GtkTextBuffer are numbered beginning with 0 for the first
635 * line in the buffer.
637 * Return value: a line number
640 gtk_text_iter_get_line (const GtkTextIter *iter)
642 GtkTextRealIter *real;
644 g_return_val_if_fail (iter != NULL, 0);
646 real = gtk_text_iter_make_surreal (iter);
651 if (real->cached_line_number < 0)
652 real->cached_line_number =
653 _gtk_text_line_get_number (real->line);
655 check_invariants (iter);
657 return real->cached_line_number;
661 * gtk_text_iter_get_line_offset:
664 * Returns the character offset of the iterator,
665 * counting from the start of a newline-terminated line.
666 * The first character on the line has offset 0.
668 * Return value: offset from start of line
671 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
673 GtkTextRealIter *real;
675 g_return_val_if_fail (iter != NULL, 0);
677 real = gtk_text_iter_make_surreal (iter);
682 ensure_char_offsets (real);
684 check_invariants (iter);
686 return real->line_char_offset;
690 * gtk_text_iter_get_line_index:
693 * Returns the byte index of the iterator, counting
694 * from the start of a newline-terminated line.
695 * Remember that #GtkTextBuffer encodes text in
696 * UTF-8, and that characters can require a variable
697 * number of bytes to represent.
699 * Return value: distance from start of line, in bytes
702 gtk_text_iter_get_line_index (const GtkTextIter *iter)
704 GtkTextRealIter *real;
706 g_return_val_if_fail (iter != NULL, 0);
708 real = gtk_text_iter_make_surreal (iter);
713 ensure_byte_offsets (real);
715 check_invariants (iter);
717 return real->line_byte_offset;
721 * gtk_text_iter_get_visible_line_offset:
722 * @iter: a #GtkTextIter
724 * Returns the offset in characters from the start of the
725 * line to the given @iter, not counting characters that
726 * are invisible due to tags with the "invisible" flag
729 * Return value: offset in visible characters from the start of the line
732 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
734 GtkTextRealIter *real;
736 GtkTextLineSegment *seg;
739 g_return_val_if_fail (iter != NULL, 0);
741 real = gtk_text_iter_make_real (iter);
746 ensure_char_offsets (real);
748 check_invariants (iter);
750 vis_offset = real->line_char_offset;
752 g_assert (vis_offset >= 0);
754 _gtk_text_btree_get_iter_at_line (real->tree,
759 seg = _gtk_text_iter_get_indexable_segment (&pos);
761 while (seg != real->segment)
763 /* This is a pretty expensive call, making the
764 * whole function pretty lame; we could keep track
765 * of current invisibility state by looking at toggle
766 * segments as we loop, and then call this function
767 * only once per line, in order to speed up the loop
770 if (_gtk_text_btree_char_is_invisible (&pos))
771 vis_offset -= seg->char_count;
773 _gtk_text_iter_forward_indexable_segment (&pos);
775 seg = _gtk_text_iter_get_indexable_segment (&pos);
778 if (_gtk_text_btree_char_is_invisible (&pos))
779 vis_offset -= real->segment_char_offset;
786 * gtk_text_iter_get_visible_line_index:
787 * @iter: a #GtkTextIter
789 * Returns the number of bytes from the start of the
790 * line to the given @iter, not counting bytes that
791 * are invisible due to tags with the "invisible" flag
794 * Return value: byte index of @iter with respect to the start of the line
797 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
799 GtkTextRealIter *real;
801 GtkTextLineSegment *seg;
804 g_return_val_if_fail (iter != NULL, 0);
806 real = gtk_text_iter_make_real (iter);
811 ensure_byte_offsets (real);
813 check_invariants (iter);
815 vis_offset = real->line_byte_offset;
817 g_assert (vis_offset >= 0);
819 _gtk_text_btree_get_iter_at_line (real->tree,
824 seg = _gtk_text_iter_get_indexable_segment (&pos);
826 while (seg != real->segment)
828 /* This is a pretty expensive call, making the
829 * whole function pretty lame; we could keep track
830 * of current invisibility state by looking at toggle
831 * segments as we loop, and then call this function
832 * only once per line, in order to speed up the loop
835 if (_gtk_text_btree_char_is_invisible (&pos))
836 vis_offset -= seg->byte_count;
838 _gtk_text_iter_forward_indexable_segment (&pos);
840 seg = _gtk_text_iter_get_indexable_segment (&pos);
843 if (_gtk_text_btree_char_is_invisible (&pos))
844 vis_offset -= real->segment_byte_offset;
854 * gtk_text_iter_get_char:
857 * Returns the Unicode character at this iterator. (Equivalent to
858 * operator* on a C++ iterator.) If the element at this iterator is a
859 * non-character element, such as an image embedded in the buffer, the
860 * Unicode "unknown" character 0xFFFC is returned. If invoked on
861 * the end iterator, zero is returned; zero is not a valid Unicode character.
862 * So you can write a loop which ends when gtk_text_iter_get_char ()
865 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
868 gtk_text_iter_get_char (const GtkTextIter *iter)
870 GtkTextRealIter *real;
872 g_return_val_if_fail (iter != NULL, 0);
874 real = gtk_text_iter_make_real (iter);
879 check_invariants (iter);
881 if (gtk_text_iter_is_end (iter))
883 else if (real->segment->type == >k_text_char_type)
885 ensure_byte_offsets (real);
887 return g_utf8_get_char (real->segment->body.chars +
888 real->segment_byte_offset);
892 /* Unicode "unknown character" 0xFFFC */
893 return GTK_TEXT_UNKNOWN_CHAR;
898 * gtk_text_iter_get_slice:
899 * @start: iterator at start of a range
900 * @end: iterator at end of a range
902 * Returns the text in the given range. A "slice" is an array of
903 * characters encoded in UTF-8 format, including the Unicode "unknown"
904 * character 0xFFFC for iterable non-character elements in the buffer,
905 * such as images. Because images are encoded in the slice, byte and
906 * character offsets in the returned array will correspond to byte
907 * offsets in the text buffer. Note that 0xFFFC can occur in normal
908 * text as well, so it is not a reliable indicator that a pixbuf or
909 * widget is in the buffer.
911 * Return value: slice of text from the buffer
914 gtk_text_iter_get_slice (const GtkTextIter *start,
915 const GtkTextIter *end)
917 g_return_val_if_fail (start != NULL, NULL);
918 g_return_val_if_fail (end != NULL, NULL);
920 check_invariants (start);
921 check_invariants (end);
923 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
927 * gtk_text_iter_get_text:
928 * @start: iterator at start of a range
929 * @end: iterator at end of a range
931 * Returns <emphasis>text</emphasis> in the given range. If the range
932 * contains non-text elements such as images, the character and byte
933 * offsets in the returned string will not correspond to character and
934 * byte offsets in the buffer. If you want offsets to correspond, see
935 * gtk_text_iter_get_slice ().
937 * Return value: array of characters from the buffer
940 gtk_text_iter_get_text (const GtkTextIter *start,
941 const GtkTextIter *end)
943 g_return_val_if_fail (start != NULL, NULL);
944 g_return_val_if_fail (end != NULL, NULL);
946 check_invariants (start);
947 check_invariants (end);
949 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
953 * gtk_text_iter_get_visible_slice:
954 * @start: iterator at start of range
955 * @end: iterator at end of range
957 * Like gtk_text_iter_get_slice (), but invisible text is not included.
958 * Invisible text is usually invisible because a #GtkTextTag with the
959 * "invisible" attribute turned on has been applied to it.
961 * Return value: slice of text from the buffer
964 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
965 const GtkTextIter *end)
967 g_return_val_if_fail (start != NULL, NULL);
968 g_return_val_if_fail (end != NULL, NULL);
970 check_invariants (start);
971 check_invariants (end);
973 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
977 * gtk_text_iter_get_visible_text:
978 * @start: iterator at start of range
979 * @end: iterator at end of range
981 * Like gtk_text_iter_get_text (), but invisible text is not included.
982 * Invisible text is usually invisible because a #GtkTextTag with the
983 * "invisible" attribute turned on has been applied to it.
985 * Return value: string containing visible text in the range
988 gtk_text_iter_get_visible_text (const GtkTextIter *start,
989 const GtkTextIter *end)
991 g_return_val_if_fail (start != NULL, NULL);
992 g_return_val_if_fail (end != NULL, NULL);
994 check_invariants (start);
995 check_invariants (end);
997 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
1001 * gtk_text_iter_get_pixbuf:
1002 * @iter: an iterator
1004 * If the element at @iter is a pixbuf, the pixbuf is returned
1005 * (with no new reference count added). Otherwise,
1006 * %NULL is returned.
1008 * Return value: the pixbuf at @iter
1011 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1013 GtkTextRealIter *real;
1015 g_return_val_if_fail (iter != NULL, NULL);
1017 real = gtk_text_iter_make_real (iter);
1022 check_invariants (iter);
1024 if (real->segment->type != >k_text_pixbuf_type)
1027 return real->segment->body.pixbuf.pixbuf;
1031 * gtk_text_iter_get_child_anchor:
1032 * @iter: an iterator
1034 * If the location at @iter contains a child anchor, the
1035 * anchor is returned (with no new reference count added). Otherwise,
1036 * %NULL is returned.
1038 * Return value: the anchor at @iter
1041 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1043 GtkTextRealIter *real;
1045 g_return_val_if_fail (iter != NULL, NULL);
1047 real = gtk_text_iter_make_real (iter);
1052 check_invariants (iter);
1054 if (real->segment->type != >k_text_child_type)
1057 return real->segment->body.child.obj;
1061 * gtk_text_iter_get_marks:
1062 * @iter: an iterator
1064 * Returns a list of all #GtkTextMark at this location. Because marks
1065 * are not iterable (they don't take up any "space" in the buffer,
1066 * they are just marks in between iterable locations), multiple marks
1067 * can exist in the same place. The returned list is not in any
1070 * Return value: list of #GtkTextMark
1073 gtk_text_iter_get_marks (const GtkTextIter *iter)
1075 GtkTextRealIter *real;
1076 GtkTextLineSegment *seg;
1079 g_return_val_if_fail (iter != NULL, NULL);
1081 real = gtk_text_iter_make_real (iter);
1086 check_invariants (iter);
1089 seg = real->any_segment;
1090 while (seg != real->segment)
1092 if (seg->type == >k_text_left_mark_type ||
1093 seg->type == >k_text_right_mark_type)
1094 retval = g_slist_prepend (retval, seg->body.mark.obj);
1099 /* The returned list isn't guaranteed to be in any special order,
1105 * gtk_text_iter_get_toggled_tags:
1106 * @iter: an iterator
1107 * @toggled_on: %TRUE to get toggled-on tags
1109 * Returns a list of #GtkTextTag that are toggled on or off at this
1110 * point. (If @toggled_on is %TRUE, the list contains tags that are
1111 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1112 * range of characters following @iter has that tag applied to it. If
1113 * a tag is toggled off, then some non-empty range following @iter
1114 * does <emphasis>not</emphasis> have the tag applied to it.
1116 * Return value: tags toggled at this point
1119 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1120 gboolean toggled_on)
1122 GtkTextRealIter *real;
1123 GtkTextLineSegment *seg;
1126 g_return_val_if_fail (iter != NULL, NULL);
1128 real = gtk_text_iter_make_real (iter);
1133 check_invariants (iter);
1136 seg = real->any_segment;
1137 while (seg != real->segment)
1141 if (seg->type == >k_text_toggle_on_type)
1143 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1148 if (seg->type == >k_text_toggle_off_type)
1150 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1157 /* The returned list isn't guaranteed to be in any special order,
1163 * gtk_text_iter_begins_tag:
1164 * @iter: an iterator
1165 * @tag: a #GtkTextTag, or %NULL
1167 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1168 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1169 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1170 * <emphasis>start</emphasis> of the tagged range;
1171 * gtk_text_iter_has_tag () tells you whether an iterator is
1172 * <emphasis>within</emphasis> a tagged range.
1174 * Return value: whether @iter is the start of a range tagged with @tag
1177 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1180 GtkTextRealIter *real;
1181 GtkTextLineSegment *seg;
1183 g_return_val_if_fail (iter != NULL, FALSE);
1185 real = gtk_text_iter_make_real (iter);
1190 check_invariants (iter);
1192 seg = real->any_segment;
1193 while (seg != real->segment)
1195 if (seg->type == >k_text_toggle_on_type)
1198 seg->body.toggle.info->tag == tag)
1209 * gtk_text_iter_ends_tag:
1210 * @iter: an iterator
1211 * @tag: a #GtkTextTag, or %NULL
1213 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1214 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1215 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1216 * <emphasis>end</emphasis> of the tagged range;
1217 * gtk_text_iter_has_tag () tells you whether an iterator is
1218 * <emphasis>within</emphasis> a tagged range.
1220 * Return value: whether @iter is the end of a range tagged with @tag
1224 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1227 GtkTextRealIter *real;
1228 GtkTextLineSegment *seg;
1230 g_return_val_if_fail (iter != NULL, FALSE);
1232 real = gtk_text_iter_make_real (iter);
1237 check_invariants (iter);
1239 seg = real->any_segment;
1240 while (seg != real->segment)
1242 if (seg->type == >k_text_toggle_off_type)
1245 seg->body.toggle.info->tag == tag)
1256 * gtk_text_iter_toggles_tag:
1257 * @iter: an iterator
1258 * @tag: a #GtkTextTag, or %NULL
1260 * This is equivalent to (gtk_text_iter_begins_tag () ||
1261 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1262 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1264 * Return value: whether @tag is toggled on or off at @iter
1267 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1270 GtkTextRealIter *real;
1271 GtkTextLineSegment *seg;
1273 g_return_val_if_fail (iter != NULL, FALSE);
1275 real = gtk_text_iter_make_real (iter);
1280 check_invariants (iter);
1282 seg = real->any_segment;
1283 while (seg != real->segment)
1285 if ( (seg->type == >k_text_toggle_off_type ||
1286 seg->type == >k_text_toggle_on_type) &&
1288 seg->body.toggle.info->tag == tag) )
1298 * gtk_text_iter_has_tag:
1299 * @iter: an iterator
1300 * @tag: a #GtkTextTag
1302 * Returns %TRUE if @iter is within a range tagged with @tag.
1304 * Return value: whether @iter is tagged with @tag
1307 gtk_text_iter_has_tag (const GtkTextIter *iter,
1310 GtkTextRealIter *real;
1312 g_return_val_if_fail (iter != NULL, FALSE);
1313 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1315 real = gtk_text_iter_make_surreal (iter);
1320 check_invariants (iter);
1322 if (real->line_byte_offset >= 0)
1324 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1325 real->line_byte_offset, tag);
1329 g_assert (real->line_char_offset >= 0);
1330 return _gtk_text_line_char_has_tag (real->line, real->tree,
1331 real->line_char_offset, tag);
1336 * gtk_text_iter_get_tags:
1337 * @iter: a #GtkTextIter
1339 * Returns a list of tags that apply to @iter, in ascending order of
1340 * priority (highest-priority tags are last). The #GtkTextTag in the
1341 * list don't have a reference added, but you have to free the list
1344 * Return value: list of #GtkTextTag
1347 gtk_text_iter_get_tags (const GtkTextIter *iter)
1354 g_return_val_if_fail (iter != NULL, NULL);
1356 /* Get the tags at this spot */
1357 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1359 /* No tags, use default style */
1360 if (tags == NULL || tag_count == 0)
1368 /* Sort tags in ascending order of priority */
1369 _gtk_text_tag_array_sort (tags, tag_count);
1373 while (i < tag_count)
1375 retval = g_slist_prepend (retval, tags[i]);
1381 /* Return tags in ascending order of priority */
1382 return g_slist_reverse (retval);
1386 * gtk_text_iter_editable:
1387 * @iter: an iterator
1388 * @default_setting: %TRUE if text is editable by default
1390 * Returns whether the character at @iter is within an editable region
1391 * of text. Non-editable text is "locked" and can't be changed by the
1392 * user via #GtkTextView. This function is simply a convenience
1393 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1394 * to this text affect editability, @default_setting will be returned.
1396 * You don't want to use this function to decide whether text can be
1397 * inserted at @iter, because for insertion you don't want to know
1398 * whether the char at @iter is inside an editable range, you want to
1399 * know whether a new character inserted at @iter would be inside an
1400 * editable range. Use gtk_text_iter_can_insert() to handle this
1403 * Return value: whether @iter is inside an editable range
1406 gtk_text_iter_editable (const GtkTextIter *iter,
1407 gboolean default_setting)
1409 GtkTextAttributes *values;
1412 g_return_val_if_fail (iter != NULL, FALSE);
1414 values = gtk_text_attributes_new ();
1416 values->editable = default_setting;
1418 gtk_text_iter_get_attributes (iter, values);
1420 retval = values->editable;
1422 gtk_text_attributes_unref (values);
1428 * gtk_text_iter_can_insert:
1429 * @iter: an iterator
1430 * @default_editability: %TRUE if text is editable by default
1432 * Considering the default editability of the buffer, and tags that
1433 * affect editability, determines whether text inserted at @iter would
1434 * be editable. If text inserted at @iter would be editable then the
1435 * user should be allowed to insert text at @iter.
1436 * gtk_text_buffer_insert_interactive() uses this function to decide
1437 * whether insertions are allowed at a given position.
1439 * Return value: whether text inserted at @iter would be editable
1442 gtk_text_iter_can_insert (const GtkTextIter *iter,
1443 gboolean default_editability)
1445 g_return_val_if_fail (iter != NULL, FALSE);
1447 if (gtk_text_iter_editable (iter, default_editability))
1449 /* If at start/end of buffer, default editability is used */
1450 else if ((gtk_text_iter_is_start (iter) ||
1451 gtk_text_iter_is_end (iter)) &&
1452 default_editability)
1456 /* if iter isn't editable, and the char before iter is,
1457 * then iter is the first char in an editable region
1458 * and thus insertion at iter results in editable text.
1460 GtkTextIter prev = *iter;
1461 gtk_text_iter_backward_char (&prev);
1462 return gtk_text_iter_editable (&prev, default_editability);
1468 * gtk_text_iter_get_language:
1469 * @iter: an iterator
1471 * A convenience wrapper around gtk_text_iter_get_attributes (),
1472 * which returns the language in effect at @iter. If no tags affecting
1473 * language apply to @iter, the return value is identical to that of
1474 * gtk_get_default_language ().
1476 * Return value: language in effect at @iter
1479 gtk_text_iter_get_language (const GtkTextIter *iter)
1481 GtkTextAttributes *values;
1482 PangoLanguage *retval;
1484 values = gtk_text_attributes_new ();
1486 gtk_text_iter_get_attributes (iter, values);
1488 retval = values->language;
1490 gtk_text_attributes_unref (values);
1496 * gtk_text_iter_starts_line:
1497 * @iter: an iterator
1499 * Returns %TRUE if @iter begins a paragraph,
1500 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1501 * However this function is potentially more efficient than
1502 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1503 * the offset, it just has to see whether it's 0.
1505 * Return value: whether @iter begins a line
1508 gtk_text_iter_starts_line (const GtkTextIter *iter)
1510 GtkTextRealIter *real;
1512 g_return_val_if_fail (iter != NULL, FALSE);
1514 real = gtk_text_iter_make_surreal (iter);
1519 check_invariants (iter);
1521 if (real->line_byte_offset >= 0)
1523 return (real->line_byte_offset == 0);
1527 g_assert (real->line_char_offset >= 0);
1528 return (real->line_char_offset == 0);
1533 * gtk_text_iter_ends_line:
1534 * @iter: an iterator
1536 * Returns %TRUE if @iter points to the start of the paragraph
1537 * delimiter characters for a line (delimiters will be either a
1538 * newline, a carriage return, a carriage return followed by a
1539 * newline, or a Unicode paragraph separator character). Note that an
1540 * iterator pointing to the \n of a \r\n pair will not be counted as
1541 * the end of a line, the line ends before the \r. The end iterator is
1542 * considered to be at the end of a line, even though there are no
1543 * paragraph delimiter chars there.
1545 * Return value: whether @iter is at the end of a line
1548 gtk_text_iter_ends_line (const GtkTextIter *iter)
1550 GtkTextRealIter *real;
1553 g_return_val_if_fail (iter != NULL, FALSE);
1555 real = gtk_text_iter_make_real (iter);
1557 check_invariants (iter);
1559 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1560 * Unicode 3.0; update this if that changes.
1562 #define PARAGRAPH_SEPARATOR 0x2029
1564 wc = gtk_text_iter_get_char (iter);
1566 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1568 else if (wc == '\n')
1570 /* need to determine if a \r precedes the \n, in which case
1571 * we aren't the end of the line
1573 GtkTextIter tmp = *iter;
1574 if (!gtk_text_iter_backward_char (&tmp))
1577 return gtk_text_iter_get_char (&tmp) != '\r';
1584 * gtk_text_iter_is_end:
1585 * @iter: an iterator
1587 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1588 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1589 * the most efficient way to check whether an iterator is the end
1592 * Return value: whether @iter is the end iterator
1595 gtk_text_iter_is_end (const GtkTextIter *iter)
1597 GtkTextRealIter *real;
1599 g_return_val_if_fail (iter != NULL, FALSE);
1601 real = gtk_text_iter_make_surreal (iter);
1606 check_invariants (iter);
1608 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1611 /* Now we need the segments validated */
1612 real = gtk_text_iter_make_real (iter);
1617 return _gtk_text_btree_is_end (real->tree, real->line,
1619 real->segment_byte_offset,
1620 real->segment_char_offset);
1624 * gtk_text_iter_is_start:
1625 * @iter: an iterator
1627 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1628 * if @iter has a character offset of 0.
1630 * Return value: whether @iter is the first in the buffer
1633 gtk_text_iter_is_start (const GtkTextIter *iter)
1635 return gtk_text_iter_get_offset (iter) == 0;
1639 * gtk_text_iter_get_chars_in_line:
1640 * @iter: an iterator
1642 * Returns the number of characters in the line containing @iter,
1643 * including the paragraph delimiters.
1645 * Return value: number of characters in the line
1648 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1650 GtkTextRealIter *real;
1652 GtkTextLineSegment *seg;
1654 g_return_val_if_fail (iter != NULL, 0);
1656 real = gtk_text_iter_make_surreal (iter);
1661 check_invariants (iter);
1663 if (real->line_char_offset >= 0)
1665 /* We can start at the segments we've already found. */
1666 count = real->line_char_offset - real->segment_char_offset;
1667 seg = _gtk_text_iter_get_indexable_segment (iter);
1671 /* count whole line. */
1672 seg = real->line->segments;
1679 count += seg->char_count;
1684 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1685 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1691 * gtk_text_iter_get_bytes_in_line:
1692 * @iter: an iterator
1694 * Returns the number of bytes in the line containing @iter,
1695 * including the paragraph delimiters.
1697 * Return value: number of bytes in the line
1700 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1702 GtkTextRealIter *real;
1704 GtkTextLineSegment *seg;
1706 g_return_val_if_fail (iter != NULL, 0);
1708 real = gtk_text_iter_make_surreal (iter);
1713 check_invariants (iter);
1715 if (real->line_byte_offset >= 0)
1717 /* We can start at the segments we've already found. */
1718 count = real->line_byte_offset - real->segment_byte_offset;
1719 seg = _gtk_text_iter_get_indexable_segment (iter);
1723 /* count whole line. */
1724 seg = real->line->segments;
1730 count += seg->byte_count;
1735 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1736 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1742 * gtk_text_iter_get_attributes:
1743 * @iter: an iterator
1744 * @values: a #GtkTextAttributes to be filled in
1746 * Computes the effect of any tags applied to this spot in the
1747 * text. The @values parameter should be initialized to the default
1748 * settings you wish to use if no tags are in effect. You'd typically
1749 * obtain the defaults from gtk_text_view_get_default_attributes().
1751 * gtk_text_iter_get_attributes () will modify @values, applying the
1752 * effects of any tags present at @iter. If any tags affected @values,
1753 * the function returns %TRUE.
1755 * Return value: %TRUE if @values was modified
1758 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1759 GtkTextAttributes *values)
1764 /* Get the tags at this spot */
1765 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1767 /* No tags, use default style */
1768 if (tags == NULL || tag_count == 0)
1776 /* Sort tags in ascending order of priority */
1777 _gtk_text_tag_array_sort (tags, tag_count);
1779 _gtk_text_attributes_fill_from_tags (values,
1789 * Increments/decrements
1792 /* The return value of this indicates WHETHER WE MOVED.
1793 * The return value of public functions indicates
1794 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1796 * This function will not change the iterator if
1797 * it's already on the last (end iter) line, i.e. it
1798 * won't move to the end of the last line.
1801 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1803 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1805 GtkTextLine *new_line;
1807 new_line = _gtk_text_line_next (real->line);
1808 g_assert (new_line);
1809 g_assert (new_line != real->line);
1810 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1812 real->line = new_line;
1814 real->line_byte_offset = 0;
1815 real->line_char_offset = 0;
1817 real->segment_byte_offset = 0;
1818 real->segment_char_offset = 0;
1820 /* Find first segments in new line */
1821 real->any_segment = real->line->segments;
1822 real->segment = real->any_segment;
1823 while (real->segment->char_count == 0)
1824 real->segment = real->segment->next;
1830 /* There is no way to move forward a line; we were already at
1831 * the line containing the end iterator.
1832 * However we may not be at the end iterator itself.
1840 /* The return value of this indicates WHETHER WE MOVED.
1841 * The return value of public functions indicates
1842 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1844 * This function is currently unused, thus it is #if-0-ed. It is
1845 * left here, since it's non-trivial code that might be useful in
1849 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1851 GtkTextLine *new_line;
1853 new_line = _gtk_text_line_previous (real->line);
1855 g_assert (new_line != real->line);
1857 if (new_line != NULL)
1859 real->line = new_line;
1861 real->line_byte_offset = 0;
1862 real->line_char_offset = 0;
1864 real->segment_byte_offset = 0;
1865 real->segment_char_offset = 0;
1867 /* Find first segments in new line */
1868 real->any_segment = real->line->segments;
1869 real->segment = real->any_segment;
1870 while (real->segment->char_count == 0)
1871 real->segment = real->segment->next;
1877 /* There is no way to move backward; we were already
1878 at the first line. */
1880 /* We leave real->line as-is */
1882 /* Note that we didn't clamp to the start of the first line. */
1889 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1893 forward_char (GtkTextRealIter *real)
1895 GtkTextIter *iter = (GtkTextIter*)real;
1897 check_invariants ((GtkTextIter*)real);
1899 ensure_char_offsets (real);
1901 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1903 /* Need to move to the next segment; if no next segment,
1904 need to move to next line. */
1905 return _gtk_text_iter_forward_indexable_segment (iter);
1909 /* Just moving within a segment. Keep byte count
1910 up-to-date, if it was already up-to-date. */
1912 g_assert (real->segment->type == >k_text_char_type);
1914 if (real->line_byte_offset >= 0)
1917 const char * start =
1918 real->segment->body.chars + real->segment_byte_offset;
1920 bytes = g_utf8_next_char (start) - start;
1922 real->line_byte_offset += bytes;
1923 real->segment_byte_offset += bytes;
1925 g_assert (real->segment_byte_offset < real->segment->byte_count);
1928 real->line_char_offset += 1;
1929 real->segment_char_offset += 1;
1931 adjust_char_index (real, 1);
1933 g_assert (real->segment_char_offset < real->segment->char_count);
1935 /* We moved into the middle of a segment, so the any_segment
1936 must now be the segment we're in the middle of. */
1937 real->any_segment = real->segment;
1939 check_invariants ((GtkTextIter*)real);
1941 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1949 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1951 /* Need to move to the next segment; if no next segment,
1952 need to move to next line. */
1953 GtkTextLineSegment *seg;
1954 GtkTextLineSegment *any_seg;
1955 GtkTextRealIter *real;
1959 g_return_val_if_fail (iter != NULL, FALSE);
1961 real = gtk_text_iter_make_real (iter);
1966 check_invariants (iter);
1968 if (real->line_char_offset >= 0)
1970 chars_skipped = real->segment->char_count - real->segment_char_offset;
1971 g_assert (chars_skipped > 0);
1976 if (real->line_byte_offset >= 0)
1978 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1979 g_assert (bytes_skipped > 0);
1984 /* Get first segment of any kind */
1985 any_seg = real->segment->next;
1986 /* skip non-indexable segments, if any */
1988 while (seg != NULL && seg->char_count == 0)
1993 real->any_segment = any_seg;
1994 real->segment = seg;
1996 if (real->line_byte_offset >= 0)
1998 g_assert (bytes_skipped > 0);
1999 real->segment_byte_offset = 0;
2000 real->line_byte_offset += bytes_skipped;
2003 if (real->line_char_offset >= 0)
2005 g_assert (chars_skipped > 0);
2006 real->segment_char_offset = 0;
2007 real->line_char_offset += chars_skipped;
2008 adjust_char_index (real, chars_skipped);
2011 check_invariants (iter);
2013 return !gtk_text_iter_is_end (iter);
2017 /* End of the line */
2018 if (forward_line_leaving_caches_unmodified (real))
2020 adjust_line_number (real, 1);
2021 if (real->line_char_offset >= 0)
2022 adjust_char_index (real, chars_skipped);
2024 g_assert (real->line_byte_offset == 0);
2025 g_assert (real->line_char_offset == 0);
2026 g_assert (real->segment_byte_offset == 0);
2027 g_assert (real->segment_char_offset == 0);
2028 g_assert (gtk_text_iter_starts_line (iter));
2030 check_invariants (iter);
2032 return !gtk_text_iter_is_end (iter);
2036 /* End of buffer, but iter is still at start of last segment,
2037 * not at the end iterator. We put it on the end iterator.
2040 check_invariants (iter);
2042 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2043 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2045 gtk_text_iter_forward_to_line_end (iter);
2047 g_assert (gtk_text_iter_is_end (iter));
2055 at_last_indexable_segment (GtkTextRealIter *real)
2057 GtkTextLineSegment *seg;
2059 /* Return TRUE if there are no indexable segments after
2063 seg = real->segment->next;
2066 if (seg->char_count > 0)
2073 /* Goes back to the start of the next segment, even if
2074 * we're not at the start of the current segment (always
2075 * ends up on a different segment if it returns TRUE)
2078 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2080 /* Move to the start of the previous segment; if no previous
2081 * segment, to the last segment in the previous line. This is
2082 * inherently a bit inefficient due to the singly-linked list and
2083 * tree nodes, but we can't afford the RAM for doubly-linked.
2085 GtkTextRealIter *real;
2086 GtkTextLineSegment *seg;
2087 GtkTextLineSegment *any_seg;
2088 GtkTextLineSegment *prev_seg;
2089 GtkTextLineSegment *prev_any_seg;
2093 g_return_val_if_fail (iter != NULL, FALSE);
2095 real = gtk_text_iter_make_real (iter);
2100 check_invariants (iter);
2102 /* Find first segments in line */
2103 any_seg = real->line->segments;
2105 while (seg->char_count == 0)
2108 if (seg == real->segment)
2110 /* Could probably do this case faster by hand-coding the
2114 /* We were already at the start of a line;
2115 * go back to the previous line.
2117 if (gtk_text_iter_backward_line (iter))
2119 /* Go forward to last indexable segment in line. */
2120 while (!at_last_indexable_segment (real))
2121 _gtk_text_iter_forward_indexable_segment (iter);
2123 check_invariants (iter);
2128 return FALSE; /* We were at the start of the first line. */
2131 /* We must be in the middle of a line; so find the indexable
2132 * segment just before our current segment.
2134 g_assert (seg != real->segment);
2138 prev_any_seg = any_seg;
2140 any_seg = seg->next;
2142 while (seg->char_count == 0)
2145 while (seg != real->segment);
2147 g_assert (prev_seg != NULL);
2148 g_assert (prev_any_seg != NULL);
2149 g_assert (prev_seg->char_count > 0);
2151 /* We skipped the entire previous segment, plus any
2152 * chars we were into the current segment.
2154 if (real->segment_byte_offset >= 0)
2155 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2159 if (real->segment_char_offset >= 0)
2160 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2164 real->segment = prev_seg;
2165 real->any_segment = prev_any_seg;
2166 real->segment_byte_offset = 0;
2167 real->segment_char_offset = 0;
2169 if (bytes_skipped >= 0)
2171 if (real->line_byte_offset >= 0)
2173 real->line_byte_offset -= bytes_skipped;
2174 g_assert (real->line_byte_offset >= 0);
2178 real->line_byte_offset = -1;
2180 if (chars_skipped >= 0)
2182 if (real->line_char_offset >= 0)
2184 real->line_char_offset -= chars_skipped;
2185 g_assert (real->line_char_offset >= 0);
2188 if (real->cached_char_index >= 0)
2190 real->cached_char_index -= chars_skipped;
2191 g_assert (real->cached_char_index >= 0);
2196 real->line_char_offset = -1;
2197 real->cached_char_index = -1;
2200 /* line number is unchanged. */
2202 check_invariants (iter);
2208 * gtk_text_iter_forward_char:
2209 * @iter: an iterator
2211 * Moves @iter forward by one character offset. Note that images
2212 * embedded in the buffer occupy 1 character slot, so
2213 * gtk_text_iter_forward_char () may actually move onto an image instead
2214 * of a character, if you have images in your buffer. If @iter is the
2215 * end iterator or one character before it, @iter will now point at
2216 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2217 * convenience when writing loops.
2219 * Return value: whether @iter moved and is dereferenceable
2222 gtk_text_iter_forward_char (GtkTextIter *iter)
2224 GtkTextRealIter *real;
2226 g_return_val_if_fail (iter != NULL, FALSE);
2228 real = gtk_text_iter_make_real (iter);
2234 check_invariants (iter);
2235 return forward_char (real);
2240 * gtk_text_iter_backward_char:
2241 * @iter: an iterator
2243 * Moves backward by one character offset. Returns %TRUE if movement
2244 * was possible; if @iter was the first in the buffer (character
2245 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2248 * Return value: whether movement was possible
2251 gtk_text_iter_backward_char (GtkTextIter *iter)
2253 g_return_val_if_fail (iter != NULL, FALSE);
2255 check_invariants (iter);
2257 return gtk_text_iter_backward_chars (iter, 1);
2261 Definitely we should try to linear scan as often as possible for
2262 movement within a single line, because we can't use the BTree to
2263 speed within-line searches up; for movement between lines, we would
2264 like to avoid the linear scan probably.
2266 Instead of using this constant, it might be nice to cache the line
2267 length in the iterator and linear scan if motion is within a single
2270 I guess you'd have to profile the various approaches.
2272 #define MAX_LINEAR_SCAN 150
2276 * gtk_text_iter_forward_chars:
2277 * @iter: an iterator
2278 * @count: number of characters to move, may be negative
2280 * Moves @count characters if possible (if @count would move past the
2281 * start or end of the buffer, moves to the start or end of the
2282 * buffer). The return value indicates whether the new position of
2283 * @iter is different from its original position, and dereferenceable
2284 * (the last iterator in the buffer is not dereferenceable). If @count
2285 * is 0, the function does nothing and returns %FALSE.
2287 * Return value: whether @iter moved and is dereferenceable
2290 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2292 GtkTextRealIter *real;
2294 g_return_val_if_fail (iter != NULL, FALSE);
2296 FIX_OVERFLOWS (count);
2298 real = gtk_text_iter_make_real (iter);
2302 else if (count == 0)
2305 return gtk_text_iter_backward_chars (iter, 0 - count);
2306 else if (count < MAX_LINEAR_SCAN)
2308 check_invariants (iter);
2312 if (!forward_char (real))
2317 return forward_char (real);
2321 gint current_char_index;
2322 gint new_char_index;
2324 check_invariants (iter);
2326 current_char_index = gtk_text_iter_get_offset (iter);
2328 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2329 return FALSE; /* can't move forward */
2331 new_char_index = current_char_index + count;
2332 gtk_text_iter_set_offset (iter, new_char_index);
2334 check_invariants (iter);
2336 /* Return FALSE if we're on the non-dereferenceable end
2339 if (gtk_text_iter_is_end (iter))
2347 * gtk_text_iter_backward_chars:
2348 * @iter: an iterator
2349 * @count: number of characters to move
2351 * Moves @count characters backward, if possible (if @count would move
2352 * past the start or end of the buffer, moves to the start or end of
2353 * the buffer). The return value indicates whether the iterator moved
2354 * onto a dereferenceable position; if the iterator didn't move, or
2355 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2356 * the function does nothing and returns %FALSE.
2358 * Return value: whether @iter moved and is dereferenceable
2362 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2364 GtkTextRealIter *real;
2366 g_return_val_if_fail (iter != NULL, FALSE);
2368 FIX_OVERFLOWS (count);
2370 real = gtk_text_iter_make_real (iter);
2374 else if (count == 0)
2377 return gtk_text_iter_forward_chars (iter, 0 - count);
2379 ensure_char_offsets (real);
2380 check_invariants (iter);
2382 /* <, not <=, because if count == segment_char_offset
2383 * we're going to the front of the segment and the any_segment
2386 if (count < real->segment_char_offset)
2388 /* Optimize the within-segment case */
2389 g_assert (real->segment->char_count > 0);
2390 g_assert (real->segment->type == >k_text_char_type);
2392 real->segment_char_offset -= count;
2393 g_assert (real->segment_char_offset >= 0);
2395 if (real->line_byte_offset >= 0)
2397 gint new_byte_offset;
2400 new_byte_offset = 0;
2402 while (i < real->segment_char_offset)
2404 const char * start = real->segment->body.chars + new_byte_offset;
2405 new_byte_offset += g_utf8_next_char (start) - start;
2410 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2411 real->segment_byte_offset = new_byte_offset;
2414 real->line_char_offset -= count;
2416 adjust_char_index (real, 0 - count);
2418 check_invariants (iter);
2424 /* We need to go back into previous segments. For now,
2425 * just keep this really simple. FIXME
2426 * use backward_indexable_segment.
2428 if (TRUE || count > MAX_LINEAR_SCAN)
2430 gint current_char_index;
2431 gint new_char_index;
2433 current_char_index = gtk_text_iter_get_offset (iter);
2435 if (current_char_index == 0)
2436 return FALSE; /* can't move backward */
2438 new_char_index = current_char_index - count;
2439 if (new_char_index < 0)
2442 gtk_text_iter_set_offset (iter, new_char_index);
2444 check_invariants (iter);
2450 /* FIXME backward_indexable_segment here */
2459 /* These two can't be implemented efficiently (always have to use
2460 * a linear scan, since that's the only way to find all the non-text
2465 * gtk_text_iter_forward_text_chars:
2466 * @iter: a #GtkTextIter
2467 * @count: number of chars to move
2469 * Moves forward by @count text characters (pixbufs, widgets,
2470 * etc. do not count as characters for this). Equivalent to moving
2471 * through the results of gtk_text_iter_get_text (), rather than
2472 * gtk_text_iter_get_slice ().
2474 * Return value: whether @iter moved and is dereferenceable
2477 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2486 * gtk_text_iter_forward_text_chars:
2487 * @iter: a #GtkTextIter
2488 * @count: number of chars to move
2490 * Moves backward by @count text characters (pixbufs, widgets,
2491 * etc. do not count as characters for this). Equivalent to moving
2492 * through the results of gtk_text_iter_get_text (), rather than
2493 * gtk_text_iter_get_slice ().
2495 * Return value: whether @iter moved and is dereferenceable
2498 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2507 * gtk_text_iter_forward_line:
2508 * @iter: an iterator
2510 * Moves @iter to the start of the next line. Returns %TRUE if there
2511 * was a next line to move to, and %FALSE if @iter was simply moved to
2512 * the end of the buffer and is now not dereferenceable, or if @iter was
2513 * already at the end of the buffer.
2515 * Return value: whether @iter can be dereferenced
2518 gtk_text_iter_forward_line (GtkTextIter *iter)
2520 GtkTextRealIter *real;
2522 g_return_val_if_fail (iter != NULL, FALSE);
2524 real = gtk_text_iter_make_real (iter);
2529 check_invariants (iter);
2531 if (forward_line_leaving_caches_unmodified (real))
2533 invalidate_char_index (real);
2534 adjust_line_number (real, 1);
2536 check_invariants (iter);
2538 if (gtk_text_iter_is_end (iter))
2545 /* On the last line, move to end of it */
2547 if (!gtk_text_iter_is_end (iter))
2548 gtk_text_iter_forward_to_end (iter);
2550 check_invariants (iter);
2556 * gtk_text_iter_backward_line:
2557 * @iter: an iterator
2559 * Moves @iter to the start of the previous line. Returns %TRUE if
2560 * @iter could be moved; i.e. if @iter was at character offset 0, this
2561 * function returns %FALSE. Therefore if @iter was already on line 0,
2562 * but not at the start of the line, @iter is snapped to the start of
2563 * the line and the function returns %TRUE. (Note that this implies that
2564 * in a loop calling this function, the line number may not change on
2565 * every iteration, if your first iteration is on line 0.)
2567 * Return value: whether @iter moved
2570 gtk_text_iter_backward_line (GtkTextIter *iter)
2572 GtkTextLine *new_line;
2573 GtkTextRealIter *real;
2574 gboolean offset_will_change;
2577 g_return_val_if_fail (iter != NULL, FALSE);
2579 real = gtk_text_iter_make_real (iter);
2584 check_invariants (iter);
2586 new_line = _gtk_text_line_previous (real->line);
2588 offset_will_change = FALSE;
2589 if (real->line_char_offset > 0)
2590 offset_will_change = TRUE;
2592 if (new_line != NULL)
2594 real->line = new_line;
2596 adjust_line_number (real, -1);
2600 if (!offset_will_change)
2604 invalidate_char_index (real);
2606 real->line_byte_offset = 0;
2607 real->line_char_offset = 0;
2609 real->segment_byte_offset = 0;
2610 real->segment_char_offset = 0;
2612 /* Find first segment in line */
2613 real->any_segment = real->line->segments;
2614 real->segment = _gtk_text_line_byte_to_segment (real->line,
2617 g_assert (offset == 0);
2619 /* Note that if we are on the first line, we snap to the start of
2620 * the first line and return TRUE, so TRUE means the iterator
2621 * changed, not that the line changed; this is maybe a bit
2622 * weird. I'm not sure there's an obvious right thing to do though.
2625 check_invariants (iter);
2632 * gtk_text_iter_forward_lines:
2633 * @iter: a #GtkTextIter
2634 * @count: number of lines to move forward
2636 * Moves @count lines forward, if possible (if @count would move
2637 * past the start or end of the buffer, moves to the start or end of
2638 * the buffer). The return value indicates whether the iterator moved
2639 * onto a dereferenceable position; if the iterator didn't move, or
2640 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2641 * the function does nothing and returns %FALSE. If @count is negative,
2642 * moves backward by 0 - @count lines.
2644 * Return value: whether @iter moved and is dereferenceable
2647 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2649 FIX_OVERFLOWS (count);
2652 return gtk_text_iter_backward_lines (iter, 0 - count);
2653 else if (count == 0)
2655 else if (count == 1)
2657 check_invariants (iter);
2658 return gtk_text_iter_forward_line (iter);
2664 if (gtk_text_iter_is_end (iter))
2667 old_line = gtk_text_iter_get_line (iter);
2669 gtk_text_iter_set_line (iter, old_line + count);
2671 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2673 /* count went past the last line, so move to end of last line */
2674 if (!gtk_text_iter_is_end (iter))
2675 gtk_text_iter_forward_to_end (iter);
2678 return !gtk_text_iter_is_end (iter);
2683 * gtk_text_iter_backward_lines:
2684 * @iter: a #GtkTextIter
2685 * @count: number of lines to move backward
2687 * Moves @count lines backward, if possible (if @count would move
2688 * past the start or end of the buffer, moves to the start or end of
2689 * the buffer). The return value indicates whether the iterator moved
2690 * onto a dereferenceable position; if the iterator didn't move, or
2691 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2692 * the function does nothing and returns %FALSE. If @count is negative,
2693 * moves forward by 0 - @count lines.
2695 * Return value: whether @iter moved and is dereferenceable
2698 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2700 FIX_OVERFLOWS (count);
2703 return gtk_text_iter_forward_lines (iter, 0 - count);
2704 else if (count == 0)
2706 else if (count == 1)
2708 return gtk_text_iter_backward_line (iter);
2714 old_line = gtk_text_iter_get_line (iter);
2716 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2718 return (gtk_text_iter_get_line (iter) != old_line);
2722 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2727 gboolean already_moved_initially);
2729 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2737 find_word_end_func (const PangoLogAttr *attrs,
2742 gboolean already_moved_initially)
2744 if (!already_moved_initially)
2747 /* Find end of next word */
2748 while (offset < min_offset + len &&
2749 !attrs[offset].is_word_end)
2752 *found_offset = offset;
2754 return offset < min_offset + len;
2758 is_word_end_func (const PangoLogAttr *attrs,
2763 return attrs[offset].is_word_end;
2767 find_word_start_func (const PangoLogAttr *attrs,
2772 gboolean already_moved_initially)
2774 if (!already_moved_initially)
2777 /* Find start of prev word */
2778 while (offset >= min_offset &&
2779 !attrs[offset].is_word_start)
2782 *found_offset = offset;
2784 return offset >= min_offset;
2788 is_word_start_func (const PangoLogAttr *attrs,
2793 return attrs[offset].is_word_start;
2797 inside_word_func (const PangoLogAttr *attrs,
2802 /* Find next word start or end */
2803 while (offset >= min_offset &&
2804 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2807 return attrs[offset].is_word_start;
2810 /* Sentence funcs */
2813 find_sentence_end_func (const PangoLogAttr *attrs,
2818 gboolean already_moved_initially)
2820 if (!already_moved_initially)
2823 /* Find end of next sentence */
2824 while (offset < min_offset + len &&
2825 !attrs[offset].is_sentence_end)
2828 *found_offset = offset;
2830 return offset < min_offset + len;
2834 is_sentence_end_func (const PangoLogAttr *attrs,
2839 return attrs[offset].is_sentence_end;
2843 find_sentence_start_func (const PangoLogAttr *attrs,
2848 gboolean already_moved_initially)
2850 if (!already_moved_initially)
2853 /* Find start of prev sentence */
2854 while (offset >= min_offset &&
2855 !attrs[offset].is_sentence_start)
2858 *found_offset = offset;
2860 return offset >= min_offset;
2864 is_sentence_start_func (const PangoLogAttr *attrs,
2869 return attrs[offset].is_sentence_start;
2873 inside_sentence_func (const PangoLogAttr *attrs,
2878 /* Find next sentence start or end */
2879 while (offset >= min_offset &&
2880 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2883 return attrs[offset].is_sentence_start;
2887 test_log_attrs (const GtkTextIter *iter,
2888 TestLogAttrFunc func)
2891 const PangoLogAttr *attrs;
2893 gboolean result = FALSE;
2895 g_return_val_if_fail (iter != NULL, FALSE);
2897 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2900 offset = gtk_text_iter_get_line_offset (iter);
2902 /* char_len may be 0 and attrs will be NULL if so, if
2903 * iter is the end iter and the last line is empty.
2905 * offset may be equal to char_len, since attrs contains an entry
2906 * for one past the end
2909 if (attrs && offset <= char_len)
2910 result = (* func) (attrs, offset, 0, char_len);
2916 find_line_log_attrs (const GtkTextIter *iter,
2917 FindLogAttrFunc func,
2919 gboolean already_moved_initially)
2922 const PangoLogAttr *attrs;
2924 gboolean result = FALSE;
2926 g_return_val_if_fail (iter != NULL, FALSE);
2928 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2931 offset = gtk_text_iter_get_line_offset (iter);
2933 /* char_len may be 0 and attrs will be NULL if so, if
2934 * iter is the end iter and the last line is empty
2938 result = (* func) (attrs, offset, 0, char_len, found_offset,
2939 already_moved_initially);
2944 /* FIXME this function is very, very gratuitously slow */
2946 find_by_log_attrs (GtkTextIter *iter,
2947 FindLogAttrFunc func,
2949 gboolean already_moved_initially)
2953 gboolean found = FALSE;
2955 g_return_val_if_fail (iter != NULL, FALSE);
2959 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2965 if (gtk_text_iter_forward_line (iter))
2966 return find_by_log_attrs (iter, func, forward,
2973 /* go to end of previous line. need to check that
2974 * line is > 0 because backward_line snaps to start of
2975 * line 0 if it's on line 0
2977 if (gtk_text_iter_get_line (iter) > 0 &&
2978 gtk_text_iter_backward_line (iter))
2980 if (!gtk_text_iter_ends_line (iter))
2981 gtk_text_iter_forward_to_line_end (iter);
2983 return find_by_log_attrs (iter, func, forward,
2992 gtk_text_iter_set_line_offset (iter, offset);
2995 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2996 !gtk_text_iter_is_end (iter);
3001 find_visible_by_log_attrs (GtkTextIter *iter,
3002 FindLogAttrFunc func,
3004 gboolean already_moved_initially)
3008 g_return_val_if_fail (iter != NULL, FALSE);
3012 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3014 if (!_gtk_text_btree_char_is_invisible (&pos))
3024 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3025 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3028 move_multiple_steps (GtkTextIter *iter,
3030 OneStepFunc step_forward,
3031 MultipleStepFunc n_steps_backward)
3033 g_return_val_if_fail (iter != NULL, FALSE);
3035 FIX_OVERFLOWS (count);
3041 return n_steps_backward (iter, -count);
3043 if (!step_forward (iter))
3049 if (!step_forward (iter))
3054 return !gtk_text_iter_is_end (iter);
3059 * gtk_text_iter_forward_word_end:
3060 * @iter: a #GtkTextIter
3062 * Moves forward to the next word end. (If @iter is currently on a
3063 * word end, moves forward to the next one after that.) Word breaks
3064 * are determined by Pango and should be correct for nearly any
3065 * language (if not, the correct fix would be to the Pango word break
3068 * Return value: %TRUE if @iter moved and is not the end iterator
3071 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3073 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3077 * gtk_text_iter_backward_word_start:
3078 * @iter: a #GtkTextIter
3080 * Moves backward to the previous word start. (If @iter is currently on a
3081 * word start, moves backward to the next one after that.) Word breaks
3082 * are determined by Pango and should be correct for nearly any
3083 * language (if not, the correct fix would be to the Pango word break
3086 * Return value: %TRUE if @iter moved and is not the end iterator
3089 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3091 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3094 /* FIXME a loop around a truly slow function means
3095 * a truly spectacularly slow function.
3099 * gtk_text_iter_forward_word_ends:
3100 * @iter: a #GtkTextIter
3101 * @count: number of times to move
3103 * Calls gtk_text_iter_forward_word_end() up to @count times.
3105 * Return value: %TRUE if @iter moved and is not the end iterator
3108 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3111 return move_multiple_steps (iter, count,
3112 gtk_text_iter_forward_word_end,
3113 gtk_text_iter_backward_word_starts);
3117 * gtk_text_iter_backward_word_starts
3118 * @iter: a #GtkTextIter
3119 * @count: number of times to move
3121 * Calls gtk_text_iter_backward_word_start() up to @count times.
3123 * Return value: %TRUE if @iter moved and is not the end iterator
3126 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3129 return move_multiple_steps (iter, count,
3130 gtk_text_iter_backward_word_start,
3131 gtk_text_iter_forward_word_ends);
3135 * gtk_text_iter_forward_visible_word_end:
3136 * @iter: a #GtkTextIter
3138 * Moves forward to the next visible word end. (If @iter is currently on a
3139 * word end, moves forward to the next one after that.) Word breaks
3140 * are determined by Pango and should be correct for nearly any
3141 * language (if not, the correct fix would be to the Pango word break
3144 * Return value: %TRUE if @iter moved and is not the end iterator
3149 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3151 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3155 * gtk_text_iter_backward_visible_word_start:
3156 * @iter: a #GtkTextIter
3158 * Moves backward to the previous visible word start. (If @iter is currently
3159 * on a word start, moves backward to the next one after that.) Word breaks
3160 * are determined by Pango and should be correct for nearly any
3161 * language (if not, the correct fix would be to the Pango word break
3164 * Return value: %TRUE if @iter moved and is not the end iterator
3169 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3171 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3175 * gtk_text_iter_forward_visible_word_ends:
3176 * @iter: a #GtkTextIter
3177 * @count: number of times to move
3179 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3181 * Return value: %TRUE if @iter moved and is not the end iterator
3186 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3189 return move_multiple_steps (iter, count,
3190 gtk_text_iter_forward_visible_word_end,
3191 gtk_text_iter_backward_visible_word_starts);
3195 * gtk_text_iter_backward_visible_word_starts
3196 * @iter: a #GtkTextIter
3197 * @count: number of times to move
3199 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3201 * Return value: %TRUE if @iter moved and is not the end iterator
3206 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3209 return move_multiple_steps (iter, count,
3210 gtk_text_iter_backward_visible_word_start,
3211 gtk_text_iter_forward_visible_word_ends);
3215 * gtk_text_iter_starts_word:
3216 * @iter: a #GtkTextIter
3218 * Determines whether @iter begins a natural-language word. Word
3219 * breaks are determined by Pango and should be correct for nearly any
3220 * language (if not, the correct fix would be to the Pango word break
3223 * Return value: %TRUE if @iter is at the start of a word
3226 gtk_text_iter_starts_word (const GtkTextIter *iter)
3228 return test_log_attrs (iter, is_word_start_func);
3232 * gtk_text_iter_ends_word:
3233 * @iter: a #GtkTextIter
3235 * Determines whether @iter ends a natural-language word. Word breaks
3236 * are determined by Pango and should be correct for nearly any
3237 * language (if not, the correct fix would be to the Pango word break
3240 * Return value: %TRUE if @iter is at the end of a word
3243 gtk_text_iter_ends_word (const GtkTextIter *iter)
3245 return test_log_attrs (iter, is_word_end_func);
3249 * gtk_text_iter_inside_word:
3250 * @iter: a #GtkTextIter
3252 * Determines whether @iter is inside a natural-language word (as
3253 * opposed to say inside some whitespace). Word breaks are determined
3254 * by Pango and should be correct for nearly any language (if not, the
3255 * correct fix would be to the Pango word break algorithms).
3257 * Return value: %TRUE if @iter is inside a word
3260 gtk_text_iter_inside_word (const GtkTextIter *iter)
3262 return test_log_attrs (iter, inside_word_func);
3266 * gtk_text_iter_starts_sentence:
3267 * @iter: a #GtkTextIter
3269 * Determines whether @iter begins a sentence. Sentence boundaries are
3270 * determined by Pango and should be correct for nearly any language
3271 * (if not, the correct fix would be to the Pango text boundary
3274 * Return value: %TRUE if @iter is at the start of a sentence.
3277 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3279 return test_log_attrs (iter, is_sentence_start_func);
3283 * gtk_text_iter_ends_sentence:
3284 * @iter: a #GtkTextIter
3286 * Determines whether @iter ends a sentence. Sentence boundaries are
3287 * determined by Pango and should be correct for nearly any language
3288 * (if not, the correct fix would be to the Pango text boundary
3291 * Return value: %TRUE if @iter is at the end of a sentence.
3294 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3296 return test_log_attrs (iter, is_sentence_end_func);
3300 * gtk_text_iter_inside_sentence:
3301 * @iter: a #GtkTextIter
3303 * Determines whether @iter is inside a sentence (as opposed to in
3304 * between two sentences, e.g. after a period and before the first
3305 * letter of the next sentence). Sentence boundaries are determined
3306 * by Pango and should be correct for nearly any language (if not, the
3307 * correct fix would be to the Pango text boundary algorithms).
3309 * Return value: %TRUE if @iter is inside a sentence.
3312 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3314 return test_log_attrs (iter, inside_sentence_func);
3318 * gtk_text_iter_forward_sentence_end:
3319 * @iter: a #GtkTextIter
3321 * Moves forward to the next sentence end. (If @iter is at the end of
3322 * a sentence, moves to the next end of sentence.) Sentence
3323 * boundaries are determined by Pango and should be correct for nearly
3324 * any language (if not, the correct fix would be to the Pango text
3325 * boundary algorithms).
3327 * Return value: %TRUE if @iter moved and is not the end iterator
3330 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3332 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3336 * gtk_text_iter_backward_sentence_start:
3337 * @iter: a #GtkTextIter
3339 * Moves backward to the previous sentence start; if @iter is already at
3340 * the start of a sentence, moves backward to the next one. Sentence
3341 * boundaries are determined by Pango and should be correct for nearly
3342 * any language (if not, the correct fix would be to the Pango text
3343 * boundary algorithms).
3345 * Return value: %TRUE if @iter moved and is not the end iterator
3348 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3350 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3353 /* FIXME a loop around a truly slow function means
3354 * a truly spectacularly slow function.
3357 * gtk_text_iter_forward_sentence_ends:
3358 * @iter: a #GtkTextIter
3359 * @count: number of sentences to move
3361 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3362 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3363 * negative, moves backward instead of forward.
3365 * Return value: %TRUE if @iter moved and is not the end iterator
3368 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3371 return move_multiple_steps (iter, count,
3372 gtk_text_iter_forward_sentence_end,
3373 gtk_text_iter_backward_sentence_starts);
3377 * gtk_text_iter_backward_sentence_starts:
3378 * @iter: a #GtkTextIter
3379 * @count: number of sentences to move
3381 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3382 * or until it returns %FALSE. If @count is negative, moves forward
3383 * instead of backward.
3385 * Return value: %TRUE if @iter moved and is not the end iterator
3388 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3391 return move_multiple_steps (iter, count,
3392 gtk_text_iter_backward_sentence_start,
3393 gtk_text_iter_forward_sentence_ends);
3397 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3402 gboolean already_moved_initially)
3404 if (!already_moved_initially)
3407 while (offset < (min_offset + len) &&
3408 !attrs[offset].is_cursor_position)
3411 *found_offset = offset;
3413 return offset < (min_offset + len);
3417 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3422 gboolean already_moved_initially)
3424 if (!already_moved_initially)
3427 while (offset > min_offset &&
3428 !attrs[offset].is_cursor_position)
3431 *found_offset = offset;
3433 return offset >= min_offset;
3437 is_cursor_pos_func (const PangoLogAttr *attrs,
3442 return attrs[offset].is_cursor_position;
3446 * gtk_text_iter_forward_cursor_position:
3447 * @iter: a #GtkTextIter
3449 * Moves @iter forward by a single cursor position. Cursor positions
3450 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3451 * surprisingly, there may not be a cursor position between all
3452 * characters. The most common example for European languages would be
3453 * a carriage return/newline sequence. For some Unicode characters,
3454 * the equivalent of say the letter "a" with an accent mark will be
3455 * represented as two characters, first the letter then a "combining
3456 * mark" that causes the accent to be rendered; so the cursor can't go
3457 * between those two characters. See also the #PangoLogAttr structure and
3458 * pango_break() function.
3460 * Return value: %TRUE if we moved and the new position is dereferenceable
3463 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3465 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3469 * gtk_text_iter_backward_cursor_position:
3470 * @iter: a #GtkTextIter
3472 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3474 * Return value: %TRUE if we moved
3477 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3479 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3483 * gtk_text_iter_forward_cursor_positions:
3484 * @iter: a #GtkTextIter
3485 * @count: number of positions to move
3487 * Moves up to @count cursor positions. See
3488 * gtk_text_iter_forward_cursor_position() for details.
3490 * Return value: %TRUE if we moved and the new position is dereferenceable
3493 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3496 return move_multiple_steps (iter, count,
3497 gtk_text_iter_forward_cursor_position,
3498 gtk_text_iter_backward_cursor_positions);
3502 * gtk_text_iter_backward_cursor_positions:
3503 * @iter: a #GtkTextIter
3504 * @count: number of positions to move
3506 * Moves up to @count cursor positions. See
3507 * gtk_text_iter_forward_cursor_position() for details.
3509 * Return value: %TRUE if we moved and the new position is dereferenceable
3512 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3515 return move_multiple_steps (iter, count,
3516 gtk_text_iter_backward_cursor_position,
3517 gtk_text_iter_forward_cursor_positions);
3521 * gtk_text_iter_forward_visible_cursor_position:
3522 * @iter: a #GtkTextIter
3524 * Moves @iter forward to the next visible cursor position. See
3525 * gtk_text_iter_forward_cursor_position() for details.
3527 * Return value: %TRUE if we moved and the new position is dereferenceable
3532 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3534 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3538 * gtk_text_iter_backward_visible_cursor_position:
3539 * @iter: a #GtkTextIter
3541 * Moves @iter forward to the previous visible cursor position. See
3542 * gtk_text_iter_backward_cursor_position() for details.
3544 * Return value: %TRUE if we moved and the new position is dereferenceable
3549 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3551 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3555 * gtk_text_iter_forward_visible_cursor_positions:
3556 * @iter: a #GtkTextIter
3557 * @count: number of positions to move
3559 * Moves up to @count visible cursor positions. See
3560 * gtk_text_iter_forward_cursor_position() for details.
3562 * Return value: %TRUE if we moved and the new position is dereferenceable
3567 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3570 return move_multiple_steps (iter, count,
3571 gtk_text_iter_forward_visible_cursor_position,
3572 gtk_text_iter_backward_visible_cursor_positions);
3576 * gtk_text_iter_backward_visible_cursor_positions:
3577 * @iter: a #GtkTextIter
3578 * @count: number of positions to move
3580 * Moves up to @count visible cursor positions. See
3581 * gtk_text_iter_forward_cursor_position() for details.
3583 * Return value: %TRUE if we moved and the new position is dereferenceable
3588 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3591 return move_multiple_steps (iter, count,
3592 gtk_text_iter_backward_visible_cursor_position,
3593 gtk_text_iter_forward_visible_cursor_positions);
3597 * gtk_text_iter_is_cursor_position:
3598 * @iter: a #GtkTextIter
3600 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3601 * pango_break() for details on what a cursor position is.
3603 * Return value: %TRUE if the cursor can be placed at @iter
3606 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3608 return test_log_attrs (iter, is_cursor_pos_func);
3612 * gtk_text_iter_set_line_offset:
3613 * @iter: a #GtkTextIter
3614 * @char_on_line: a character offset relative to the start of @iter's current line
3616 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3617 * (not byte) offset. The given character offset must be less than or
3618 * equal to the number of characters in the line; if equal, @iter
3619 * moves to the start of the next line. See
3620 * gtk_text_iter_set_line_index() if you have a byte index rather than
3621 * a character offset.
3625 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3628 GtkTextRealIter *real;
3631 g_return_if_fail (iter != NULL);
3633 real = gtk_text_iter_make_surreal (iter);
3638 check_invariants (iter);
3640 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3642 g_return_if_fail (char_on_line <= chars_in_line);
3644 if (char_on_line < chars_in_line)
3645 iter_set_from_char_offset (real, real->line, char_on_line);
3647 gtk_text_iter_forward_line (iter); /* set to start of next line */
3649 check_invariants (iter);
3653 * gtk_text_iter_set_line_index:
3654 * @iter: a #GtkTextIter
3655 * @byte_on_line: a byte index relative to the start of @iter's current line
3657 * Same as gtk_text_iter_set_line_offset(), but works with a
3658 * <emphasis>byte</emphasis> index. The given byte index must be at
3659 * the start of a character, it can't be in the middle of a UTF-8
3660 * encoded character.
3664 gtk_text_iter_set_line_index (GtkTextIter *iter,
3667 GtkTextRealIter *real;
3670 g_return_if_fail (iter != NULL);
3672 real = gtk_text_iter_make_surreal (iter);
3677 check_invariants (iter);
3679 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3681 g_return_if_fail (byte_on_line <= bytes_in_line);
3683 if (byte_on_line < bytes_in_line)
3684 iter_set_from_byte_offset (real, real->line, byte_on_line);
3686 gtk_text_iter_forward_line (iter);
3688 if (real->segment->type == >k_text_char_type &&
3689 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3690 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3691 "character; this will crash the text buffer. "
3692 "Byte indexes must refer to the start of a character.",
3693 G_STRLOC, byte_on_line);
3695 check_invariants (iter);
3700 * gtk_text_iter_set_visible_line_offset:
3701 * @iter: a #GtkTextIter
3702 * @char_on_line: a character offset
3704 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3705 * characters, i.e. text with a tag making it invisible is not
3706 * counted in the offset.
3709 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3712 gint chars_seen = 0;
3715 g_return_if_fail (iter != NULL);
3719 /* For now we use a ludicrously slow implementation */
3720 while (chars_seen < char_on_line)
3722 if (!_gtk_text_btree_char_is_invisible (&pos))
3725 if (!gtk_text_iter_forward_char (&pos))
3728 if (chars_seen == char_on_line)
3732 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3735 gtk_text_iter_forward_line (iter);
3739 bytes_in_char (GtkTextIter *iter)
3741 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3745 * gtk_text_iter_set_visible_line_index:
3746 * @iter: a #GtkTextIter
3747 * @byte_on_line: a byte index
3749 * Like gtk_text_iter_set_line_index(), but the index is in visible
3750 * bytes, i.e. text with a tag making it invisible is not counted
3754 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3757 gint bytes_seen = 0;
3761 g_return_if_fail (iter != NULL);
3765 /* For now we use a ludicrously slow implementation */
3766 while (bytes_seen < byte_on_line)
3768 if (!_gtk_text_btree_char_is_invisible (&pos))
3769 bytes_seen += bytes_in_char (&pos);
3772 if (!gtk_text_iter_forward_char (&pos))
3775 if (bytes_seen >= byte_on_line)
3779 if (bytes_seen > byte_on_line)
3780 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3781 "character; this will crash the text buffer. "
3782 "Byte indexes must refer to the start of a character.",
3783 G_STRLOC, byte_on_line);
3785 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3788 gtk_text_iter_forward_line (iter);
3792 * gtk_text_iter_set_line:
3793 * @iter: a #GtkTextIter
3794 * @line_number: line number (counted from 0)
3796 * Moves iterator @iter to the start of the line @line_number. If
3797 * @line_number is negative or larger than the number of lines in the
3798 * buffer, moves @iter to the start of the last line in the buffer.
3802 gtk_text_iter_set_line (GtkTextIter *iter,
3807 GtkTextRealIter *real;
3809 g_return_if_fail (iter != NULL);
3811 real = gtk_text_iter_make_surreal (iter);
3816 check_invariants (iter);
3818 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3820 iter_set_from_char_offset (real, line, 0);
3822 /* We might as well cache this, since we know it. */
3823 real->cached_line_number = real_line;
3825 check_invariants (iter);
3829 * gtk_text_iter_set_offset:
3830 * @iter: a #GtkTextIter
3831 * @char_offset: a character number
3833 * Sets @iter to point to @char_offset. @char_offset counts from the start
3834 * of the entire text buffer, starting with 0.
3837 gtk_text_iter_set_offset (GtkTextIter *iter,
3841 GtkTextRealIter *real;
3843 gint real_char_index;
3845 g_return_if_fail (iter != NULL);
3847 real = gtk_text_iter_make_surreal (iter);
3852 check_invariants (iter);
3854 if (real->cached_char_index >= 0 &&
3855 real->cached_char_index == char_offset)
3858 line = _gtk_text_btree_get_line_at_char (real->tree,
3863 iter_set_from_char_offset (real, line, real_char_index - line_start);
3865 /* Go ahead and cache this since we have it. */
3866 real->cached_char_index = real_char_index;
3868 check_invariants (iter);
3872 * gtk_text_iter_forward_to_end:
3873 * @iter: a #GtkTextIter
3875 * Moves @iter forward to the "end iterator," which points one past the last
3876 * valid character in the buffer. gtk_text_iter_get_char() called on the
3877 * end iterator returns 0, which is convenient for writing loops.
3880 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3882 GtkTextBuffer *buffer;
3883 GtkTextRealIter *real;
3885 g_return_if_fail (iter != NULL);
3887 real = gtk_text_iter_make_surreal (iter);
3892 buffer = _gtk_text_btree_get_buffer (real->tree);
3894 gtk_text_buffer_get_end_iter (buffer, iter);
3897 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3898 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3899 * If all else fails we could cache the para delimiter pos in the iter.
3900 * I think forward_to_line_end() actually gets called fairly often.
3903 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3908 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3909 _gtk_text_iter_get_btree (&end)))
3911 gtk_text_iter_forward_to_end (&end);
3915 /* if we aren't on the last line, go forward to start of next line, then scan
3916 * back for the delimiters on the previous line
3918 gtk_text_iter_forward_line (&end);
3919 gtk_text_iter_backward_char (&end);
3920 while (!gtk_text_iter_ends_line (&end))
3921 gtk_text_iter_backward_char (&end);
3924 return gtk_text_iter_get_line_offset (&end);
3928 * gtk_text_iter_forward_to_line_end:
3929 * @iter: a #GtkTextIter
3931 * Moves the iterator to point to the paragraph delimiter characters,
3932 * which will be either a newline, a carriage return, a carriage
3933 * return/newline in sequence, or the Unicode paragraph separator
3934 * character. If the iterator is already at the paragraph delimiter
3935 * characters, moves to the paragraph delimiter characters for the
3936 * next line. If @iter is on the last line in the buffer, which does
3937 * not end in paragraph delimiters, moves to the end iterator (end of
3938 * the last line), and returns %FALSE.
3940 * Return value: %TRUE if we moved and the new location is not the end iterator
3943 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3945 gint current_offset;
3949 g_return_val_if_fail (iter != NULL, FALSE);
3951 current_offset = gtk_text_iter_get_line_offset (iter);
3952 new_offset = find_paragraph_delimiter_for_line (iter);
3954 if (current_offset < new_offset)
3956 /* Move to end of this line. */
3957 gtk_text_iter_set_line_offset (iter, new_offset);
3958 return !gtk_text_iter_is_end (iter);
3962 /* Move to end of next line. */
3963 if (gtk_text_iter_forward_line (iter))
3965 /* We don't want to move past all
3968 if (!gtk_text_iter_ends_line (iter))
3969 gtk_text_iter_forward_to_line_end (iter);
3970 return !gtk_text_iter_is_end (iter);
3978 * gtk_text_iter_forward_to_tag_toggle:
3979 * @iter: a #GtkTextIter
3980 * @tag: a #GtkTextTag, or %NULL
3982 * Moves forward to the next toggle (on or off) of the
3983 * #GtkTextTag @tag, or to the next toggle of any tag if
3984 * @tag is %NULL. If no matching tag toggles are found,
3985 * returns %FALSE, otherwise %TRUE. Does not return toggles
3986 * located at @iter, only toggles after @iter. Sets @iter to
3987 * the location of the toggle, or to the end of the buffer
3988 * if no toggle is found.
3990 * Return value: whether we found a tag toggle after @iter
3993 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3996 GtkTextLine *next_line;
3997 GtkTextLine *current_line;
3998 GtkTextRealIter *real;
4000 g_return_val_if_fail (iter != NULL, FALSE);
4002 real = gtk_text_iter_make_real (iter);
4007 check_invariants (iter);
4009 current_line = real->line;
4010 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4013 while (_gtk_text_iter_forward_indexable_segment (iter))
4015 /* If we went forward to a line that couldn't contain a toggle
4016 for the tag, then skip forward to a line that could contain
4017 it. This potentially skips huge hunks of the tree, so we
4018 aren't a purely linear search. */
4019 if (real->line != current_line)
4021 if (next_line == NULL)
4023 /* End of search. Set to end of buffer. */
4024 _gtk_text_btree_get_end_iter (real->tree, iter);
4028 if (real->line != next_line)
4029 iter_set_from_byte_offset (real, next_line, 0);
4031 current_line = real->line;
4032 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4037 if (gtk_text_iter_toggles_tag (iter, tag))
4039 /* If there's a toggle here, it isn't indexable so
4040 any_segment can't be the indexable segment. */
4041 g_assert (real->any_segment != real->segment);
4046 /* Check end iterator for tags */
4047 if (gtk_text_iter_toggles_tag (iter, tag))
4049 /* If there's a toggle here, it isn't indexable so
4050 any_segment can't be the indexable segment. */
4051 g_assert (real->any_segment != real->segment);
4055 /* Reached end of buffer */
4060 * gtk_text_iter_backward_to_tag_toggle:
4061 * @iter: a #GtkTextIter
4062 * @tag: a #GtkTextTag, or %NULL
4064 * Moves backward to the next toggle (on or off) of the
4065 * #GtkTextTag @tag, or to the next toggle of any tag if
4066 * @tag is %NULL. If no matching tag toggles are found,
4067 * returns %FALSE, otherwise %TRUE. Does not return toggles
4068 * located at @iter, only toggles before @iter. Sets @iter
4069 * to the location of the toggle, or the start of the buffer
4070 * if no toggle is found.
4072 * Return value: whether we found a tag toggle before @iter
4075 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4078 GtkTextLine *prev_line;
4079 GtkTextLine *current_line;
4080 GtkTextRealIter *real;
4082 g_return_val_if_fail (iter != NULL, FALSE);
4084 real = gtk_text_iter_make_real (iter);
4089 check_invariants (iter);
4091 current_line = real->line;
4092 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4096 /* If we're at segment start, go to the previous segment;
4097 * if mid-segment, snap to start of current segment.
4099 if (is_segment_start (real))
4101 if (!_gtk_text_iter_backward_indexable_segment (iter))
4106 ensure_char_offsets (real);
4108 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4114 /* If we went backward to a line that couldn't contain a toggle
4115 * for the tag, then skip backward further to a line that
4116 * could contain it. This potentially skips huge hunks of the
4117 * tree, so we aren't a purely linear search.
4119 if (real->line != current_line)
4121 if (prev_line == NULL)
4123 /* End of search. Set to start of buffer. */
4124 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4128 if (real->line != prev_line)
4130 /* Set to last segment in prev_line (could do this
4133 iter_set_from_byte_offset (real, prev_line, 0);
4135 while (!at_last_indexable_segment (real))
4136 _gtk_text_iter_forward_indexable_segment (iter);
4139 current_line = real->line;
4140 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4145 if (gtk_text_iter_toggles_tag (iter, tag))
4147 /* If there's a toggle here, it isn't indexable so
4148 * any_segment can't be the indexable segment.
4150 g_assert (real->any_segment != real->segment);
4154 while (_gtk_text_iter_backward_indexable_segment (iter));
4156 /* Reached front of buffer */
4161 matches_pred (GtkTextIter *iter,
4162 GtkTextCharPredicate pred,
4167 ch = gtk_text_iter_get_char (iter);
4169 return (*pred) (ch, user_data);
4173 * gtk_text_iter_forward_find_char:
4174 * @iter: a #GtkTextIter
4175 * @pred: a function to be called on each character
4176 * @user_data: user data for @pred
4177 * @limit: search limit, or %NULL for none
4179 * Advances @iter, calling @pred on each character. If
4180 * @pred returns %TRUE, returns %TRUE and stops scanning.
4181 * If @pred never returns %TRUE, @iter is set to @limit if
4182 * @limit is non-%NULL, otherwise to the end iterator.
4184 * Return value: whether a match was found
4187 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4188 GtkTextCharPredicate pred,
4190 const GtkTextIter *limit)
4192 g_return_val_if_fail (iter != NULL, FALSE);
4193 g_return_val_if_fail (pred != NULL, FALSE);
4196 gtk_text_iter_compare (iter, limit) >= 0)
4199 while ((limit == NULL ||
4200 !gtk_text_iter_equal (limit, iter)) &&
4201 gtk_text_iter_forward_char (iter))
4203 if (matches_pred (iter, pred, user_data))
4211 * gtk_text_iter_backward_find_char:
4212 * @iter: a #GtkTextIter
4213 * @pred: function to be called on each character
4214 * @user_data: user data for @pred
4215 * @limit: search limit, or %NULL for none
4217 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4219 * Return value: whether a match was found
4222 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4223 GtkTextCharPredicate pred,
4225 const GtkTextIter *limit)
4227 g_return_val_if_fail (iter != NULL, FALSE);
4228 g_return_val_if_fail (pred != NULL, FALSE);
4231 gtk_text_iter_compare (iter, limit) <= 0)
4234 while ((limit == NULL ||
4235 !gtk_text_iter_equal (limit, iter)) &&
4236 gtk_text_iter_backward_char (iter))
4238 if (matches_pred (iter, pred, user_data))
4246 forward_chars_with_skipping (GtkTextIter *iter,
4248 gboolean skip_invisible,
4249 gboolean skip_nontext)
4254 g_return_if_fail (count >= 0);
4260 gboolean ignored = FALSE;
4263 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4268 _gtk_text_btree_char_is_invisible (iter))
4271 gtk_text_iter_forward_char (iter);
4279 lines_match (const GtkTextIter *start,
4280 const gchar **lines,
4281 gboolean visible_only,
4283 GtkTextIter *match_start,
4284 GtkTextIter *match_end)
4291 if (*lines == NULL || **lines == '\0')
4294 *match_start = *start;
4297 *match_end = *start;
4302 gtk_text_iter_forward_line (&next);
4304 /* No more text in buffer, but *lines is nonempty */
4305 if (gtk_text_iter_equal (start, &next))
4313 line_text = gtk_text_iter_get_visible_slice (start, &next);
4315 line_text = gtk_text_iter_get_slice (start, &next);
4320 line_text = gtk_text_iter_get_visible_text (start, &next);
4322 line_text = gtk_text_iter_get_text (start, &next);
4325 if (match_start) /* if this is the first line we're matching */
4326 found = strstr (line_text, *lines);
4329 /* If it's not the first line, we have to match from the
4330 * start of the line.
4332 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4344 /* Get offset to start of search string */
4345 offset = g_utf8_strlen (line_text, found - line_text);
4349 /* If match start needs to be returned, set it to the
4350 * start of the search string.
4354 *match_start = next;
4356 forward_chars_with_skipping (match_start, offset,
4357 visible_only, !slice);
4360 /* Go to end of search string */
4361 offset += g_utf8_strlen (*lines, -1);
4363 forward_chars_with_skipping (&next, offset,
4364 visible_only, !slice);
4373 /* pass NULL for match_start, since we don't need to find the
4376 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4379 /* strsplit () that retains the delimiter as part of the string. */
4381 strbreakup (const char *string,
4382 const char *delimiter,
4385 GSList *string_list = NULL, *slist;
4386 gchar **str_array, *s;
4389 g_return_val_if_fail (string != NULL, NULL);
4390 g_return_val_if_fail (delimiter != NULL, NULL);
4393 max_tokens = G_MAXINT;
4395 s = strstr (string, delimiter);
4398 guint delimiter_len = strlen (delimiter);
4405 len = s - string + delimiter_len;
4406 new_string = g_new (gchar, len + 1);
4407 strncpy (new_string, string, len);
4408 new_string[len] = 0;
4409 string_list = g_slist_prepend (string_list, new_string);
4411 string = s + delimiter_len;
4412 s = strstr (string, delimiter);
4414 while (--max_tokens && s);
4419 string_list = g_slist_prepend (string_list, g_strdup (string));
4422 str_array = g_new (gchar*, n);
4426 str_array[i--] = NULL;
4427 for (slist = string_list; slist; slist = slist->next)
4428 str_array[i--] = slist->data;
4430 g_slist_free (string_list);
4436 * gtk_text_iter_forward_search:
4437 * @iter: start of search
4438 * @str: a search string
4439 * @flags: flags affecting how the search is done
4440 * @match_start: return location for start of match, or %NULL
4441 * @match_end: return location for end of match, or %NULL
4442 * @limit: bound for the search, or %NULL for the end of the buffer
4444 * Searches forward for @str. Any match is returned by setting
4445 * @match_start to the first character of the match and @match_end to the
4446 * first character after the match. The search will not continue past
4447 * @limit. Note that a search is a linear or O(n) operation, so you
4448 * may wish to use @limit to avoid locking up your UI on large
4451 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4452 * have invisible text interspersed in @str. i.e. @str will be a
4453 * possibly-noncontiguous subsequence of the matched range. similarly,
4454 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4455 * pixbufs or child widgets mixed inside the matched range. If these
4456 * flags are not given, the match must be exact; the special 0xFFFC
4457 * character in @str will match embedded pixbufs or child widgets.
4459 * Return value: whether a match was found
4462 gtk_text_iter_forward_search (const GtkTextIter *iter,
4464 GtkTextSearchFlags flags,
4465 GtkTextIter *match_start,
4466 GtkTextIter *match_end,
4467 const GtkTextIter *limit)
4469 gchar **lines = NULL;
4471 gboolean retval = FALSE;
4473 gboolean visible_only;
4476 g_return_val_if_fail (iter != NULL, FALSE);
4477 g_return_val_if_fail (str != NULL, FALSE);
4480 gtk_text_iter_compare (iter, limit) >= 0)
4485 /* If we can move one char, return the empty string there */
4488 if (gtk_text_iter_forward_char (&match))
4491 gtk_text_iter_equal (&match, limit))
4495 *match_start = match;
4504 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4505 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4507 /* locate all lines */
4509 lines = strbreakup (str, "\n", -1);
4515 /* This loop has an inefficient worst-case, where
4516 * gtk_text_iter_get_text () is called repeatedly on
4522 gtk_text_iter_compare (&search, limit) >= 0)
4525 if (lines_match (&search, (const gchar**)lines,
4526 visible_only, slice, &match, &end))
4528 if (limit == NULL ||
4530 gtk_text_iter_compare (&end, limit) < 0))
4535 *match_start = match;
4544 while (gtk_text_iter_forward_line (&search));
4546 g_strfreev ((gchar**)lines);
4552 vectors_equal_ignoring_trailing (gchar **vec1,
4555 /* Ignores trailing chars in vec2's last line */
4564 if (strcmp (*i1, *i2) != 0)
4566 if (*(i2 + 1) == NULL) /* if this is the last line */
4568 gint len1 = strlen (*i1);
4569 gint len2 = strlen (*i2);
4572 strncmp (*i1, *i2, len1) == 0)
4574 /* We matched ignoring the trailing stuff in vec2 */
4599 typedef struct _LinesWindow LinesWindow;
4605 GtkTextIter first_line_start;
4606 GtkTextIter first_line_end;
4608 gboolean visible_only;
4612 lines_window_init (LinesWindow *win,
4613 const GtkTextIter *start)
4616 GtkTextIter line_start;
4617 GtkTextIter line_end;
4619 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4622 if (gtk_text_iter_is_start (start) ||
4623 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4625 /* Already at the end, or not enough lines to match */
4626 win->lines = g_new0 (gchar*, 1);
4631 line_start = *start;
4634 /* Move to start iter to start of line */
4635 gtk_text_iter_set_line_offset (&line_start, 0);
4637 if (gtk_text_iter_equal (&line_start, &line_end))
4639 /* we were already at the start; so go back one line */
4640 gtk_text_iter_backward_line (&line_start);
4643 win->first_line_start = line_start;
4644 win->first_line_end = line_end;
4646 win->lines = g_new0 (gchar*, win->n_lines + 1);
4648 i = win->n_lines - 1;
4655 if (win->visible_only)
4656 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4658 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4662 if (win->visible_only)
4663 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4665 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4668 win->lines[i] = line_text;
4670 line_end = line_start;
4671 gtk_text_iter_backward_line (&line_start);
4678 lines_window_back (LinesWindow *win)
4680 GtkTextIter new_start;
4683 new_start = win->first_line_start;
4685 if (!gtk_text_iter_backward_line (&new_start))
4689 win->first_line_start = new_start;
4690 win->first_line_end = new_start;
4692 gtk_text_iter_forward_line (&win->first_line_end);
4697 if (win->visible_only)
4698 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4699 &win->first_line_end);
4701 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4702 &win->first_line_end);
4706 if (win->visible_only)
4707 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4708 &win->first_line_end);
4710 line_text = gtk_text_iter_get_text (&win->first_line_start,
4711 &win->first_line_end);
4714 /* Move lines to make room for first line. */
4715 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4717 *win->lines = line_text;
4719 /* Free old last line and NULL-terminate */
4720 g_free (win->lines[win->n_lines]);
4721 win->lines[win->n_lines] = NULL;
4727 lines_window_free (LinesWindow *win)
4729 g_strfreev (win->lines);
4733 * gtk_text_iter_backward_search:
4734 * @iter: a #GtkTextIter where the search begins
4735 * @str: search string
4736 * @flags: bitmask of flags affecting the search
4737 * @match_start: return location for start of match, or %NULL
4738 * @match_end: return location for end of match, or %NULL
4739 * @limit: location of last possible @match_start, or %NULL for start of buffer
4741 * Same as gtk_text_iter_forward_search(), but moves backward.
4743 * Return value: whether a match was found
4746 gtk_text_iter_backward_search (const GtkTextIter *iter,
4748 GtkTextSearchFlags flags,
4749 GtkTextIter *match_start,
4750 GtkTextIter *match_end,
4751 const GtkTextIter *limit)
4753 gchar **lines = NULL;
4757 gboolean retval = FALSE;
4758 gboolean visible_only;
4761 g_return_val_if_fail (iter != NULL, FALSE);
4762 g_return_val_if_fail (str != NULL, FALSE);
4765 gtk_text_iter_compare (limit, iter) > 0)
4770 /* If we can move one char, return the empty string there */
4771 GtkTextIter match = *iter;
4773 if (limit && gtk_text_iter_equal (limit, &match))
4776 if (gtk_text_iter_backward_char (&match))
4779 *match_start = match;
4788 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4789 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4791 /* locate all lines */
4793 lines = strbreakup (str, "\n", -1);
4803 win.n_lines = n_lines;
4805 win.visible_only = visible_only;
4807 lines_window_init (&win, iter);
4809 if (*win.lines == NULL)
4814 gchar *first_line_match;
4817 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4819 /* We're now before the search limit, abort. */
4823 /* If there are multiple lines, the first line will
4824 * end in '\n', so this will only match at the
4825 * end of the first line, which is correct.
4827 first_line_match = g_strrstr (*win.lines, *lines);
4829 if (first_line_match &&
4830 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4835 GtkTextIter start_tmp;
4837 /* Offset to start of search string */
4838 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4840 next = win.first_line_start;
4842 forward_chars_with_skipping (&start_tmp, offset,
4843 visible_only, !slice);
4846 gtk_text_iter_compare (limit, &start_tmp) > 0)
4847 goto out; /* match was bogus */
4850 *match_start = start_tmp;
4852 /* Go to end of search string */
4856 offset += g_utf8_strlen (*l, -1);
4860 forward_chars_with_skipping (&next, offset,
4861 visible_only, !slice);
4870 while (lines_window_back (&win));
4873 lines_window_free (&win);
4884 * gtk_text_iter_equal:
4885 * @lhs: a #GtkTextIter
4886 * @rhs: another #GtkTextIter
4888 * Tests whether two iterators are equal, using the fastest possible
4889 * mechanism. This function is very fast; you can expect it to perform
4890 * better than e.g. getting the character offset for each iterator and
4891 * comparing the offsets yourself. Also, it's a bit faster than
4892 * gtk_text_iter_compare().
4894 * Return value: %TRUE if the iterators point to the same place in the buffer
4897 gtk_text_iter_equal (const GtkTextIter *lhs,
4898 const GtkTextIter *rhs)
4900 GtkTextRealIter *real_lhs;
4901 GtkTextRealIter *real_rhs;
4903 real_lhs = (GtkTextRealIter*)lhs;
4904 real_rhs = (GtkTextRealIter*)rhs;
4906 check_invariants (lhs);
4907 check_invariants (rhs);
4909 if (real_lhs->line != real_rhs->line)
4911 else if (real_lhs->line_byte_offset >= 0 &&
4912 real_rhs->line_byte_offset >= 0)
4913 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4916 /* the ensure_char_offsets () calls do nothing if the char offsets
4917 are already up-to-date. */
4918 ensure_char_offsets (real_lhs);
4919 ensure_char_offsets (real_rhs);
4920 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4925 * gtk_text_iter_compare:
4926 * @lhs: a #GtkTextIter
4927 * @rhs: another #GtkTextIter
4929 * A qsort()-style function that returns negative if @lhs is less than
4930 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4931 * Ordering is in character offset order, i.e. the first character in the buffer
4932 * is less than the second character in the buffer.
4934 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4937 gtk_text_iter_compare (const GtkTextIter *lhs,
4938 const GtkTextIter *rhs)
4940 GtkTextRealIter *real_lhs;
4941 GtkTextRealIter *real_rhs;
4943 real_lhs = gtk_text_iter_make_surreal (lhs);
4944 real_rhs = gtk_text_iter_make_surreal (rhs);
4946 if (real_lhs == NULL ||
4948 return -1; /* why not */
4950 check_invariants (lhs);
4951 check_invariants (rhs);
4953 if (real_lhs->line == real_rhs->line)
4955 gint left_index, right_index;
4957 if (real_lhs->line_byte_offset >= 0 &&
4958 real_rhs->line_byte_offset >= 0)
4960 left_index = real_lhs->line_byte_offset;
4961 right_index = real_rhs->line_byte_offset;
4965 /* the ensure_char_offsets () calls do nothing if
4966 the offsets are already up-to-date. */
4967 ensure_char_offsets (real_lhs);
4968 ensure_char_offsets (real_rhs);
4969 left_index = real_lhs->line_char_offset;
4970 right_index = real_rhs->line_char_offset;
4973 if (left_index < right_index)
4975 else if (left_index > right_index)
4984 line1 = gtk_text_iter_get_line (lhs);
4985 line2 = gtk_text_iter_get_line (rhs);
4988 else if (line1 > line2)
4996 * gtk_text_iter_in_range:
4997 * @iter: a #GtkTextIter
4998 * @start: start of range
4999 * @end: end of range
5001 * Checks whether @iter falls in the range [@start, @end).
5002 * @start and @end must be in ascending order.
5004 * Return value: %TRUE if @iter is in the range
5007 gtk_text_iter_in_range (const GtkTextIter *iter,
5008 const GtkTextIter *start,
5009 const GtkTextIter *end)
5011 g_return_val_if_fail (iter != NULL, FALSE);
5012 g_return_val_if_fail (start != NULL, FALSE);
5013 g_return_val_if_fail (end != NULL, FALSE);
5014 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5016 return gtk_text_iter_compare (iter, start) >= 0 &&
5017 gtk_text_iter_compare (iter, end) < 0;
5021 * gtk_text_iter_order:
5022 * @first: a #GtkTextIter
5023 * @second: another #GtkTextIter
5025 * Swaps the value of @first and @second if @second comes before
5026 * @first in the buffer. That is, ensures that @first and @second are
5027 * in sequence. Most text buffer functions that take a range call this
5028 * automatically on your behalf, so there's no real reason to call it yourself
5029 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5030 * that expect a pre-sorted range.
5034 gtk_text_iter_order (GtkTextIter *first,
5035 GtkTextIter *second)
5037 g_return_if_fail (first != NULL);
5038 g_return_if_fail (second != NULL);
5040 if (gtk_text_iter_compare (first, second) > 0)
5051 * Init iterators from the BTree
5055 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5059 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5060 gint real_char_index;
5064 g_return_if_fail (iter != NULL);
5065 g_return_if_fail (tree != NULL);
5067 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5068 &line_start, &real_char_index);
5070 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5072 real->cached_char_index = real_char_index;
5074 check_invariants (iter);
5078 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5083 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5087 g_return_if_fail (iter != NULL);
5088 g_return_if_fail (tree != NULL);
5090 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5092 iter_init_from_char_offset (iter, tree, line, char_on_line);
5094 /* We might as well cache this, since we know it. */
5095 real->cached_line_number = real_line;
5097 check_invariants (iter);
5101 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5106 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5110 g_return_if_fail (iter != NULL);
5111 g_return_if_fail (tree != NULL);
5113 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5115 iter_init_from_byte_offset (iter, tree, line, byte_index);
5117 /* We might as well cache this, since we know it. */
5118 real->cached_line_number = real_line;
5120 check_invariants (iter);
5124 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5129 g_return_if_fail (iter != NULL);
5130 g_return_if_fail (tree != NULL);
5131 g_return_if_fail (line != NULL);
5133 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5135 check_invariants (iter);
5139 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5145 g_return_val_if_fail (iter != NULL, FALSE);
5146 g_return_val_if_fail (tree != NULL, FALSE);
5148 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5152 /* Set iter to last in tree */
5153 _gtk_text_btree_get_end_iter (tree, iter);
5154 check_invariants (iter);
5159 iter_init_from_byte_offset (iter, tree, line, 0);
5161 if (!gtk_text_iter_toggles_tag (iter, tag))
5162 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5164 check_invariants (iter);
5170 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5174 g_return_val_if_fail (iter != NULL, FALSE);
5175 g_return_val_if_fail (tree != NULL, FALSE);
5177 _gtk_text_btree_get_end_iter (tree, iter);
5178 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5179 check_invariants (iter);
5185 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5187 const gchar *mark_name)
5191 g_return_val_if_fail (iter != NULL, FALSE);
5192 g_return_val_if_fail (tree != NULL, FALSE);
5194 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5200 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5201 check_invariants (iter);
5207 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5211 GtkTextLineSegment *seg;
5213 g_return_if_fail (iter != NULL);
5214 g_return_if_fail (tree != NULL);
5215 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5217 seg = mark->segment;
5219 iter_init_from_segment (iter, tree,
5220 seg->body.mark.line, seg);
5221 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5222 check_invariants (iter);
5226 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5228 GtkTextChildAnchor *anchor)
5230 GtkTextLineSegment *seg;
5232 g_return_if_fail (iter != NULL);
5233 g_return_if_fail (tree != NULL);
5234 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5236 seg = anchor->segment;
5238 g_assert (seg->body.child.line != NULL);
5240 iter_init_from_segment (iter, tree,
5241 seg->body.child.line, seg);
5242 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5243 check_invariants (iter);
5247 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5250 g_return_if_fail (iter != NULL);
5251 g_return_if_fail (tree != NULL);
5253 _gtk_text_btree_get_iter_at_char (tree,
5255 _gtk_text_btree_char_count (tree));
5256 check_invariants (iter);
5260 _gtk_text_iter_check (const GtkTextIter *iter)
5262 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5263 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5264 GtkTextLineSegment *byte_segment = NULL;
5265 GtkTextLineSegment *byte_any_segment = NULL;
5266 GtkTextLineSegment *char_segment = NULL;
5267 GtkTextLineSegment *char_any_segment = NULL;
5268 gboolean segments_updated;
5270 /* This function checks our class invariants for the Iter class. */
5272 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5274 if (real->chars_changed_stamp !=
5275 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5276 g_error ("iterator check failed: invalid iterator");
5278 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5279 g_error ("iterator check failed: both char and byte offsets are invalid");
5281 segments_updated = (real->segments_changed_stamp ==
5282 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5285 printf ("checking iter, segments %s updated, byte %d char %d\n",
5286 segments_updated ? "are" : "aren't",
5287 real->line_byte_offset,
5288 real->line_char_offset);
5291 if (segments_updated)
5293 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5294 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5296 if (real->segment->char_count == 0)
5297 g_error ("iterator check failed: segment is not indexable.");
5299 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5300 g_error ("segment char offset is not properly up-to-date");
5302 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5303 g_error ("segment byte offset is not properly up-to-date");
5305 if (real->segment_byte_offset >= 0 &&
5306 real->segment_byte_offset >= real->segment->byte_count)
5307 g_error ("segment byte offset is too large.");
5309 if (real->segment_char_offset >= 0 &&
5310 real->segment_char_offset >= real->segment->char_count)
5311 g_error ("segment char offset is too large.");
5314 if (real->line_byte_offset >= 0)
5316 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5317 &byte_segment, &byte_any_segment,
5318 &seg_byte_offset, &line_byte_offset);
5320 if (line_byte_offset != real->line_byte_offset)
5321 g_error ("wrong byte offset was stored in iterator");
5323 if (segments_updated)
5325 if (real->segment != byte_segment)
5326 g_error ("wrong segment was stored in iterator");
5328 if (real->any_segment != byte_any_segment)
5329 g_error ("wrong any_segment was stored in iterator");
5331 if (seg_byte_offset != real->segment_byte_offset)
5332 g_error ("wrong segment byte offset was stored in iterator");
5334 if (byte_segment->type == >k_text_char_type)
5337 p = byte_segment->body.chars + seg_byte_offset;
5339 if (!gtk_text_byte_begins_utf8_char (p))
5340 g_error ("broken iterator byte index pointed into the middle of a character");
5345 if (real->line_char_offset >= 0)
5347 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5348 &char_segment, &char_any_segment,
5349 &seg_char_offset, &line_char_offset);
5351 if (line_char_offset != real->line_char_offset)
5352 g_error ("wrong char offset was stored in iterator");
5354 if (segments_updated)
5356 if (real->segment != char_segment)
5357 g_error ("wrong segment was stored in iterator");
5359 if (real->any_segment != char_any_segment)
5360 g_error ("wrong any_segment was stored in iterator");
5362 if (seg_char_offset != real->segment_char_offset)
5363 g_error ("wrong segment char offset was stored in iterator");
5365 if (char_segment->type == >k_text_char_type)
5368 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5371 /* hmm, not likely to happen eh */
5372 if (!gtk_text_byte_begins_utf8_char (p))
5373 g_error ("broken iterator char offset pointed into the middle of a character");
5378 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5380 if (byte_segment != char_segment)
5381 g_error ("char and byte offsets did not point to the same segment");
5383 if (byte_any_segment != char_any_segment)
5384 g_error ("char and byte offsets did not point to the same any segment");
5386 /* Make sure the segment offsets are equivalent, if it's a char
5388 if (char_segment->type == >k_text_char_type)
5390 gint byte_offset = 0;
5391 gint char_offset = 0;
5392 while (char_offset < seg_char_offset)
5394 const char * start = char_segment->body.chars + byte_offset;
5395 byte_offset += g_utf8_next_char (start) - start;
5399 if (byte_offset != seg_byte_offset)
5400 g_error ("byte offset did not correspond to char offset");
5403 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5405 if (char_offset != seg_char_offset)
5406 g_error ("char offset did not correspond to byte offset");
5408 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5409 g_error ("byte index for iterator does not index the start of a character");
5413 if (real->cached_line_number >= 0)
5417 should_be = _gtk_text_line_get_number (real->line);
5418 if (real->cached_line_number != should_be)
5419 g_error ("wrong line number was cached");
5422 if (real->cached_char_index >= 0)
5424 if (real->line_char_offset >= 0) /* only way we can check it
5425 efficiently, not a real
5430 char_index = _gtk_text_line_char_index (real->line);
5431 char_index += real->line_char_offset;
5433 if (real->cached_char_index != char_index)
5434 g_error ("wrong char index was cached");
5438 if (_gtk_text_line_is_last (real->line, real->tree))
5439 g_error ("Iterator was on last line (past the end iterator)");