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))
2808 return attrs[offset].is_word_start;
2813 /* Sentence funcs */
2816 find_sentence_end_func (const PangoLogAttr *attrs,
2821 gboolean already_moved_initially)
2823 if (!already_moved_initially)
2826 /* Find end of next sentence */
2827 while (offset < min_offset + len &&
2828 !attrs[offset].is_sentence_end)
2831 *found_offset = offset;
2833 return offset < min_offset + len;
2837 is_sentence_end_func (const PangoLogAttr *attrs,
2842 return attrs[offset].is_sentence_end;
2846 find_sentence_start_func (const PangoLogAttr *attrs,
2851 gboolean already_moved_initially)
2853 if (!already_moved_initially)
2856 /* Find start of prev sentence */
2857 while (offset >= min_offset &&
2858 !attrs[offset].is_sentence_start)
2861 *found_offset = offset;
2863 return offset >= min_offset;
2867 is_sentence_start_func (const PangoLogAttr *attrs,
2872 return attrs[offset].is_sentence_start;
2876 inside_sentence_func (const PangoLogAttr *attrs,
2881 /* Find next sentence start or end */
2882 while (offset >= min_offset &&
2883 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2886 return attrs[offset].is_sentence_start;
2890 test_log_attrs (const GtkTextIter *iter,
2891 TestLogAttrFunc func)
2894 const PangoLogAttr *attrs;
2896 gboolean result = FALSE;
2898 g_return_val_if_fail (iter != NULL, FALSE);
2900 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2903 offset = gtk_text_iter_get_line_offset (iter);
2905 /* char_len may be 0 and attrs will be NULL if so, if
2906 * iter is the end iter and the last line is empty.
2908 * offset may be equal to char_len, since attrs contains an entry
2909 * for one past the end
2912 if (attrs && offset <= char_len)
2913 result = (* func) (attrs, offset, 0, char_len);
2919 find_line_log_attrs (const GtkTextIter *iter,
2920 FindLogAttrFunc func,
2922 gboolean already_moved_initially)
2925 const PangoLogAttr *attrs;
2927 gboolean result = FALSE;
2929 g_return_val_if_fail (iter != NULL, FALSE);
2931 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2934 offset = gtk_text_iter_get_line_offset (iter);
2936 /* char_len may be 0 and attrs will be NULL if so, if
2937 * iter is the end iter and the last line is empty
2941 result = (* func) (attrs, offset, 0, char_len, found_offset,
2942 already_moved_initially);
2947 /* FIXME this function is very, very gratuitously slow */
2949 find_by_log_attrs (GtkTextIter *iter,
2950 FindLogAttrFunc func,
2952 gboolean already_moved_initially)
2956 gboolean found = FALSE;
2958 g_return_val_if_fail (iter != NULL, FALSE);
2962 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2968 if (gtk_text_iter_forward_line (iter))
2969 return find_by_log_attrs (iter, func, forward,
2976 /* go to end of previous line. need to check that
2977 * line is > 0 because backward_line snaps to start of
2978 * line 0 if it's on line 0
2980 if (gtk_text_iter_get_line (iter) > 0 &&
2981 gtk_text_iter_backward_line (iter))
2983 if (!gtk_text_iter_ends_line (iter))
2984 gtk_text_iter_forward_to_line_end (iter);
2986 return find_by_log_attrs (iter, func, forward,
2995 gtk_text_iter_set_line_offset (iter, offset);
2998 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2999 !gtk_text_iter_is_end (iter);
3004 find_visible_by_log_attrs (GtkTextIter *iter,
3005 FindLogAttrFunc func,
3007 gboolean already_moved_initially)
3011 g_return_val_if_fail (iter != NULL, FALSE);
3015 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3017 if (!_gtk_text_btree_char_is_invisible (&pos))
3027 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3028 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3031 move_multiple_steps (GtkTextIter *iter,
3033 OneStepFunc step_forward,
3034 MultipleStepFunc n_steps_backward)
3036 g_return_val_if_fail (iter != NULL, FALSE);
3038 FIX_OVERFLOWS (count);
3044 return n_steps_backward (iter, -count);
3046 if (!step_forward (iter))
3052 if (!step_forward (iter))
3057 return !gtk_text_iter_is_end (iter);
3062 * gtk_text_iter_forward_word_end:
3063 * @iter: a #GtkTextIter
3065 * Moves forward to the next word end. (If @iter is currently on a
3066 * word end, moves forward to the next one after that.) Word breaks
3067 * are determined by Pango and should be correct for nearly any
3068 * language (if not, the correct fix would be to the Pango word break
3071 * Return value: %TRUE if @iter moved and is not the end iterator
3074 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3076 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3080 * gtk_text_iter_backward_word_start:
3081 * @iter: a #GtkTextIter
3083 * Moves backward to the previous word start. (If @iter is currently on a
3084 * word start, moves backward to the next one after that.) Word breaks
3085 * are determined by Pango and should be correct for nearly any
3086 * language (if not, the correct fix would be to the Pango word break
3089 * Return value: %TRUE if @iter moved and is not the end iterator
3092 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3094 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3097 /* FIXME a loop around a truly slow function means
3098 * a truly spectacularly slow function.
3102 * gtk_text_iter_forward_word_ends:
3103 * @iter: a #GtkTextIter
3104 * @count: number of times to move
3106 * Calls gtk_text_iter_forward_word_end() up to @count times.
3108 * Return value: %TRUE if @iter moved and is not the end iterator
3111 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3114 return move_multiple_steps (iter, count,
3115 gtk_text_iter_forward_word_end,
3116 gtk_text_iter_backward_word_starts);
3120 * gtk_text_iter_backward_word_starts
3121 * @iter: a #GtkTextIter
3122 * @count: number of times to move
3124 * Calls gtk_text_iter_backward_word_start() up to @count times.
3126 * Return value: %TRUE if @iter moved and is not the end iterator
3129 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3132 return move_multiple_steps (iter, count,
3133 gtk_text_iter_backward_word_start,
3134 gtk_text_iter_forward_word_ends);
3138 * gtk_text_iter_forward_visible_word_end:
3139 * @iter: a #GtkTextIter
3141 * Moves forward to the next visible word end. (If @iter is currently on a
3142 * word end, moves forward to the next one after that.) Word breaks
3143 * are determined by Pango and should be correct for nearly any
3144 * language (if not, the correct fix would be to the Pango word break
3147 * Return value: %TRUE if @iter moved and is not the end iterator
3152 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3154 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3158 * gtk_text_iter_backward_visible_word_start:
3159 * @iter: a #GtkTextIter
3161 * Moves backward to the previous visible word start. (If @iter is currently
3162 * on a word start, moves backward to the next one after that.) Word breaks
3163 * are determined by Pango and should be correct for nearly any
3164 * language (if not, the correct fix would be to the Pango word break
3167 * Return value: %TRUE if @iter moved and is not the end iterator
3172 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3174 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3178 * gtk_text_iter_forward_visible_word_ends:
3179 * @iter: a #GtkTextIter
3180 * @count: number of times to move
3182 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3184 * Return value: %TRUE if @iter moved and is not the end iterator
3189 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3192 return move_multiple_steps (iter, count,
3193 gtk_text_iter_forward_visible_word_end,
3194 gtk_text_iter_backward_visible_word_starts);
3198 * gtk_text_iter_backward_visible_word_starts
3199 * @iter: a #GtkTextIter
3200 * @count: number of times to move
3202 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3204 * Return value: %TRUE if @iter moved and is not the end iterator
3209 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3212 return move_multiple_steps (iter, count,
3213 gtk_text_iter_backward_visible_word_start,
3214 gtk_text_iter_forward_visible_word_ends);
3218 * gtk_text_iter_starts_word:
3219 * @iter: a #GtkTextIter
3221 * Determines whether @iter begins a natural-language word. Word
3222 * breaks are determined by Pango and should be correct for nearly any
3223 * language (if not, the correct fix would be to the Pango word break
3226 * Return value: %TRUE if @iter is at the start of a word
3229 gtk_text_iter_starts_word (const GtkTextIter *iter)
3231 return test_log_attrs (iter, is_word_start_func);
3235 * gtk_text_iter_ends_word:
3236 * @iter: a #GtkTextIter
3238 * Determines whether @iter ends a natural-language word. Word breaks
3239 * are determined by Pango and should be correct for nearly any
3240 * language (if not, the correct fix would be to the Pango word break
3243 * Return value: %TRUE if @iter is at the end of a word
3246 gtk_text_iter_ends_word (const GtkTextIter *iter)
3248 return test_log_attrs (iter, is_word_end_func);
3252 * gtk_text_iter_inside_word:
3253 * @iter: a #GtkTextIter
3255 * Determines whether @iter is inside a natural-language word (as
3256 * opposed to say inside some whitespace). Word breaks are determined
3257 * by Pango and should be correct for nearly any language (if not, the
3258 * correct fix would be to the Pango word break algorithms).
3260 * Return value: %TRUE if @iter is inside a word
3263 gtk_text_iter_inside_word (const GtkTextIter *iter)
3265 return test_log_attrs (iter, inside_word_func);
3269 * gtk_text_iter_starts_sentence:
3270 * @iter: a #GtkTextIter
3272 * Determines whether @iter begins a sentence. Sentence boundaries are
3273 * determined by Pango and should be correct for nearly any language
3274 * (if not, the correct fix would be to the Pango text boundary
3277 * Return value: %TRUE if @iter is at the start of a sentence.
3280 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3282 return test_log_attrs (iter, is_sentence_start_func);
3286 * gtk_text_iter_ends_sentence:
3287 * @iter: a #GtkTextIter
3289 * Determines whether @iter ends a sentence. Sentence boundaries are
3290 * determined by Pango and should be correct for nearly any language
3291 * (if not, the correct fix would be to the Pango text boundary
3294 * Return value: %TRUE if @iter is at the end of a sentence.
3297 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3299 return test_log_attrs (iter, is_sentence_end_func);
3303 * gtk_text_iter_inside_sentence:
3304 * @iter: a #GtkTextIter
3306 * Determines whether @iter is inside a sentence (as opposed to in
3307 * between two sentences, e.g. after a period and before the first
3308 * letter of the next sentence). Sentence boundaries are determined
3309 * by Pango and should be correct for nearly any language (if not, the
3310 * correct fix would be to the Pango text boundary algorithms).
3312 * Return value: %TRUE if @iter is inside a sentence.
3315 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3317 return test_log_attrs (iter, inside_sentence_func);
3321 * gtk_text_iter_forward_sentence_end:
3322 * @iter: a #GtkTextIter
3324 * Moves forward to the next sentence end. (If @iter is at the end of
3325 * a sentence, moves to the next end of sentence.) Sentence
3326 * boundaries are determined by Pango and should be correct for nearly
3327 * any language (if not, the correct fix would be to the Pango text
3328 * boundary algorithms).
3330 * Return value: %TRUE if @iter moved and is not the end iterator
3333 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3335 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3339 * gtk_text_iter_backward_sentence_start:
3340 * @iter: a #GtkTextIter
3342 * Moves backward to the previous sentence start; if @iter is already at
3343 * the start of a sentence, moves backward to the next one. Sentence
3344 * boundaries are determined by Pango and should be correct for nearly
3345 * any language (if not, the correct fix would be to the Pango text
3346 * boundary algorithms).
3348 * Return value: %TRUE if @iter moved and is not the end iterator
3351 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3353 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3356 /* FIXME a loop around a truly slow function means
3357 * a truly spectacularly slow function.
3360 * gtk_text_iter_forward_sentence_ends:
3361 * @iter: a #GtkTextIter
3362 * @count: number of sentences to move
3364 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3365 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3366 * negative, moves backward instead of forward.
3368 * Return value: %TRUE if @iter moved and is not the end iterator
3371 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3374 return move_multiple_steps (iter, count,
3375 gtk_text_iter_forward_sentence_end,
3376 gtk_text_iter_backward_sentence_starts);
3380 * gtk_text_iter_backward_sentence_starts:
3381 * @iter: a #GtkTextIter
3382 * @count: number of sentences to move
3384 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3385 * or until it returns %FALSE. If @count is negative, moves forward
3386 * instead of backward.
3388 * Return value: %TRUE if @iter moved and is not the end iterator
3391 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3394 return move_multiple_steps (iter, count,
3395 gtk_text_iter_backward_sentence_start,
3396 gtk_text_iter_forward_sentence_ends);
3400 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3405 gboolean already_moved_initially)
3407 if (!already_moved_initially)
3410 while (offset < (min_offset + len) &&
3411 !attrs[offset].is_cursor_position)
3414 *found_offset = offset;
3416 return offset < (min_offset + len);
3420 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3425 gboolean already_moved_initially)
3427 if (!already_moved_initially)
3430 while (offset > min_offset &&
3431 !attrs[offset].is_cursor_position)
3434 *found_offset = offset;
3436 return offset >= min_offset;
3440 is_cursor_pos_func (const PangoLogAttr *attrs,
3445 return attrs[offset].is_cursor_position;
3449 * gtk_text_iter_forward_cursor_position:
3450 * @iter: a #GtkTextIter
3452 * Moves @iter forward by a single cursor position. Cursor positions
3453 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3454 * surprisingly, there may not be a cursor position between all
3455 * characters. The most common example for European languages would be
3456 * a carriage return/newline sequence. For some Unicode characters,
3457 * the equivalent of say the letter "a" with an accent mark will be
3458 * represented as two characters, first the letter then a "combining
3459 * mark" that causes the accent to be rendered; so the cursor can't go
3460 * between those two characters. See also the #PangoLogAttr structure and
3461 * pango_break() function.
3463 * Return value: %TRUE if we moved and the new position is dereferenceable
3466 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3468 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3472 * gtk_text_iter_backward_cursor_position:
3473 * @iter: a #GtkTextIter
3475 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3477 * Return value: %TRUE if we moved
3480 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3482 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3486 * gtk_text_iter_forward_cursor_positions:
3487 * @iter: a #GtkTextIter
3488 * @count: number of positions to move
3490 * Moves up to @count cursor positions. See
3491 * gtk_text_iter_forward_cursor_position() for details.
3493 * Return value: %TRUE if we moved and the new position is dereferenceable
3496 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3499 return move_multiple_steps (iter, count,
3500 gtk_text_iter_forward_cursor_position,
3501 gtk_text_iter_backward_cursor_positions);
3505 * gtk_text_iter_backward_cursor_positions:
3506 * @iter: a #GtkTextIter
3507 * @count: number of positions to move
3509 * Moves up to @count cursor positions. See
3510 * gtk_text_iter_forward_cursor_position() for details.
3512 * Return value: %TRUE if we moved and the new position is dereferenceable
3515 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3518 return move_multiple_steps (iter, count,
3519 gtk_text_iter_backward_cursor_position,
3520 gtk_text_iter_forward_cursor_positions);
3524 * gtk_text_iter_forward_visible_cursor_position:
3525 * @iter: a #GtkTextIter
3527 * Moves @iter forward to the next visible cursor position. See
3528 * gtk_text_iter_forward_cursor_position() for details.
3530 * Return value: %TRUE if we moved and the new position is dereferenceable
3535 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3537 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3541 * gtk_text_iter_backward_visible_cursor_position:
3542 * @iter: a #GtkTextIter
3544 * Moves @iter forward to the previous visible cursor position. See
3545 * gtk_text_iter_backward_cursor_position() for details.
3547 * Return value: %TRUE if we moved and the new position is dereferenceable
3552 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3554 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3558 * gtk_text_iter_forward_visible_cursor_positions:
3559 * @iter: a #GtkTextIter
3560 * @count: number of positions to move
3562 * Moves up to @count visible cursor positions. See
3563 * gtk_text_iter_forward_cursor_position() for details.
3565 * Return value: %TRUE if we moved and the new position is dereferenceable
3570 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3573 return move_multiple_steps (iter, count,
3574 gtk_text_iter_forward_visible_cursor_position,
3575 gtk_text_iter_backward_visible_cursor_positions);
3579 * gtk_text_iter_backward_visible_cursor_positions:
3580 * @iter: a #GtkTextIter
3581 * @count: number of positions to move
3583 * Moves up to @count visible cursor positions. See
3584 * gtk_text_iter_forward_cursor_position() for details.
3586 * Return value: %TRUE if we moved and the new position is dereferenceable
3591 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3594 return move_multiple_steps (iter, count,
3595 gtk_text_iter_backward_visible_cursor_position,
3596 gtk_text_iter_forward_visible_cursor_positions);
3600 * gtk_text_iter_is_cursor_position:
3601 * @iter: a #GtkTextIter
3603 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3604 * pango_break() for details on what a cursor position is.
3606 * Return value: %TRUE if the cursor can be placed at @iter
3609 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3611 return test_log_attrs (iter, is_cursor_pos_func);
3615 * gtk_text_iter_set_line_offset:
3616 * @iter: a #GtkTextIter
3617 * @char_on_line: a character offset relative to the start of @iter's current line
3619 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3620 * (not byte) offset. The given character offset must be less than or
3621 * equal to the number of characters in the line; if equal, @iter
3622 * moves to the start of the next line. See
3623 * gtk_text_iter_set_line_index() if you have a byte index rather than
3624 * a character offset.
3628 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3631 GtkTextRealIter *real;
3634 g_return_if_fail (iter != NULL);
3636 real = gtk_text_iter_make_surreal (iter);
3641 check_invariants (iter);
3643 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3645 g_return_if_fail (char_on_line <= chars_in_line);
3647 if (char_on_line < chars_in_line)
3648 iter_set_from_char_offset (real, real->line, char_on_line);
3650 gtk_text_iter_forward_line (iter); /* set to start of next line */
3652 check_invariants (iter);
3656 * gtk_text_iter_set_line_index:
3657 * @iter: a #GtkTextIter
3658 * @byte_on_line: a byte index relative to the start of @iter's current line
3660 * Same as gtk_text_iter_set_line_offset(), but works with a
3661 * <emphasis>byte</emphasis> index. The given byte index must be at
3662 * the start of a character, it can't be in the middle of a UTF-8
3663 * encoded character.
3667 gtk_text_iter_set_line_index (GtkTextIter *iter,
3670 GtkTextRealIter *real;
3673 g_return_if_fail (iter != NULL);
3675 real = gtk_text_iter_make_surreal (iter);
3680 check_invariants (iter);
3682 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3684 g_return_if_fail (byte_on_line <= bytes_in_line);
3686 if (byte_on_line < bytes_in_line)
3687 iter_set_from_byte_offset (real, real->line, byte_on_line);
3689 gtk_text_iter_forward_line (iter);
3691 if (real->segment->type == >k_text_char_type &&
3692 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3693 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3694 "character; this will crash the text buffer. "
3695 "Byte indexes must refer to the start of a character.",
3696 G_STRLOC, byte_on_line);
3698 check_invariants (iter);
3703 * gtk_text_iter_set_visible_line_offset:
3704 * @iter: a #GtkTextIter
3705 * @char_on_line: a character offset
3707 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3708 * characters, i.e. text with a tag making it invisible is not
3709 * counted in the offset.
3712 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3715 gint chars_seen = 0;
3718 g_return_if_fail (iter != NULL);
3720 gtk_text_iter_set_line_offset (iter, 0);
3724 /* For now we use a ludicrously slow implementation */
3725 while (chars_seen < char_on_line)
3727 if (!_gtk_text_btree_char_is_invisible (&pos))
3730 if (!gtk_text_iter_forward_char (&pos))
3733 if (chars_seen == char_on_line)
3737 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3740 gtk_text_iter_forward_line (iter);
3744 bytes_in_char (GtkTextIter *iter)
3746 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3750 * gtk_text_iter_set_visible_line_index:
3751 * @iter: a #GtkTextIter
3752 * @byte_on_line: a byte index
3754 * Like gtk_text_iter_set_line_index(), but the index is in visible
3755 * bytes, i.e. text with a tag making it invisible is not counted
3759 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3762 gint bytes_seen = 0;
3766 g_return_if_fail (iter != NULL);
3768 gtk_text_iter_set_line_offset (iter, 0);
3772 /* For now we use a ludicrously slow implementation */
3773 while (bytes_seen < byte_on_line)
3775 if (!_gtk_text_btree_char_is_invisible (&pos))
3776 bytes_seen += bytes_in_char (&pos);
3779 if (!gtk_text_iter_forward_char (&pos))
3782 if (bytes_seen >= byte_on_line)
3786 if (bytes_seen > byte_on_line)
3787 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3788 "character; this will crash the text buffer. "
3789 "Byte indexes must refer to the start of a character.",
3790 G_STRLOC, byte_on_line);
3792 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3795 gtk_text_iter_forward_line (iter);
3799 * gtk_text_iter_set_line:
3800 * @iter: a #GtkTextIter
3801 * @line_number: line number (counted from 0)
3803 * Moves iterator @iter to the start of the line @line_number. If
3804 * @line_number is negative or larger than the number of lines in the
3805 * buffer, moves @iter to the start of the last line in the buffer.
3809 gtk_text_iter_set_line (GtkTextIter *iter,
3814 GtkTextRealIter *real;
3816 g_return_if_fail (iter != NULL);
3818 real = gtk_text_iter_make_surreal (iter);
3823 check_invariants (iter);
3825 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3827 iter_set_from_char_offset (real, line, 0);
3829 /* We might as well cache this, since we know it. */
3830 real->cached_line_number = real_line;
3832 check_invariants (iter);
3836 * gtk_text_iter_set_offset:
3837 * @iter: a #GtkTextIter
3838 * @char_offset: a character number
3840 * Sets @iter to point to @char_offset. @char_offset counts from the start
3841 * of the entire text buffer, starting with 0.
3844 gtk_text_iter_set_offset (GtkTextIter *iter,
3848 GtkTextRealIter *real;
3850 gint real_char_index;
3852 g_return_if_fail (iter != NULL);
3854 real = gtk_text_iter_make_surreal (iter);
3859 check_invariants (iter);
3861 if (real->cached_char_index >= 0 &&
3862 real->cached_char_index == char_offset)
3865 line = _gtk_text_btree_get_line_at_char (real->tree,
3870 iter_set_from_char_offset (real, line, real_char_index - line_start);
3872 /* Go ahead and cache this since we have it. */
3873 real->cached_char_index = real_char_index;
3875 check_invariants (iter);
3879 * gtk_text_iter_forward_to_end:
3880 * @iter: a #GtkTextIter
3882 * Moves @iter forward to the "end iterator," which points one past the last
3883 * valid character in the buffer. gtk_text_iter_get_char() called on the
3884 * end iterator returns 0, which is convenient for writing loops.
3887 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3889 GtkTextBuffer *buffer;
3890 GtkTextRealIter *real;
3892 g_return_if_fail (iter != NULL);
3894 real = gtk_text_iter_make_surreal (iter);
3899 buffer = _gtk_text_btree_get_buffer (real->tree);
3901 gtk_text_buffer_get_end_iter (buffer, iter);
3904 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3905 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3906 * If all else fails we could cache the para delimiter pos in the iter.
3907 * I think forward_to_line_end() actually gets called fairly often.
3910 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3915 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3916 _gtk_text_iter_get_btree (&end)))
3918 gtk_text_iter_forward_to_end (&end);
3922 /* if we aren't on the last line, go forward to start of next line, then scan
3923 * back for the delimiters on the previous line
3925 gtk_text_iter_forward_line (&end);
3926 gtk_text_iter_backward_char (&end);
3927 while (!gtk_text_iter_ends_line (&end))
3928 gtk_text_iter_backward_char (&end);
3931 return gtk_text_iter_get_line_offset (&end);
3935 * gtk_text_iter_forward_to_line_end:
3936 * @iter: a #GtkTextIter
3938 * Moves the iterator to point to the paragraph delimiter characters,
3939 * which will be either a newline, a carriage return, a carriage
3940 * return/newline in sequence, or the Unicode paragraph separator
3941 * character. If the iterator is already at the paragraph delimiter
3942 * characters, moves to the paragraph delimiter characters for the
3943 * next line. If @iter is on the last line in the buffer, which does
3944 * not end in paragraph delimiters, moves to the end iterator (end of
3945 * the last line), and returns %FALSE.
3947 * Return value: %TRUE if we moved and the new location is not the end iterator
3950 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3952 gint current_offset;
3956 g_return_val_if_fail (iter != NULL, FALSE);
3958 current_offset = gtk_text_iter_get_line_offset (iter);
3959 new_offset = find_paragraph_delimiter_for_line (iter);
3961 if (current_offset < new_offset)
3963 /* Move to end of this line. */
3964 gtk_text_iter_set_line_offset (iter, new_offset);
3965 return !gtk_text_iter_is_end (iter);
3969 /* Move to end of next line. */
3970 if (gtk_text_iter_forward_line (iter))
3972 /* We don't want to move past all
3975 if (!gtk_text_iter_ends_line (iter))
3976 gtk_text_iter_forward_to_line_end (iter);
3977 return !gtk_text_iter_is_end (iter);
3985 * gtk_text_iter_forward_to_tag_toggle:
3986 * @iter: a #GtkTextIter
3987 * @tag: a #GtkTextTag, or %NULL
3989 * Moves forward to the next toggle (on or off) of the
3990 * #GtkTextTag @tag, or to the next toggle of any tag if
3991 * @tag is %NULL. If no matching tag toggles are found,
3992 * returns %FALSE, otherwise %TRUE. Does not return toggles
3993 * located at @iter, only toggles after @iter. Sets @iter to
3994 * the location of the toggle, or to the end of the buffer
3995 * if no toggle is found.
3997 * Return value: whether we found a tag toggle after @iter
4000 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4003 GtkTextLine *next_line;
4004 GtkTextLine *current_line;
4005 GtkTextRealIter *real;
4007 g_return_val_if_fail (iter != NULL, FALSE);
4009 real = gtk_text_iter_make_real (iter);
4014 check_invariants (iter);
4016 current_line = real->line;
4017 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4020 while (_gtk_text_iter_forward_indexable_segment (iter))
4022 /* If we went forward to a line that couldn't contain a toggle
4023 for the tag, then skip forward to a line that could contain
4024 it. This potentially skips huge hunks of the tree, so we
4025 aren't a purely linear search. */
4026 if (real->line != current_line)
4028 if (next_line == NULL)
4030 /* End of search. Set to end of buffer. */
4031 _gtk_text_btree_get_end_iter (real->tree, iter);
4035 if (real->line != next_line)
4036 iter_set_from_byte_offset (real, next_line, 0);
4038 current_line = real->line;
4039 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4044 if (gtk_text_iter_toggles_tag (iter, tag))
4046 /* If there's a toggle here, it isn't indexable so
4047 any_segment can't be the indexable segment. */
4048 g_assert (real->any_segment != real->segment);
4053 /* Check end iterator for tags */
4054 if (gtk_text_iter_toggles_tag (iter, tag))
4056 /* If there's a toggle here, it isn't indexable so
4057 any_segment can't be the indexable segment. */
4058 g_assert (real->any_segment != real->segment);
4062 /* Reached end of buffer */
4067 * gtk_text_iter_backward_to_tag_toggle:
4068 * @iter: a #GtkTextIter
4069 * @tag: a #GtkTextTag, or %NULL
4071 * Moves backward to the next toggle (on or off) of the
4072 * #GtkTextTag @tag, or to the next toggle of any tag if
4073 * @tag is %NULL. If no matching tag toggles are found,
4074 * returns %FALSE, otherwise %TRUE. Does not return toggles
4075 * located at @iter, only toggles before @iter. Sets @iter
4076 * to the location of the toggle, or the start of the buffer
4077 * if no toggle is found.
4079 * Return value: whether we found a tag toggle before @iter
4082 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4085 GtkTextLine *prev_line;
4086 GtkTextLine *current_line;
4087 GtkTextRealIter *real;
4089 g_return_val_if_fail (iter != NULL, FALSE);
4091 real = gtk_text_iter_make_real (iter);
4096 check_invariants (iter);
4098 current_line = real->line;
4099 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4103 /* If we're at segment start, go to the previous segment;
4104 * if mid-segment, snap to start of current segment.
4106 if (is_segment_start (real))
4108 if (!_gtk_text_iter_backward_indexable_segment (iter))
4113 ensure_char_offsets (real);
4115 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4121 /* If we went backward to a line that couldn't contain a toggle
4122 * for the tag, then skip backward further to a line that
4123 * could contain it. This potentially skips huge hunks of the
4124 * tree, so we aren't a purely linear search.
4126 if (real->line != current_line)
4128 if (prev_line == NULL)
4130 /* End of search. Set to start of buffer. */
4131 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4135 if (real->line != prev_line)
4137 /* Set to last segment in prev_line (could do this
4140 iter_set_from_byte_offset (real, prev_line, 0);
4142 while (!at_last_indexable_segment (real))
4143 _gtk_text_iter_forward_indexable_segment (iter);
4146 current_line = real->line;
4147 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4152 if (gtk_text_iter_toggles_tag (iter, tag))
4154 /* If there's a toggle here, it isn't indexable so
4155 * any_segment can't be the indexable segment.
4157 g_assert (real->any_segment != real->segment);
4161 while (_gtk_text_iter_backward_indexable_segment (iter));
4163 /* Reached front of buffer */
4168 matches_pred (GtkTextIter *iter,
4169 GtkTextCharPredicate pred,
4174 ch = gtk_text_iter_get_char (iter);
4176 return (*pred) (ch, user_data);
4180 * gtk_text_iter_forward_find_char:
4181 * @iter: a #GtkTextIter
4182 * @pred: a function to be called on each character
4183 * @user_data: user data for @pred
4184 * @limit: search limit, or %NULL for none
4186 * Advances @iter, calling @pred on each character. If
4187 * @pred returns %TRUE, returns %TRUE and stops scanning.
4188 * If @pred never returns %TRUE, @iter is set to @limit if
4189 * @limit is non-%NULL, otherwise to the end iterator.
4191 * Return value: whether a match was found
4194 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4195 GtkTextCharPredicate pred,
4197 const GtkTextIter *limit)
4199 g_return_val_if_fail (iter != NULL, FALSE);
4200 g_return_val_if_fail (pred != NULL, FALSE);
4203 gtk_text_iter_compare (iter, limit) >= 0)
4206 while ((limit == NULL ||
4207 !gtk_text_iter_equal (limit, iter)) &&
4208 gtk_text_iter_forward_char (iter))
4210 if (matches_pred (iter, pred, user_data))
4218 * gtk_text_iter_backward_find_char:
4219 * @iter: a #GtkTextIter
4220 * @pred: function to be called on each character
4221 * @user_data: user data for @pred
4222 * @limit: search limit, or %NULL for none
4224 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4226 * Return value: whether a match was found
4229 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4230 GtkTextCharPredicate pred,
4232 const GtkTextIter *limit)
4234 g_return_val_if_fail (iter != NULL, FALSE);
4235 g_return_val_if_fail (pred != NULL, FALSE);
4238 gtk_text_iter_compare (iter, limit) <= 0)
4241 while ((limit == NULL ||
4242 !gtk_text_iter_equal (limit, iter)) &&
4243 gtk_text_iter_backward_char (iter))
4245 if (matches_pred (iter, pred, user_data))
4253 forward_chars_with_skipping (GtkTextIter *iter,
4255 gboolean skip_invisible,
4256 gboolean skip_nontext)
4261 g_return_if_fail (count >= 0);
4267 gboolean ignored = FALSE;
4270 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4275 _gtk_text_btree_char_is_invisible (iter))
4278 gtk_text_iter_forward_char (iter);
4286 lines_match (const GtkTextIter *start,
4287 const gchar **lines,
4288 gboolean visible_only,
4290 GtkTextIter *match_start,
4291 GtkTextIter *match_end)
4298 if (*lines == NULL || **lines == '\0')
4301 *match_start = *start;
4304 *match_end = *start;
4309 gtk_text_iter_forward_line (&next);
4311 /* No more text in buffer, but *lines is nonempty */
4312 if (gtk_text_iter_equal (start, &next))
4320 line_text = gtk_text_iter_get_visible_slice (start, &next);
4322 line_text = gtk_text_iter_get_slice (start, &next);
4327 line_text = gtk_text_iter_get_visible_text (start, &next);
4329 line_text = gtk_text_iter_get_text (start, &next);
4332 if (match_start) /* if this is the first line we're matching */
4333 found = strstr (line_text, *lines);
4336 /* If it's not the first line, we have to match from the
4337 * start of the line.
4339 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4351 /* Get offset to start of search string */
4352 offset = g_utf8_strlen (line_text, found - line_text);
4356 /* If match start needs to be returned, set it to the
4357 * start of the search string.
4361 *match_start = next;
4363 forward_chars_with_skipping (match_start, offset,
4364 visible_only, !slice);
4367 /* Go to end of search string */
4368 offset += g_utf8_strlen (*lines, -1);
4370 forward_chars_with_skipping (&next, offset,
4371 visible_only, !slice);
4380 /* pass NULL for match_start, since we don't need to find the
4383 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4386 /* strsplit () that retains the delimiter as part of the string. */
4388 strbreakup (const char *string,
4389 const char *delimiter,
4392 GSList *string_list = NULL, *slist;
4393 gchar **str_array, *s;
4396 g_return_val_if_fail (string != NULL, NULL);
4397 g_return_val_if_fail (delimiter != NULL, NULL);
4400 max_tokens = G_MAXINT;
4402 s = strstr (string, delimiter);
4405 guint delimiter_len = strlen (delimiter);
4412 len = s - string + delimiter_len;
4413 new_string = g_new (gchar, len + 1);
4414 strncpy (new_string, string, len);
4415 new_string[len] = 0;
4416 string_list = g_slist_prepend (string_list, new_string);
4418 string = s + delimiter_len;
4419 s = strstr (string, delimiter);
4421 while (--max_tokens && s);
4426 string_list = g_slist_prepend (string_list, g_strdup (string));
4429 str_array = g_new (gchar*, n);
4433 str_array[i--] = NULL;
4434 for (slist = string_list; slist; slist = slist->next)
4435 str_array[i--] = slist->data;
4437 g_slist_free (string_list);
4443 * gtk_text_iter_forward_search:
4444 * @iter: start of search
4445 * @str: a search string
4446 * @flags: flags affecting how the search is done
4447 * @match_start: return location for start of match, or %NULL
4448 * @match_end: return location for end of match, or %NULL
4449 * @limit: bound for the search, or %NULL for the end of the buffer
4451 * Searches forward for @str. Any match is returned by setting
4452 * @match_start to the first character of the match and @match_end to the
4453 * first character after the match. The search will not continue past
4454 * @limit. Note that a search is a linear or O(n) operation, so you
4455 * may wish to use @limit to avoid locking up your UI on large
4458 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4459 * have invisible text interspersed in @str. i.e. @str will be a
4460 * possibly-noncontiguous subsequence of the matched range. similarly,
4461 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4462 * pixbufs or child widgets mixed inside the matched range. If these
4463 * flags are not given, the match must be exact; the special 0xFFFC
4464 * character in @str will match embedded pixbufs or child widgets.
4466 * Return value: whether a match was found
4469 gtk_text_iter_forward_search (const GtkTextIter *iter,
4471 GtkTextSearchFlags flags,
4472 GtkTextIter *match_start,
4473 GtkTextIter *match_end,
4474 const GtkTextIter *limit)
4476 gchar **lines = NULL;
4478 gboolean retval = FALSE;
4480 gboolean visible_only;
4483 g_return_val_if_fail (iter != NULL, FALSE);
4484 g_return_val_if_fail (str != NULL, FALSE);
4487 gtk_text_iter_compare (iter, limit) >= 0)
4492 /* If we can move one char, return the empty string there */
4495 if (gtk_text_iter_forward_char (&match))
4498 gtk_text_iter_equal (&match, limit))
4502 *match_start = match;
4511 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4512 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4514 /* locate all lines */
4516 lines = strbreakup (str, "\n", -1);
4522 /* This loop has an inefficient worst-case, where
4523 * gtk_text_iter_get_text () is called repeatedly on
4529 gtk_text_iter_compare (&search, limit) >= 0)
4532 if (lines_match (&search, (const gchar**)lines,
4533 visible_only, slice, &match, &end))
4535 if (limit == NULL ||
4537 gtk_text_iter_compare (&end, limit) < 0))
4542 *match_start = match;
4551 while (gtk_text_iter_forward_line (&search));
4553 g_strfreev ((gchar**)lines);
4559 vectors_equal_ignoring_trailing (gchar **vec1,
4562 /* Ignores trailing chars in vec2's last line */
4571 if (strcmp (*i1, *i2) != 0)
4573 if (*(i2 + 1) == NULL) /* if this is the last line */
4575 gint len1 = strlen (*i1);
4576 gint len2 = strlen (*i2);
4579 strncmp (*i1, *i2, len1) == 0)
4581 /* We matched ignoring the trailing stuff in vec2 */
4606 typedef struct _LinesWindow LinesWindow;
4612 GtkTextIter first_line_start;
4613 GtkTextIter first_line_end;
4615 gboolean visible_only;
4619 lines_window_init (LinesWindow *win,
4620 const GtkTextIter *start)
4623 GtkTextIter line_start;
4624 GtkTextIter line_end;
4626 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4629 if (gtk_text_iter_is_start (start) ||
4630 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4632 /* Already at the end, or not enough lines to match */
4633 win->lines = g_new0 (gchar*, 1);
4638 line_start = *start;
4641 /* Move to start iter to start of line */
4642 gtk_text_iter_set_line_offset (&line_start, 0);
4644 if (gtk_text_iter_equal (&line_start, &line_end))
4646 /* we were already at the start; so go back one line */
4647 gtk_text_iter_backward_line (&line_start);
4650 win->first_line_start = line_start;
4651 win->first_line_end = line_end;
4653 win->lines = g_new0 (gchar*, win->n_lines + 1);
4655 i = win->n_lines - 1;
4662 if (win->visible_only)
4663 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4665 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4669 if (win->visible_only)
4670 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4672 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4675 win->lines[i] = line_text;
4677 line_end = line_start;
4678 gtk_text_iter_backward_line (&line_start);
4685 lines_window_back (LinesWindow *win)
4687 GtkTextIter new_start;
4690 new_start = win->first_line_start;
4692 if (!gtk_text_iter_backward_line (&new_start))
4696 win->first_line_start = new_start;
4697 win->first_line_end = new_start;
4699 gtk_text_iter_forward_line (&win->first_line_end);
4704 if (win->visible_only)
4705 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4706 &win->first_line_end);
4708 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4709 &win->first_line_end);
4713 if (win->visible_only)
4714 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4715 &win->first_line_end);
4717 line_text = gtk_text_iter_get_text (&win->first_line_start,
4718 &win->first_line_end);
4721 /* Move lines to make room for first line. */
4722 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4724 *win->lines = line_text;
4726 /* Free old last line and NULL-terminate */
4727 g_free (win->lines[win->n_lines]);
4728 win->lines[win->n_lines] = NULL;
4734 lines_window_free (LinesWindow *win)
4736 g_strfreev (win->lines);
4740 * gtk_text_iter_backward_search:
4741 * @iter: a #GtkTextIter where the search begins
4742 * @str: search string
4743 * @flags: bitmask of flags affecting the search
4744 * @match_start: return location for start of match, or %NULL
4745 * @match_end: return location for end of match, or %NULL
4746 * @limit: location of last possible @match_start, or %NULL for start of buffer
4748 * Same as gtk_text_iter_forward_search(), but moves backward.
4750 * Return value: whether a match was found
4753 gtk_text_iter_backward_search (const GtkTextIter *iter,
4755 GtkTextSearchFlags flags,
4756 GtkTextIter *match_start,
4757 GtkTextIter *match_end,
4758 const GtkTextIter *limit)
4760 gchar **lines = NULL;
4764 gboolean retval = FALSE;
4765 gboolean visible_only;
4768 g_return_val_if_fail (iter != NULL, FALSE);
4769 g_return_val_if_fail (str != NULL, FALSE);
4772 gtk_text_iter_compare (limit, iter) > 0)
4777 /* If we can move one char, return the empty string there */
4778 GtkTextIter match = *iter;
4780 if (limit && gtk_text_iter_equal (limit, &match))
4783 if (gtk_text_iter_backward_char (&match))
4786 *match_start = match;
4795 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4796 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4798 /* locate all lines */
4800 lines = strbreakup (str, "\n", -1);
4810 win.n_lines = n_lines;
4812 win.visible_only = visible_only;
4814 lines_window_init (&win, iter);
4816 if (*win.lines == NULL)
4821 gchar *first_line_match;
4824 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4826 /* We're now before the search limit, abort. */
4830 /* If there are multiple lines, the first line will
4831 * end in '\n', so this will only match at the
4832 * end of the first line, which is correct.
4834 first_line_match = g_strrstr (*win.lines, *lines);
4836 if (first_line_match &&
4837 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4842 GtkTextIter start_tmp;
4844 /* Offset to start of search string */
4845 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4847 next = win.first_line_start;
4849 forward_chars_with_skipping (&start_tmp, offset,
4850 visible_only, !slice);
4853 gtk_text_iter_compare (limit, &start_tmp) > 0)
4854 goto out; /* match was bogus */
4857 *match_start = start_tmp;
4859 /* Go to end of search string */
4863 offset += g_utf8_strlen (*l, -1);
4867 forward_chars_with_skipping (&next, offset,
4868 visible_only, !slice);
4877 while (lines_window_back (&win));
4880 lines_window_free (&win);
4891 * gtk_text_iter_equal:
4892 * @lhs: a #GtkTextIter
4893 * @rhs: another #GtkTextIter
4895 * Tests whether two iterators are equal, using the fastest possible
4896 * mechanism. This function is very fast; you can expect it to perform
4897 * better than e.g. getting the character offset for each iterator and
4898 * comparing the offsets yourself. Also, it's a bit faster than
4899 * gtk_text_iter_compare().
4901 * Return value: %TRUE if the iterators point to the same place in the buffer
4904 gtk_text_iter_equal (const GtkTextIter *lhs,
4905 const GtkTextIter *rhs)
4907 GtkTextRealIter *real_lhs;
4908 GtkTextRealIter *real_rhs;
4910 real_lhs = (GtkTextRealIter*)lhs;
4911 real_rhs = (GtkTextRealIter*)rhs;
4913 check_invariants (lhs);
4914 check_invariants (rhs);
4916 if (real_lhs->line != real_rhs->line)
4918 else if (real_lhs->line_byte_offset >= 0 &&
4919 real_rhs->line_byte_offset >= 0)
4920 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4923 /* the ensure_char_offsets () calls do nothing if the char offsets
4924 are already up-to-date. */
4925 ensure_char_offsets (real_lhs);
4926 ensure_char_offsets (real_rhs);
4927 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4932 * gtk_text_iter_compare:
4933 * @lhs: a #GtkTextIter
4934 * @rhs: another #GtkTextIter
4936 * A qsort()-style function that returns negative if @lhs is less than
4937 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4938 * Ordering is in character offset order, i.e. the first character in the buffer
4939 * is less than the second character in the buffer.
4941 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4944 gtk_text_iter_compare (const GtkTextIter *lhs,
4945 const GtkTextIter *rhs)
4947 GtkTextRealIter *real_lhs;
4948 GtkTextRealIter *real_rhs;
4950 real_lhs = gtk_text_iter_make_surreal (lhs);
4951 real_rhs = gtk_text_iter_make_surreal (rhs);
4953 if (real_lhs == NULL ||
4955 return -1; /* why not */
4957 check_invariants (lhs);
4958 check_invariants (rhs);
4960 if (real_lhs->line == real_rhs->line)
4962 gint left_index, right_index;
4964 if (real_lhs->line_byte_offset >= 0 &&
4965 real_rhs->line_byte_offset >= 0)
4967 left_index = real_lhs->line_byte_offset;
4968 right_index = real_rhs->line_byte_offset;
4972 /* the ensure_char_offsets () calls do nothing if
4973 the offsets are already up-to-date. */
4974 ensure_char_offsets (real_lhs);
4975 ensure_char_offsets (real_rhs);
4976 left_index = real_lhs->line_char_offset;
4977 right_index = real_rhs->line_char_offset;
4980 if (left_index < right_index)
4982 else if (left_index > right_index)
4991 line1 = gtk_text_iter_get_line (lhs);
4992 line2 = gtk_text_iter_get_line (rhs);
4995 else if (line1 > line2)
5003 * gtk_text_iter_in_range:
5004 * @iter: a #GtkTextIter
5005 * @start: start of range
5006 * @end: end of range
5008 * Checks whether @iter falls in the range [@start, @end).
5009 * @start and @end must be in ascending order.
5011 * Return value: %TRUE if @iter is in the range
5014 gtk_text_iter_in_range (const GtkTextIter *iter,
5015 const GtkTextIter *start,
5016 const GtkTextIter *end)
5018 g_return_val_if_fail (iter != NULL, FALSE);
5019 g_return_val_if_fail (start != NULL, FALSE);
5020 g_return_val_if_fail (end != NULL, FALSE);
5021 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5023 return gtk_text_iter_compare (iter, start) >= 0 &&
5024 gtk_text_iter_compare (iter, end) < 0;
5028 * gtk_text_iter_order:
5029 * @first: a #GtkTextIter
5030 * @second: another #GtkTextIter
5032 * Swaps the value of @first and @second if @second comes before
5033 * @first in the buffer. That is, ensures that @first and @second are
5034 * in sequence. Most text buffer functions that take a range call this
5035 * automatically on your behalf, so there's no real reason to call it yourself
5036 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5037 * that expect a pre-sorted range.
5041 gtk_text_iter_order (GtkTextIter *first,
5042 GtkTextIter *second)
5044 g_return_if_fail (first != NULL);
5045 g_return_if_fail (second != NULL);
5047 if (gtk_text_iter_compare (first, second) > 0)
5058 * Init iterators from the BTree
5062 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5066 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5067 gint real_char_index;
5071 g_return_if_fail (iter != NULL);
5072 g_return_if_fail (tree != NULL);
5074 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5075 &line_start, &real_char_index);
5077 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5079 real->cached_char_index = real_char_index;
5081 check_invariants (iter);
5085 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5090 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5094 g_return_if_fail (iter != NULL);
5095 g_return_if_fail (tree != NULL);
5097 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5099 iter_init_from_char_offset (iter, tree, line, char_on_line);
5101 /* We might as well cache this, since we know it. */
5102 real->cached_line_number = real_line;
5104 check_invariants (iter);
5108 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5113 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5117 g_return_if_fail (iter != NULL);
5118 g_return_if_fail (tree != NULL);
5120 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5122 iter_init_from_byte_offset (iter, tree, line, byte_index);
5124 /* We might as well cache this, since we know it. */
5125 real->cached_line_number = real_line;
5127 check_invariants (iter);
5131 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5136 g_return_if_fail (iter != NULL);
5137 g_return_if_fail (tree != NULL);
5138 g_return_if_fail (line != NULL);
5140 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5142 check_invariants (iter);
5146 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5152 g_return_val_if_fail (iter != NULL, FALSE);
5153 g_return_val_if_fail (tree != NULL, FALSE);
5155 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5159 /* Set iter to last in tree */
5160 _gtk_text_btree_get_end_iter (tree, iter);
5161 check_invariants (iter);
5166 iter_init_from_byte_offset (iter, tree, line, 0);
5168 if (!gtk_text_iter_toggles_tag (iter, tag))
5169 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5171 check_invariants (iter);
5177 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5181 g_return_val_if_fail (iter != NULL, FALSE);
5182 g_return_val_if_fail (tree != NULL, FALSE);
5184 _gtk_text_btree_get_end_iter (tree, iter);
5185 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5186 check_invariants (iter);
5192 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5194 const gchar *mark_name)
5198 g_return_val_if_fail (iter != NULL, FALSE);
5199 g_return_val_if_fail (tree != NULL, FALSE);
5201 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5207 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5208 check_invariants (iter);
5214 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5218 GtkTextLineSegment *seg;
5220 g_return_if_fail (iter != NULL);
5221 g_return_if_fail (tree != NULL);
5222 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5224 seg = mark->segment;
5226 iter_init_from_segment (iter, tree,
5227 seg->body.mark.line, seg);
5228 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5229 check_invariants (iter);
5233 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5235 GtkTextChildAnchor *anchor)
5237 GtkTextLineSegment *seg;
5239 g_return_if_fail (iter != NULL);
5240 g_return_if_fail (tree != NULL);
5241 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5243 seg = anchor->segment;
5245 g_assert (seg->body.child.line != NULL);
5247 iter_init_from_segment (iter, tree,
5248 seg->body.child.line, seg);
5249 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5250 check_invariants (iter);
5254 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5257 g_return_if_fail (iter != NULL);
5258 g_return_if_fail (tree != NULL);
5260 _gtk_text_btree_get_iter_at_char (tree,
5262 _gtk_text_btree_char_count (tree));
5263 check_invariants (iter);
5267 _gtk_text_iter_check (const GtkTextIter *iter)
5269 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5270 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5271 GtkTextLineSegment *byte_segment = NULL;
5272 GtkTextLineSegment *byte_any_segment = NULL;
5273 GtkTextLineSegment *char_segment = NULL;
5274 GtkTextLineSegment *char_any_segment = NULL;
5275 gboolean segments_updated;
5277 /* This function checks our class invariants for the Iter class. */
5279 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5281 if (real->chars_changed_stamp !=
5282 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5283 g_error ("iterator check failed: invalid iterator");
5285 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5286 g_error ("iterator check failed: both char and byte offsets are invalid");
5288 segments_updated = (real->segments_changed_stamp ==
5289 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5292 printf ("checking iter, segments %s updated, byte %d char %d\n",
5293 segments_updated ? "are" : "aren't",
5294 real->line_byte_offset,
5295 real->line_char_offset);
5298 if (segments_updated)
5300 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5301 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5303 if (real->segment->char_count == 0)
5304 g_error ("iterator check failed: segment is not indexable.");
5306 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5307 g_error ("segment char offset is not properly up-to-date");
5309 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5310 g_error ("segment byte offset is not properly up-to-date");
5312 if (real->segment_byte_offset >= 0 &&
5313 real->segment_byte_offset >= real->segment->byte_count)
5314 g_error ("segment byte offset is too large.");
5316 if (real->segment_char_offset >= 0 &&
5317 real->segment_char_offset >= real->segment->char_count)
5318 g_error ("segment char offset is too large.");
5321 if (real->line_byte_offset >= 0)
5323 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5324 &byte_segment, &byte_any_segment,
5325 &seg_byte_offset, &line_byte_offset);
5327 if (line_byte_offset != real->line_byte_offset)
5328 g_error ("wrong byte offset was stored in iterator");
5330 if (segments_updated)
5332 if (real->segment != byte_segment)
5333 g_error ("wrong segment was stored in iterator");
5335 if (real->any_segment != byte_any_segment)
5336 g_error ("wrong any_segment was stored in iterator");
5338 if (seg_byte_offset != real->segment_byte_offset)
5339 g_error ("wrong segment byte offset was stored in iterator");
5341 if (byte_segment->type == >k_text_char_type)
5344 p = byte_segment->body.chars + seg_byte_offset;
5346 if (!gtk_text_byte_begins_utf8_char (p))
5347 g_error ("broken iterator byte index pointed into the middle of a character");
5352 if (real->line_char_offset >= 0)
5354 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5355 &char_segment, &char_any_segment,
5356 &seg_char_offset, &line_char_offset);
5358 if (line_char_offset != real->line_char_offset)
5359 g_error ("wrong char offset was stored in iterator");
5361 if (segments_updated)
5363 if (real->segment != char_segment)
5364 g_error ("wrong segment was stored in iterator");
5366 if (real->any_segment != char_any_segment)
5367 g_error ("wrong any_segment was stored in iterator");
5369 if (seg_char_offset != real->segment_char_offset)
5370 g_error ("wrong segment char offset was stored in iterator");
5372 if (char_segment->type == >k_text_char_type)
5375 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5378 /* hmm, not likely to happen eh */
5379 if (!gtk_text_byte_begins_utf8_char (p))
5380 g_error ("broken iterator char offset pointed into the middle of a character");
5385 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5387 if (byte_segment != char_segment)
5388 g_error ("char and byte offsets did not point to the same segment");
5390 if (byte_any_segment != char_any_segment)
5391 g_error ("char and byte offsets did not point to the same any segment");
5393 /* Make sure the segment offsets are equivalent, if it's a char
5395 if (char_segment->type == >k_text_char_type)
5397 gint byte_offset = 0;
5398 gint char_offset = 0;
5399 while (char_offset < seg_char_offset)
5401 const char * start = char_segment->body.chars + byte_offset;
5402 byte_offset += g_utf8_next_char (start) - start;
5406 if (byte_offset != seg_byte_offset)
5407 g_error ("byte offset did not correspond to char offset");
5410 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5412 if (char_offset != seg_char_offset)
5413 g_error ("char offset did not correspond to byte offset");
5415 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5416 g_error ("byte index for iterator does not index the start of a character");
5420 if (real->cached_line_number >= 0)
5424 should_be = _gtk_text_line_get_number (real->line);
5425 if (real->cached_line_number != should_be)
5426 g_error ("wrong line number was cached");
5429 if (real->cached_char_index >= 0)
5431 if (real->line_char_offset >= 0) /* only way we can check it
5432 efficiently, not a real
5437 char_index = _gtk_text_line_char_index (real->line);
5438 char_index += real->line_char_offset;
5440 if (real->cached_char_index != char_index)
5441 g_error ("wrong char index was cached");
5445 if (_gtk_text_line_is_last (real->line, real->tree))
5446 g_error ("Iterator was on last line (past the end iterator)");