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
29 #include "gtktextiter.h"
30 #include "gtktextbtree.h"
31 #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)
1552 g_return_val_if_fail (iter != NULL, FALSE);
1554 check_invariants (iter);
1556 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1557 * Unicode 3.0; update this if that changes.
1559 #define PARAGRAPH_SEPARATOR 0x2029
1561 wc = gtk_text_iter_get_char (iter);
1563 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1565 else if (wc == '\n')
1567 /* need to determine if a \r precedes the \n, in which case
1568 * we aren't the end of the line
1570 GtkTextIter tmp = *iter;
1571 if (!gtk_text_iter_backward_char (&tmp))
1574 return gtk_text_iter_get_char (&tmp) != '\r';
1581 * gtk_text_iter_is_end:
1582 * @iter: an iterator
1584 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1585 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1586 * the most efficient way to check whether an iterator is the end
1589 * Return value: whether @iter is the end iterator
1592 gtk_text_iter_is_end (const GtkTextIter *iter)
1594 GtkTextRealIter *real;
1596 g_return_val_if_fail (iter != NULL, FALSE);
1598 real = gtk_text_iter_make_surreal (iter);
1603 check_invariants (iter);
1605 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1608 /* Now we need the segments validated */
1609 real = gtk_text_iter_make_real (iter);
1614 return _gtk_text_btree_is_end (real->tree, real->line,
1616 real->segment_byte_offset,
1617 real->segment_char_offset);
1621 * gtk_text_iter_is_start:
1622 * @iter: an iterator
1624 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1625 * if @iter has a character offset of 0.
1627 * Return value: whether @iter is the first in the buffer
1630 gtk_text_iter_is_start (const GtkTextIter *iter)
1632 return gtk_text_iter_get_offset (iter) == 0;
1636 * gtk_text_iter_get_chars_in_line:
1637 * @iter: an iterator
1639 * Returns the number of characters in the line containing @iter,
1640 * including the paragraph delimiters.
1642 * Return value: number of characters in the line
1645 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1647 GtkTextRealIter *real;
1649 GtkTextLineSegment *seg;
1651 g_return_val_if_fail (iter != NULL, 0);
1653 real = gtk_text_iter_make_surreal (iter);
1658 check_invariants (iter);
1660 if (real->line_char_offset >= 0)
1662 /* We can start at the segments we've already found. */
1663 count = real->line_char_offset - real->segment_char_offset;
1664 seg = _gtk_text_iter_get_indexable_segment (iter);
1668 /* count whole line. */
1669 seg = real->line->segments;
1676 count += seg->char_count;
1681 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1682 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1688 * gtk_text_iter_get_bytes_in_line:
1689 * @iter: an iterator
1691 * Returns the number of bytes in the line containing @iter,
1692 * including the paragraph delimiters.
1694 * Return value: number of bytes in the line
1697 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1699 GtkTextRealIter *real;
1701 GtkTextLineSegment *seg;
1703 g_return_val_if_fail (iter != NULL, 0);
1705 real = gtk_text_iter_make_surreal (iter);
1710 check_invariants (iter);
1712 if (real->line_byte_offset >= 0)
1714 /* We can start at the segments we've already found. */
1715 count = real->line_byte_offset - real->segment_byte_offset;
1716 seg = _gtk_text_iter_get_indexable_segment (iter);
1720 /* count whole line. */
1721 seg = real->line->segments;
1727 count += seg->byte_count;
1732 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1733 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1739 * gtk_text_iter_get_attributes:
1740 * @iter: an iterator
1741 * @values: a #GtkTextAttributes to be filled in
1743 * Computes the effect of any tags applied to this spot in the
1744 * text. The @values parameter should be initialized to the default
1745 * settings you wish to use if no tags are in effect. You'd typically
1746 * obtain the defaults from gtk_text_view_get_default_attributes().
1748 * gtk_text_iter_get_attributes () will modify @values, applying the
1749 * effects of any tags present at @iter. If any tags affected @values,
1750 * the function returns %TRUE.
1752 * Return value: %TRUE if @values was modified
1755 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1756 GtkTextAttributes *values)
1761 /* Get the tags at this spot */
1762 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1764 /* No tags, use default style */
1765 if (tags == NULL || tag_count == 0)
1773 /* Sort tags in ascending order of priority */
1774 _gtk_text_tag_array_sort (tags, tag_count);
1776 _gtk_text_attributes_fill_from_tags (values,
1786 * Increments/decrements
1789 /* The return value of this indicates WHETHER WE MOVED.
1790 * The return value of public functions indicates
1791 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1793 * This function will not change the iterator if
1794 * it's already on the last (end iter) line, i.e. it
1795 * won't move to the end of the last line.
1798 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1800 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1802 GtkTextLine *new_line;
1804 new_line = _gtk_text_line_next (real->line);
1805 g_assert (new_line);
1806 g_assert (new_line != real->line);
1807 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1809 real->line = new_line;
1811 real->line_byte_offset = 0;
1812 real->line_char_offset = 0;
1814 real->segment_byte_offset = 0;
1815 real->segment_char_offset = 0;
1817 /* Find first segments in new line */
1818 real->any_segment = real->line->segments;
1819 real->segment = real->any_segment;
1820 while (real->segment->char_count == 0)
1821 real->segment = real->segment->next;
1827 /* There is no way to move forward a line; we were already at
1828 * the line containing the end iterator.
1829 * However we may not be at the end iterator itself.
1837 /* The return value of this indicates WHETHER WE MOVED.
1838 * The return value of public functions indicates
1839 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1841 * This function is currently unused, thus it is #if-0-ed. It is
1842 * left here, since it's non-trivial code that might be useful in
1846 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1848 GtkTextLine *new_line;
1850 new_line = _gtk_text_line_previous (real->line);
1852 g_assert (new_line != real->line);
1854 if (new_line != NULL)
1856 real->line = new_line;
1858 real->line_byte_offset = 0;
1859 real->line_char_offset = 0;
1861 real->segment_byte_offset = 0;
1862 real->segment_char_offset = 0;
1864 /* Find first segments in new line */
1865 real->any_segment = real->line->segments;
1866 real->segment = real->any_segment;
1867 while (real->segment->char_count == 0)
1868 real->segment = real->segment->next;
1874 /* There is no way to move backward; we were already
1875 at the first line. */
1877 /* We leave real->line as-is */
1879 /* Note that we didn't clamp to the start of the first line. */
1886 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1890 forward_char (GtkTextRealIter *real)
1892 GtkTextIter *iter = (GtkTextIter*)real;
1894 check_invariants ((GtkTextIter*)real);
1896 ensure_char_offsets (real);
1898 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1900 /* Need to move to the next segment; if no next segment,
1901 need to move to next line. */
1902 return _gtk_text_iter_forward_indexable_segment (iter);
1906 /* Just moving within a segment. Keep byte count
1907 up-to-date, if it was already up-to-date. */
1909 g_assert (real->segment->type == >k_text_char_type);
1911 if (real->line_byte_offset >= 0)
1914 const char * start =
1915 real->segment->body.chars + real->segment_byte_offset;
1917 bytes = g_utf8_next_char (start) - start;
1919 real->line_byte_offset += bytes;
1920 real->segment_byte_offset += bytes;
1922 g_assert (real->segment_byte_offset < real->segment->byte_count);
1925 real->line_char_offset += 1;
1926 real->segment_char_offset += 1;
1928 adjust_char_index (real, 1);
1930 g_assert (real->segment_char_offset < real->segment->char_count);
1932 /* We moved into the middle of a segment, so the any_segment
1933 must now be the segment we're in the middle of. */
1934 real->any_segment = real->segment;
1936 check_invariants ((GtkTextIter*)real);
1938 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1946 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1948 /* Need to move to the next segment; if no next segment,
1949 need to move to next line. */
1950 GtkTextLineSegment *seg;
1951 GtkTextLineSegment *any_seg;
1952 GtkTextRealIter *real;
1956 g_return_val_if_fail (iter != NULL, FALSE);
1958 real = gtk_text_iter_make_real (iter);
1963 check_invariants (iter);
1965 if (real->line_char_offset >= 0)
1967 chars_skipped = real->segment->char_count - real->segment_char_offset;
1968 g_assert (chars_skipped > 0);
1973 if (real->line_byte_offset >= 0)
1975 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1976 g_assert (bytes_skipped > 0);
1981 /* Get first segment of any kind */
1982 any_seg = real->segment->next;
1983 /* skip non-indexable segments, if any */
1985 while (seg != NULL && seg->char_count == 0)
1990 real->any_segment = any_seg;
1991 real->segment = seg;
1993 if (real->line_byte_offset >= 0)
1995 g_assert (bytes_skipped > 0);
1996 real->segment_byte_offset = 0;
1997 real->line_byte_offset += bytes_skipped;
2000 if (real->line_char_offset >= 0)
2002 g_assert (chars_skipped > 0);
2003 real->segment_char_offset = 0;
2004 real->line_char_offset += chars_skipped;
2005 adjust_char_index (real, chars_skipped);
2008 check_invariants (iter);
2010 return !gtk_text_iter_is_end (iter);
2014 /* End of the line */
2015 if (forward_line_leaving_caches_unmodified (real))
2017 adjust_line_number (real, 1);
2018 if (real->line_char_offset >= 0)
2019 adjust_char_index (real, chars_skipped);
2021 g_assert (real->line_byte_offset == 0);
2022 g_assert (real->line_char_offset == 0);
2023 g_assert (real->segment_byte_offset == 0);
2024 g_assert (real->segment_char_offset == 0);
2025 g_assert (gtk_text_iter_starts_line (iter));
2027 check_invariants (iter);
2029 return !gtk_text_iter_is_end (iter);
2033 /* End of buffer, but iter is still at start of last segment,
2034 * not at the end iterator. We put it on the end iterator.
2037 check_invariants (iter);
2039 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2040 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2042 gtk_text_iter_forward_to_line_end (iter);
2044 g_assert (gtk_text_iter_is_end (iter));
2052 at_last_indexable_segment (GtkTextRealIter *real)
2054 GtkTextLineSegment *seg;
2056 /* Return TRUE if there are no indexable segments after
2060 seg = real->segment->next;
2063 if (seg->char_count > 0)
2070 /* Goes back to the start of the next segment, even if
2071 * we're not at the start of the current segment (always
2072 * ends up on a different segment if it returns TRUE)
2075 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2077 /* Move to the start of the previous segment; if no previous
2078 * segment, to the last segment in the previous line. This is
2079 * inherently a bit inefficient due to the singly-linked list and
2080 * tree nodes, but we can't afford the RAM for doubly-linked.
2082 GtkTextRealIter *real;
2083 GtkTextLineSegment *seg;
2084 GtkTextLineSegment *any_seg;
2085 GtkTextLineSegment *prev_seg;
2086 GtkTextLineSegment *prev_any_seg;
2090 g_return_val_if_fail (iter != NULL, FALSE);
2092 real = gtk_text_iter_make_real (iter);
2097 check_invariants (iter);
2099 /* Find first segments in line */
2100 any_seg = real->line->segments;
2102 while (seg->char_count == 0)
2105 if (seg == real->segment)
2107 /* Could probably do this case faster by hand-coding the
2111 /* We were already at the start of a line;
2112 * go back to the previous line.
2114 if (gtk_text_iter_backward_line (iter))
2116 /* Go forward to last indexable segment in line. */
2117 while (!at_last_indexable_segment (real))
2118 _gtk_text_iter_forward_indexable_segment (iter);
2120 check_invariants (iter);
2125 return FALSE; /* We were at the start of the first line. */
2128 /* We must be in the middle of a line; so find the indexable
2129 * segment just before our current segment.
2131 g_assert (seg != real->segment);
2135 prev_any_seg = any_seg;
2137 any_seg = seg->next;
2139 while (seg->char_count == 0)
2142 while (seg != real->segment);
2144 g_assert (prev_seg != NULL);
2145 g_assert (prev_any_seg != NULL);
2146 g_assert (prev_seg->char_count > 0);
2148 /* We skipped the entire previous segment, plus any
2149 * chars we were into the current segment.
2151 if (real->segment_byte_offset >= 0)
2152 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2156 if (real->segment_char_offset >= 0)
2157 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2161 real->segment = prev_seg;
2162 real->any_segment = prev_any_seg;
2163 real->segment_byte_offset = 0;
2164 real->segment_char_offset = 0;
2166 if (bytes_skipped >= 0)
2168 if (real->line_byte_offset >= 0)
2170 real->line_byte_offset -= bytes_skipped;
2171 g_assert (real->line_byte_offset >= 0);
2175 real->line_byte_offset = -1;
2177 if (chars_skipped >= 0)
2179 if (real->line_char_offset >= 0)
2181 real->line_char_offset -= chars_skipped;
2182 g_assert (real->line_char_offset >= 0);
2185 if (real->cached_char_index >= 0)
2187 real->cached_char_index -= chars_skipped;
2188 g_assert (real->cached_char_index >= 0);
2193 real->line_char_offset = -1;
2194 real->cached_char_index = -1;
2197 /* line number is unchanged. */
2199 check_invariants (iter);
2205 * gtk_text_iter_forward_char:
2206 * @iter: an iterator
2208 * Moves @iter forward by one character offset. Note that images
2209 * embedded in the buffer occupy 1 character slot, so
2210 * gtk_text_iter_forward_char () may actually move onto an image instead
2211 * of a character, if you have images in your buffer. If @iter is the
2212 * end iterator or one character before it, @iter will now point at
2213 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2214 * convenience when writing loops.
2216 * Return value: whether @iter moved and is dereferenceable
2219 gtk_text_iter_forward_char (GtkTextIter *iter)
2221 GtkTextRealIter *real;
2223 g_return_val_if_fail (iter != NULL, FALSE);
2225 real = gtk_text_iter_make_real (iter);
2231 check_invariants (iter);
2232 return forward_char (real);
2237 * gtk_text_iter_backward_char:
2238 * @iter: an iterator
2240 * Moves backward by one character offset. Returns %TRUE if movement
2241 * was possible; if @iter was the first in the buffer (character
2242 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2245 * Return value: whether movement was possible
2248 gtk_text_iter_backward_char (GtkTextIter *iter)
2250 g_return_val_if_fail (iter != NULL, FALSE);
2252 check_invariants (iter);
2254 return gtk_text_iter_backward_chars (iter, 1);
2258 Definitely we should try to linear scan as often as possible for
2259 movement within a single line, because we can't use the BTree to
2260 speed within-line searches up; for movement between lines, we would
2261 like to avoid the linear scan probably.
2263 Instead of using this constant, it might be nice to cache the line
2264 length in the iterator and linear scan if motion is within a single
2267 I guess you'd have to profile the various approaches.
2269 #define MAX_LINEAR_SCAN 150
2273 * gtk_text_iter_forward_chars:
2274 * @iter: an iterator
2275 * @count: number of characters to move, may be negative
2277 * Moves @count characters if possible (if @count would move past the
2278 * start or end of the buffer, moves to the start or end of the
2279 * buffer). The return value indicates whether the new position of
2280 * @iter is different from its original position, and dereferenceable
2281 * (the last iterator in the buffer is not dereferenceable). If @count
2282 * is 0, the function does nothing and returns %FALSE.
2284 * Return value: whether @iter moved and is dereferenceable
2287 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2289 GtkTextRealIter *real;
2291 g_return_val_if_fail (iter != NULL, FALSE);
2293 FIX_OVERFLOWS (count);
2295 real = gtk_text_iter_make_real (iter);
2299 else if (count == 0)
2302 return gtk_text_iter_backward_chars (iter, 0 - count);
2303 else if (count < MAX_LINEAR_SCAN)
2305 check_invariants (iter);
2309 if (!forward_char (real))
2314 return forward_char (real);
2318 gint current_char_index;
2319 gint new_char_index;
2321 check_invariants (iter);
2323 current_char_index = gtk_text_iter_get_offset (iter);
2325 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2326 return FALSE; /* can't move forward */
2328 new_char_index = current_char_index + count;
2329 gtk_text_iter_set_offset (iter, new_char_index);
2331 check_invariants (iter);
2333 /* Return FALSE if we're on the non-dereferenceable end
2336 if (gtk_text_iter_is_end (iter))
2344 * gtk_text_iter_backward_chars:
2345 * @iter: an iterator
2346 * @count: number of characters to move
2348 * Moves @count characters backward, if possible (if @count would move
2349 * past the start or end of the buffer, moves to the start or end of
2350 * the buffer). The return value indicates whether the iterator moved
2351 * onto a dereferenceable position; if the iterator didn't move, or
2352 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2353 * the function does nothing and returns %FALSE.
2355 * Return value: whether @iter moved and is dereferenceable
2359 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2361 GtkTextRealIter *real;
2363 g_return_val_if_fail (iter != NULL, FALSE);
2365 FIX_OVERFLOWS (count);
2367 real = gtk_text_iter_make_real (iter);
2371 else if (count == 0)
2374 return gtk_text_iter_forward_chars (iter, 0 - count);
2376 ensure_char_offsets (real);
2377 check_invariants (iter);
2379 /* <, not <=, because if count == segment_char_offset
2380 * we're going to the front of the segment and the any_segment
2383 if (count < real->segment_char_offset)
2385 /* Optimize the within-segment case */
2386 g_assert (real->segment->char_count > 0);
2387 g_assert (real->segment->type == >k_text_char_type);
2389 real->segment_char_offset -= count;
2390 g_assert (real->segment_char_offset >= 0);
2392 if (real->line_byte_offset >= 0)
2395 gint new_byte_offset;
2398 p = g_utf8_offset_to_pointer (real->segment->body.chars,
2399 real->segment_char_offset);
2401 new_byte_offset = p - real->segment->body.chars;
2402 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2403 real->segment_byte_offset = new_byte_offset;
2406 real->line_char_offset -= count;
2408 adjust_char_index (real, 0 - count);
2410 check_invariants (iter);
2416 /* We need to go back into previous segments. For now,
2417 * just keep this really simple. FIXME
2418 * use backward_indexable_segment.
2420 if (TRUE || count > MAX_LINEAR_SCAN)
2422 gint current_char_index;
2423 gint new_char_index;
2425 current_char_index = gtk_text_iter_get_offset (iter);
2427 if (current_char_index == 0)
2428 return FALSE; /* can't move backward */
2430 new_char_index = current_char_index - count;
2431 if (new_char_index < 0)
2434 gtk_text_iter_set_offset (iter, new_char_index);
2436 check_invariants (iter);
2442 /* FIXME backward_indexable_segment here */
2451 /* These two can't be implemented efficiently (always have to use
2452 * a linear scan, since that's the only way to find all the non-text
2457 * gtk_text_iter_forward_text_chars:
2458 * @iter: a #GtkTextIter
2459 * @count: number of chars to move
2461 * Moves forward by @count text characters (pixbufs, widgets,
2462 * etc. do not count as characters for this). Equivalent to moving
2463 * through the results of gtk_text_iter_get_text (), rather than
2464 * gtk_text_iter_get_slice ().
2466 * Return value: whether @iter moved and is dereferenceable
2469 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2478 * gtk_text_iter_forward_text_chars:
2479 * @iter: a #GtkTextIter
2480 * @count: number of chars to move
2482 * Moves backward by @count text characters (pixbufs, widgets,
2483 * etc. do not count as characters for this). Equivalent to moving
2484 * through the results of gtk_text_iter_get_text (), rather than
2485 * gtk_text_iter_get_slice ().
2487 * Return value: whether @iter moved and is dereferenceable
2490 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2499 * gtk_text_iter_forward_line:
2500 * @iter: an iterator
2502 * Moves @iter to the start of the next line. Returns %TRUE if there
2503 * was a next line to move to, and %FALSE if @iter was simply moved to
2504 * the end of the buffer and is now not dereferenceable, or if @iter was
2505 * already at the end of the buffer.
2507 * Return value: whether @iter can be dereferenced
2510 gtk_text_iter_forward_line (GtkTextIter *iter)
2512 GtkTextRealIter *real;
2514 g_return_val_if_fail (iter != NULL, FALSE);
2516 real = gtk_text_iter_make_real (iter);
2521 check_invariants (iter);
2523 if (forward_line_leaving_caches_unmodified (real))
2525 invalidate_char_index (real);
2526 adjust_line_number (real, 1);
2528 check_invariants (iter);
2530 if (gtk_text_iter_is_end (iter))
2537 /* On the last line, move to end of it */
2539 if (!gtk_text_iter_is_end (iter))
2540 gtk_text_iter_forward_to_end (iter);
2542 check_invariants (iter);
2548 * gtk_text_iter_backward_line:
2549 * @iter: an iterator
2551 * Moves @iter to the start of the previous line. Returns %TRUE if
2552 * @iter could be moved; i.e. if @iter was at character offset 0, this
2553 * function returns %FALSE. Therefore if @iter was already on line 0,
2554 * but not at the start of the line, @iter is snapped to the start of
2555 * the line and the function returns %TRUE. (Note that this implies that
2556 * in a loop calling this function, the line number may not change on
2557 * every iteration, if your first iteration is on line 0.)
2559 * Return value: whether @iter moved
2562 gtk_text_iter_backward_line (GtkTextIter *iter)
2564 GtkTextLine *new_line;
2565 GtkTextRealIter *real;
2566 gboolean offset_will_change;
2569 g_return_val_if_fail (iter != NULL, FALSE);
2571 real = gtk_text_iter_make_real (iter);
2576 check_invariants (iter);
2578 new_line = _gtk_text_line_previous (real->line);
2580 offset_will_change = FALSE;
2581 if (real->line_char_offset > 0)
2582 offset_will_change = TRUE;
2584 if (new_line != NULL)
2586 real->line = new_line;
2588 adjust_line_number (real, -1);
2592 if (!offset_will_change)
2596 invalidate_char_index (real);
2598 real->line_byte_offset = 0;
2599 real->line_char_offset = 0;
2601 real->segment_byte_offset = 0;
2602 real->segment_char_offset = 0;
2604 /* Find first segment in line */
2605 real->any_segment = real->line->segments;
2606 real->segment = _gtk_text_line_byte_to_segment (real->line,
2609 g_assert (offset == 0);
2611 /* Note that if we are on the first line, we snap to the start of
2612 * the first line and return TRUE, so TRUE means the iterator
2613 * changed, not that the line changed; this is maybe a bit
2614 * weird. I'm not sure there's an obvious right thing to do though.
2617 check_invariants (iter);
2624 * gtk_text_iter_forward_lines:
2625 * @iter: a #GtkTextIter
2626 * @count: number of lines to move forward
2628 * Moves @count lines forward, if possible (if @count would move
2629 * past the start or end of the buffer, moves to the start or end of
2630 * the buffer). The return value indicates whether the iterator moved
2631 * onto a dereferenceable position; if the iterator didn't move, or
2632 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2633 * the function does nothing and returns %FALSE. If @count is negative,
2634 * moves backward by 0 - @count lines.
2636 * Return value: whether @iter moved and is dereferenceable
2639 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2641 FIX_OVERFLOWS (count);
2644 return gtk_text_iter_backward_lines (iter, 0 - count);
2645 else if (count == 0)
2647 else if (count == 1)
2649 check_invariants (iter);
2650 return gtk_text_iter_forward_line (iter);
2656 if (gtk_text_iter_is_end (iter))
2659 old_line = gtk_text_iter_get_line (iter);
2661 gtk_text_iter_set_line (iter, old_line + count);
2663 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2665 /* count went past the last line, so move to end of last line */
2666 if (!gtk_text_iter_is_end (iter))
2667 gtk_text_iter_forward_to_end (iter);
2670 return !gtk_text_iter_is_end (iter);
2675 * gtk_text_iter_backward_lines:
2676 * @iter: a #GtkTextIter
2677 * @count: number of lines to move backward
2679 * Moves @count lines backward, if possible (if @count would move
2680 * past the start or end of the buffer, moves to the start or end of
2681 * the buffer). The return value indicates whether the iterator moved
2682 * onto a dereferenceable position; if the iterator didn't move, or
2683 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2684 * the function does nothing and returns %FALSE. If @count is negative,
2685 * moves forward by 0 - @count lines.
2687 * Return value: whether @iter moved and is dereferenceable
2690 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2692 FIX_OVERFLOWS (count);
2695 return gtk_text_iter_forward_lines (iter, 0 - count);
2696 else if (count == 0)
2698 else if (count == 1)
2700 return gtk_text_iter_backward_line (iter);
2706 old_line = gtk_text_iter_get_line (iter);
2708 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2710 return (gtk_text_iter_get_line (iter) != old_line);
2715 * gtk_text_iter_forward_visible_line:
2716 * @iter: an iterator
2718 * Moves @iter to the start of the next visible line. Returns %TRUE if there
2719 * was a next line to move to, and %FALSE if @iter was simply moved to
2720 * the end of the buffer and is now not dereferenceable, or if @iter was
2721 * already at the end of the buffer.
2723 * Return value: whether @iter can be dereferenced
2728 gtk_text_iter_forward_visible_line (GtkTextIter *iter)
2730 while (gtk_text_iter_forward_line (iter))
2732 if (!_gtk_text_btree_char_is_invisible (iter))
2738 if (!gtk_text_iter_forward_char (iter))
2741 if (!_gtk_text_btree_char_is_invisible (iter))
2744 while (!gtk_text_iter_ends_line (iter));
2752 * gtk_text_iter_backward_visible_line:
2753 * @iter: an iterator
2755 * Moves @iter to the start of the previous visible line. Returns %TRUE if
2756 * @iter could be moved; i.e. if @iter was at character offset 0, this
2757 * function returns %FALSE. Therefore if @iter was already on line 0,
2758 * but not at the start of the line, @iter is snapped to the start of
2759 * the line and the function returns %TRUE. (Note that this implies that
2760 * in a loop calling this function, the line number may not change on
2761 * every iteration, if your first iteration is on line 0.)
2763 * Return value: whether @iter moved
2768 gtk_text_iter_backward_visible_line (GtkTextIter *iter)
2770 while (gtk_text_iter_backward_line (iter))
2772 if (!_gtk_text_btree_char_is_invisible (iter))
2778 if (!gtk_text_iter_backward_char (iter))
2781 if (!_gtk_text_btree_char_is_invisible (iter))
2784 while (!gtk_text_iter_starts_line (iter));
2792 * gtk_text_iter_forward_visible_lines:
2793 * @iter: a #GtkTextIter
2794 * @count: number of lines to move forward
2796 * Moves @count visible lines forward, if possible (if @count would move
2797 * past the start or end of the buffer, moves to the start or end of
2798 * the buffer). The return value indicates whether the iterator moved
2799 * onto a dereferenceable position; if the iterator didn't move, or
2800 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2801 * the function does nothing and returns %FALSE. If @count is negative,
2802 * moves backward by 0 - @count lines.
2804 * Return value: whether @iter moved and is dereferenceable
2809 gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
2812 FIX_OVERFLOWS (count);
2815 return gtk_text_iter_backward_visible_lines (iter, 0 - count);
2816 else if (count == 0)
2818 else if (count == 1)
2820 check_invariants (iter);
2821 return gtk_text_iter_forward_visible_line (iter);
2825 while (gtk_text_iter_forward_visible_line (iter) && count > 0)
2832 * gtk_text_iter_backward_visible_lines:
2833 * @iter: a #GtkTextIter
2834 * @count: number of lines to move backward
2836 * Moves @count visible lines backward, if possible (if @count would move
2837 * past the start or end of the buffer, moves to the start or end of
2838 * the buffer). The return value indicates whether the iterator moved
2839 * onto a dereferenceable position; if the iterator didn't move, or
2840 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2841 * the function does nothing and returns %FALSE. If @count is negative,
2842 * moves forward by 0 - @count lines.
2844 * Return value: whether @iter moved and is dereferenceable
2849 gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
2852 FIX_OVERFLOWS (count);
2855 return gtk_text_iter_forward_visible_lines (iter, 0 - count);
2856 else if (count == 0)
2858 else if (count == 1)
2860 return gtk_text_iter_backward_visible_line (iter);
2864 while (gtk_text_iter_backward_visible_line (iter) && count > 0)
2870 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2875 gboolean already_moved_initially);
2877 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2885 find_word_end_func (const PangoLogAttr *attrs,
2890 gboolean already_moved_initially)
2892 if (!already_moved_initially)
2895 /* Find end of next word */
2896 while (offset < min_offset + len &&
2897 !attrs[offset].is_word_end)
2900 *found_offset = offset;
2902 return offset < min_offset + len;
2906 is_word_end_func (const PangoLogAttr *attrs,
2911 return attrs[offset].is_word_end;
2915 find_word_start_func (const PangoLogAttr *attrs,
2920 gboolean already_moved_initially)
2922 if (!already_moved_initially)
2925 /* Find start of prev word */
2926 while (offset >= min_offset &&
2927 !attrs[offset].is_word_start)
2930 *found_offset = offset;
2932 return offset >= min_offset;
2936 is_word_start_func (const PangoLogAttr *attrs,
2941 return attrs[offset].is_word_start;
2945 inside_word_func (const PangoLogAttr *attrs,
2950 /* Find next word start or end */
2951 while (offset >= min_offset &&
2952 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2956 return attrs[offset].is_word_start;
2961 /* Sentence funcs */
2964 find_sentence_end_func (const PangoLogAttr *attrs,
2969 gboolean already_moved_initially)
2971 if (!already_moved_initially)
2974 /* Find end of next sentence */
2975 while (offset < min_offset + len &&
2976 !attrs[offset].is_sentence_end)
2979 *found_offset = offset;
2981 return offset < min_offset + len;
2985 is_sentence_end_func (const PangoLogAttr *attrs,
2990 return attrs[offset].is_sentence_end;
2994 find_sentence_start_func (const PangoLogAttr *attrs,
2999 gboolean already_moved_initially)
3001 if (!already_moved_initially)
3004 /* Find start of prev sentence */
3005 while (offset >= min_offset &&
3006 !attrs[offset].is_sentence_start)
3009 *found_offset = offset;
3011 return offset >= min_offset;
3015 is_sentence_start_func (const PangoLogAttr *attrs,
3020 return attrs[offset].is_sentence_start;
3024 inside_sentence_func (const PangoLogAttr *attrs,
3029 /* Find next sentence start or end */
3030 while (offset >= min_offset &&
3031 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
3034 return attrs[offset].is_sentence_start;
3038 test_log_attrs (const GtkTextIter *iter,
3039 TestLogAttrFunc func)
3042 const PangoLogAttr *attrs;
3044 gboolean result = FALSE;
3046 g_return_val_if_fail (iter != NULL, FALSE);
3048 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3051 offset = gtk_text_iter_get_line_offset (iter);
3053 /* char_len may be 0 and attrs will be NULL if so, if
3054 * iter is the end iter and the last line is empty.
3056 * offset may be equal to char_len, since attrs contains an entry
3057 * for one past the end
3060 if (attrs && offset <= char_len)
3061 result = (* func) (attrs, offset, 0, char_len);
3067 find_line_log_attrs (const GtkTextIter *iter,
3068 FindLogAttrFunc func,
3070 gboolean already_moved_initially)
3073 const PangoLogAttr *attrs;
3075 gboolean result = FALSE;
3077 g_return_val_if_fail (iter != NULL, FALSE);
3079 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3082 offset = gtk_text_iter_get_line_offset (iter);
3084 /* char_len may be 0 and attrs will be NULL if so, if
3085 * iter is the end iter and the last line is empty
3089 result = (* func) (attrs, offset, 0, char_len, found_offset,
3090 already_moved_initially);
3095 /* FIXME this function is very, very gratuitously slow */
3097 find_by_log_attrs (GtkTextIter *iter,
3098 FindLogAttrFunc func,
3100 gboolean already_moved_initially)
3104 gboolean found = FALSE;
3106 g_return_val_if_fail (iter != NULL, FALSE);
3110 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
3116 if (gtk_text_iter_forward_line (iter))
3117 return find_by_log_attrs (iter, func, forward,
3124 /* go to end of previous line. need to check that
3125 * line is > 0 because backward_line snaps to start of
3126 * line 0 if it's on line 0
3128 if (gtk_text_iter_get_line (iter) > 0 &&
3129 gtk_text_iter_backward_line (iter))
3131 if (!gtk_text_iter_ends_line (iter))
3132 gtk_text_iter_forward_to_line_end (iter);
3134 return find_by_log_attrs (iter, func, forward,
3143 gtk_text_iter_set_line_offset (iter, offset);
3146 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
3147 !gtk_text_iter_is_end (iter);
3152 find_visible_by_log_attrs (GtkTextIter *iter,
3153 FindLogAttrFunc func,
3155 gboolean already_moved_initially)
3159 g_return_val_if_fail (iter != NULL, FALSE);
3163 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3165 if (!_gtk_text_btree_char_is_invisible (&pos))
3175 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3176 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3179 move_multiple_steps (GtkTextIter *iter,
3181 OneStepFunc step_forward,
3182 MultipleStepFunc n_steps_backward)
3184 g_return_val_if_fail (iter != NULL, FALSE);
3186 FIX_OVERFLOWS (count);
3192 return n_steps_backward (iter, -count);
3194 if (!step_forward (iter))
3200 if (!step_forward (iter))
3205 return !gtk_text_iter_is_end (iter);
3210 * gtk_text_iter_forward_word_end:
3211 * @iter: a #GtkTextIter
3213 * Moves forward to the next word end. (If @iter is currently on a
3214 * word end, moves forward to the next one after that.) Word breaks
3215 * are determined by Pango and should be correct for nearly any
3216 * language (if not, the correct fix would be to the Pango word break
3219 * Return value: %TRUE if @iter moved and is not the end iterator
3222 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3224 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3228 * gtk_text_iter_backward_word_start:
3229 * @iter: a #GtkTextIter
3231 * Moves backward to the previous word start. (If @iter is currently on a
3232 * word start, moves backward to the next one after that.) Word breaks
3233 * are determined by Pango and should be correct for nearly any
3234 * language (if not, the correct fix would be to the Pango word break
3237 * Return value: %TRUE if @iter moved and is not the end iterator
3240 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3242 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3245 /* FIXME a loop around a truly slow function means
3246 * a truly spectacularly slow function.
3250 * gtk_text_iter_forward_word_ends:
3251 * @iter: a #GtkTextIter
3252 * @count: number of times to move
3254 * Calls gtk_text_iter_forward_word_end() up to @count times.
3256 * Return value: %TRUE if @iter moved and is not the end iterator
3259 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3262 return move_multiple_steps (iter, count,
3263 gtk_text_iter_forward_word_end,
3264 gtk_text_iter_backward_word_starts);
3268 * gtk_text_iter_backward_word_starts
3269 * @iter: a #GtkTextIter
3270 * @count: number of times to move
3272 * Calls gtk_text_iter_backward_word_start() up to @count times.
3274 * Return value: %TRUE if @iter moved and is not the end iterator
3277 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3280 return move_multiple_steps (iter, count,
3281 gtk_text_iter_backward_word_start,
3282 gtk_text_iter_forward_word_ends);
3286 * gtk_text_iter_forward_visible_word_end:
3287 * @iter: a #GtkTextIter
3289 * Moves forward to the next visible word end. (If @iter is currently on a
3290 * word end, moves forward to the next one after that.) Word breaks
3291 * are determined by Pango and should be correct for nearly any
3292 * language (if not, the correct fix would be to the Pango word break
3295 * Return value: %TRUE if @iter moved and is not the end iterator
3300 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3302 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3306 * gtk_text_iter_backward_visible_word_start:
3307 * @iter: a #GtkTextIter
3309 * Moves backward to the previous visible word start. (If @iter is currently
3310 * on a word start, moves backward to the next one after that.) Word breaks
3311 * are determined by Pango and should be correct for nearly any
3312 * language (if not, the correct fix would be to the Pango word break
3315 * Return value: %TRUE if @iter moved and is not the end iterator
3320 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3322 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3326 * gtk_text_iter_forward_visible_word_ends:
3327 * @iter: a #GtkTextIter
3328 * @count: number of times to move
3330 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3332 * Return value: %TRUE if @iter moved and is not the end iterator
3337 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3340 return move_multiple_steps (iter, count,
3341 gtk_text_iter_forward_visible_word_end,
3342 gtk_text_iter_backward_visible_word_starts);
3346 * gtk_text_iter_backward_visible_word_starts
3347 * @iter: a #GtkTextIter
3348 * @count: number of times to move
3350 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3352 * Return value: %TRUE if @iter moved and is not the end iterator
3357 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3360 return move_multiple_steps (iter, count,
3361 gtk_text_iter_backward_visible_word_start,
3362 gtk_text_iter_forward_visible_word_ends);
3366 * gtk_text_iter_starts_word:
3367 * @iter: a #GtkTextIter
3369 * Determines whether @iter begins a natural-language word. Word
3370 * breaks are determined by Pango and should be correct for nearly any
3371 * language (if not, the correct fix would be to the Pango word break
3374 * Return value: %TRUE if @iter is at the start of a word
3377 gtk_text_iter_starts_word (const GtkTextIter *iter)
3379 return test_log_attrs (iter, is_word_start_func);
3383 * gtk_text_iter_ends_word:
3384 * @iter: a #GtkTextIter
3386 * Determines whether @iter ends a natural-language word. Word breaks
3387 * are determined by Pango and should be correct for nearly any
3388 * language (if not, the correct fix would be to the Pango word break
3391 * Return value: %TRUE if @iter is at the end of a word
3394 gtk_text_iter_ends_word (const GtkTextIter *iter)
3396 return test_log_attrs (iter, is_word_end_func);
3400 * gtk_text_iter_inside_word:
3401 * @iter: a #GtkTextIter
3403 * Determines whether @iter is inside a natural-language word (as
3404 * opposed to say inside some whitespace). Word breaks are determined
3405 * by Pango and should be correct for nearly any language (if not, the
3406 * correct fix would be to the Pango word break algorithms).
3408 * Return value: %TRUE if @iter is inside a word
3411 gtk_text_iter_inside_word (const GtkTextIter *iter)
3413 return test_log_attrs (iter, inside_word_func);
3417 * gtk_text_iter_starts_sentence:
3418 * @iter: a #GtkTextIter
3420 * Determines whether @iter begins a sentence. Sentence boundaries are
3421 * determined by Pango and should be correct for nearly any language
3422 * (if not, the correct fix would be to the Pango text boundary
3425 * Return value: %TRUE if @iter is at the start of a sentence.
3428 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3430 return test_log_attrs (iter, is_sentence_start_func);
3434 * gtk_text_iter_ends_sentence:
3435 * @iter: a #GtkTextIter
3437 * Determines whether @iter ends a sentence. Sentence boundaries are
3438 * determined by Pango and should be correct for nearly any language
3439 * (if not, the correct fix would be to the Pango text boundary
3442 * Return value: %TRUE if @iter is at the end of a sentence.
3445 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3447 return test_log_attrs (iter, is_sentence_end_func);
3451 * gtk_text_iter_inside_sentence:
3452 * @iter: a #GtkTextIter
3454 * Determines whether @iter is inside a sentence (as opposed to in
3455 * between two sentences, e.g. after a period and before the first
3456 * letter of the next sentence). Sentence boundaries are determined
3457 * by Pango and should be correct for nearly any language (if not, the
3458 * correct fix would be to the Pango text boundary algorithms).
3460 * Return value: %TRUE if @iter is inside a sentence.
3463 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3465 return test_log_attrs (iter, inside_sentence_func);
3469 * gtk_text_iter_forward_sentence_end:
3470 * @iter: a #GtkTextIter
3472 * Moves forward to the next sentence end. (If @iter is at the end of
3473 * a sentence, moves to the next end of sentence.) Sentence
3474 * boundaries are determined by Pango and should be correct for nearly
3475 * any language (if not, the correct fix would be to the Pango text
3476 * boundary algorithms).
3478 * Return value: %TRUE if @iter moved and is not the end iterator
3481 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3483 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3487 * gtk_text_iter_backward_sentence_start:
3488 * @iter: a #GtkTextIter
3490 * Moves backward to the previous sentence start; if @iter is already at
3491 * the start of a sentence, moves backward to the next one. Sentence
3492 * boundaries are determined by Pango and should be correct for nearly
3493 * any language (if not, the correct fix would be to the Pango text
3494 * boundary algorithms).
3496 * Return value: %TRUE if @iter moved and is not the end iterator
3499 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3501 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3504 /* FIXME a loop around a truly slow function means
3505 * a truly spectacularly slow function.
3508 * gtk_text_iter_forward_sentence_ends:
3509 * @iter: a #GtkTextIter
3510 * @count: number of sentences to move
3512 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3513 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3514 * negative, moves backward instead of forward.
3516 * Return value: %TRUE if @iter moved and is not the end iterator
3519 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3522 return move_multiple_steps (iter, count,
3523 gtk_text_iter_forward_sentence_end,
3524 gtk_text_iter_backward_sentence_starts);
3528 * gtk_text_iter_backward_sentence_starts:
3529 * @iter: a #GtkTextIter
3530 * @count: number of sentences to move
3532 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3533 * or until it returns %FALSE. If @count is negative, moves forward
3534 * instead of backward.
3536 * Return value: %TRUE if @iter moved and is not the end iterator
3539 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3542 return move_multiple_steps (iter, count,
3543 gtk_text_iter_backward_sentence_start,
3544 gtk_text_iter_forward_sentence_ends);
3548 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3553 gboolean already_moved_initially)
3555 if (!already_moved_initially)
3558 while (offset < (min_offset + len) &&
3559 !attrs[offset].is_cursor_position)
3562 *found_offset = offset;
3564 return offset < (min_offset + len);
3568 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3573 gboolean already_moved_initially)
3575 if (!already_moved_initially)
3578 while (offset > min_offset &&
3579 !attrs[offset].is_cursor_position)
3582 *found_offset = offset;
3584 return offset >= min_offset;
3588 is_cursor_pos_func (const PangoLogAttr *attrs,
3593 return attrs[offset].is_cursor_position;
3597 * gtk_text_iter_forward_cursor_position:
3598 * @iter: a #GtkTextIter
3600 * Moves @iter forward by a single cursor position. Cursor positions
3601 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3602 * surprisingly, there may not be a cursor position between all
3603 * characters. The most common example for European languages would be
3604 * a carriage return/newline sequence. For some Unicode characters,
3605 * the equivalent of say the letter "a" with an accent mark will be
3606 * represented as two characters, first the letter then a "combining
3607 * mark" that causes the accent to be rendered; so the cursor can't go
3608 * between those two characters. See also the #PangoLogAttr structure and
3609 * pango_break() function.
3611 * Return value: %TRUE if we moved and the new position is dereferenceable
3614 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3616 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3620 * gtk_text_iter_backward_cursor_position:
3621 * @iter: a #GtkTextIter
3623 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3625 * Return value: %TRUE if we moved
3628 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3630 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3634 * gtk_text_iter_forward_cursor_positions:
3635 * @iter: a #GtkTextIter
3636 * @count: number of positions to move
3638 * Moves up to @count cursor positions. See
3639 * gtk_text_iter_forward_cursor_position() for details.
3641 * Return value: %TRUE if we moved and the new position is dereferenceable
3644 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3647 return move_multiple_steps (iter, count,
3648 gtk_text_iter_forward_cursor_position,
3649 gtk_text_iter_backward_cursor_positions);
3653 * gtk_text_iter_backward_cursor_positions:
3654 * @iter: a #GtkTextIter
3655 * @count: number of positions to move
3657 * Moves up to @count cursor positions. See
3658 * gtk_text_iter_forward_cursor_position() for details.
3660 * Return value: %TRUE if we moved and the new position is dereferenceable
3663 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3666 return move_multiple_steps (iter, count,
3667 gtk_text_iter_backward_cursor_position,
3668 gtk_text_iter_forward_cursor_positions);
3672 * gtk_text_iter_forward_visible_cursor_position:
3673 * @iter: a #GtkTextIter
3675 * Moves @iter forward to the next visible cursor position. See
3676 * gtk_text_iter_forward_cursor_position() for details.
3678 * Return value: %TRUE if we moved and the new position is dereferenceable
3683 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3685 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3689 * gtk_text_iter_backward_visible_cursor_position:
3690 * @iter: a #GtkTextIter
3692 * Moves @iter forward to the previous visible cursor position. See
3693 * gtk_text_iter_backward_cursor_position() for details.
3695 * Return value: %TRUE if we moved and the new position is dereferenceable
3700 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3702 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3706 * gtk_text_iter_forward_visible_cursor_positions:
3707 * @iter: a #GtkTextIter
3708 * @count: number of positions to move
3710 * Moves up to @count visible cursor positions. See
3711 * gtk_text_iter_forward_cursor_position() for details.
3713 * Return value: %TRUE if we moved and the new position is dereferenceable
3718 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3721 return move_multiple_steps (iter, count,
3722 gtk_text_iter_forward_visible_cursor_position,
3723 gtk_text_iter_backward_visible_cursor_positions);
3727 * gtk_text_iter_backward_visible_cursor_positions:
3728 * @iter: a #GtkTextIter
3729 * @count: number of positions to move
3731 * Moves up to @count visible cursor positions. See
3732 * gtk_text_iter_backward_cursor_position() for details.
3734 * Return value: %TRUE if we moved and the new position is dereferenceable
3739 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3742 return move_multiple_steps (iter, count,
3743 gtk_text_iter_backward_visible_cursor_position,
3744 gtk_text_iter_forward_visible_cursor_positions);
3748 * gtk_text_iter_is_cursor_position:
3749 * @iter: a #GtkTextIter
3751 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3752 * pango_break() for details on what a cursor position is.
3754 * Return value: %TRUE if the cursor can be placed at @iter
3757 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3759 return test_log_attrs (iter, is_cursor_pos_func);
3763 * gtk_text_iter_set_line_offset:
3764 * @iter: a #GtkTextIter
3765 * @char_on_line: a character offset relative to the start of @iter's current line
3767 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3768 * (not byte) offset. The given character offset must be less than or
3769 * equal to the number of characters in the line; if equal, @iter
3770 * moves to the start of the next line. See
3771 * gtk_text_iter_set_line_index() if you have a byte index rather than
3772 * a character offset.
3776 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3779 GtkTextRealIter *real;
3782 g_return_if_fail (iter != NULL);
3784 real = gtk_text_iter_make_surreal (iter);
3789 check_invariants (iter);
3791 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3793 g_return_if_fail (char_on_line <= chars_in_line);
3795 if (char_on_line < chars_in_line)
3796 iter_set_from_char_offset (real, real->line, char_on_line);
3798 gtk_text_iter_forward_line (iter); /* set to start of next line */
3800 check_invariants (iter);
3804 * gtk_text_iter_set_line_index:
3805 * @iter: a #GtkTextIter
3806 * @byte_on_line: a byte index relative to the start of @iter's current line
3808 * Same as gtk_text_iter_set_line_offset(), but works with a
3809 * <emphasis>byte</emphasis> index. The given byte index must be at
3810 * the start of a character, it can't be in the middle of a UTF-8
3811 * encoded character.
3815 gtk_text_iter_set_line_index (GtkTextIter *iter,
3818 GtkTextRealIter *real;
3821 g_return_if_fail (iter != NULL);
3823 real = gtk_text_iter_make_surreal (iter);
3828 check_invariants (iter);
3830 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3832 g_return_if_fail (byte_on_line <= bytes_in_line);
3834 if (byte_on_line < bytes_in_line)
3835 iter_set_from_byte_offset (real, real->line, byte_on_line);
3837 gtk_text_iter_forward_line (iter);
3839 if (real->segment->type == >k_text_char_type &&
3840 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3841 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3842 "character; this will crash the text buffer. "
3843 "Byte indexes must refer to the start of a character.",
3844 G_STRLOC, byte_on_line);
3846 check_invariants (iter);
3851 * gtk_text_iter_set_visible_line_offset:
3852 * @iter: a #GtkTextIter
3853 * @char_on_line: a character offset
3855 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3856 * characters, i.e. text with a tag making it invisible is not
3857 * counted in the offset.
3860 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3863 gint chars_seen = 0;
3866 g_return_if_fail (iter != NULL);
3868 gtk_text_iter_set_line_offset (iter, 0);
3872 /* For now we use a ludicrously slow implementation */
3873 while (chars_seen < char_on_line)
3875 if (!_gtk_text_btree_char_is_invisible (&pos))
3878 if (!gtk_text_iter_forward_char (&pos))
3881 if (chars_seen == char_on_line)
3885 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3888 gtk_text_iter_forward_line (iter);
3892 bytes_in_char (GtkTextIter *iter)
3894 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3898 * gtk_text_iter_set_visible_line_index:
3899 * @iter: a #GtkTextIter
3900 * @byte_on_line: a byte index
3902 * Like gtk_text_iter_set_line_index(), but the index is in visible
3903 * bytes, i.e. text with a tag making it invisible is not counted
3907 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3910 gint bytes_seen = 0;
3914 g_return_if_fail (iter != NULL);
3916 gtk_text_iter_set_line_offset (iter, 0);
3920 /* For now we use a ludicrously slow implementation */
3921 while (bytes_seen < byte_on_line)
3923 if (!_gtk_text_btree_char_is_invisible (&pos))
3924 bytes_seen += bytes_in_char (&pos);
3927 if (!gtk_text_iter_forward_char (&pos))
3930 if (bytes_seen >= byte_on_line)
3934 if (bytes_seen > byte_on_line)
3935 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3936 "character; this will crash the text buffer. "
3937 "Byte indexes must refer to the start of a character.",
3938 G_STRLOC, byte_on_line);
3940 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3943 gtk_text_iter_forward_line (iter);
3947 * gtk_text_iter_set_line:
3948 * @iter: a #GtkTextIter
3949 * @line_number: line number (counted from 0)
3951 * Moves iterator @iter to the start of the line @line_number. If
3952 * @line_number is negative or larger than the number of lines in the
3953 * buffer, moves @iter to the start of the last line in the buffer.
3957 gtk_text_iter_set_line (GtkTextIter *iter,
3962 GtkTextRealIter *real;
3964 g_return_if_fail (iter != NULL);
3966 real = gtk_text_iter_make_surreal (iter);
3971 check_invariants (iter);
3973 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3975 iter_set_from_char_offset (real, line, 0);
3977 /* We might as well cache this, since we know it. */
3978 real->cached_line_number = real_line;
3980 check_invariants (iter);
3984 * gtk_text_iter_set_offset:
3985 * @iter: a #GtkTextIter
3986 * @char_offset: a character number
3988 * Sets @iter to point to @char_offset. @char_offset counts from the start
3989 * of the entire text buffer, starting with 0.
3992 gtk_text_iter_set_offset (GtkTextIter *iter,
3996 GtkTextRealIter *real;
3998 gint real_char_index;
4000 g_return_if_fail (iter != NULL);
4002 real = gtk_text_iter_make_surreal (iter);
4007 check_invariants (iter);
4009 if (real->cached_char_index >= 0 &&
4010 real->cached_char_index == char_offset)
4013 line = _gtk_text_btree_get_line_at_char (real->tree,
4018 iter_set_from_char_offset (real, line, real_char_index - line_start);
4020 /* Go ahead and cache this since we have it. */
4021 real->cached_char_index = real_char_index;
4023 check_invariants (iter);
4027 * gtk_text_iter_forward_to_end:
4028 * @iter: a #GtkTextIter
4030 * Moves @iter forward to the "end iterator," which points one past the last
4031 * valid character in the buffer. gtk_text_iter_get_char() called on the
4032 * end iterator returns 0, which is convenient for writing loops.
4035 gtk_text_iter_forward_to_end (GtkTextIter *iter)
4037 GtkTextBuffer *buffer;
4038 GtkTextRealIter *real;
4040 g_return_if_fail (iter != NULL);
4042 real = gtk_text_iter_make_surreal (iter);
4047 buffer = _gtk_text_btree_get_buffer (real->tree);
4049 gtk_text_buffer_get_end_iter (buffer, iter);
4052 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
4053 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
4054 * If all else fails we could cache the para delimiter pos in the iter.
4055 * I think forward_to_line_end() actually gets called fairly often.
4058 find_paragraph_delimiter_for_line (GtkTextIter *iter)
4063 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
4064 _gtk_text_iter_get_btree (&end)))
4066 gtk_text_iter_forward_to_end (&end);
4070 /* if we aren't on the last line, go forward to start of next line, then scan
4071 * back for the delimiters on the previous line
4073 gtk_text_iter_forward_line (&end);
4074 gtk_text_iter_backward_char (&end);
4075 while (!gtk_text_iter_ends_line (&end))
4076 gtk_text_iter_backward_char (&end);
4079 return gtk_text_iter_get_line_offset (&end);
4083 * gtk_text_iter_forward_to_line_end:
4084 * @iter: a #GtkTextIter
4086 * Moves the iterator to point to the paragraph delimiter characters,
4087 * which will be either a newline, a carriage return, a carriage
4088 * return/newline in sequence, or the Unicode paragraph separator
4089 * character. If the iterator is already at the paragraph delimiter
4090 * characters, moves to the paragraph delimiter characters for the
4091 * next line. If @iter is on the last line in the buffer, which does
4092 * not end in paragraph delimiters, moves to the end iterator (end of
4093 * the last line), and returns %FALSE.
4095 * Return value: %TRUE if we moved and the new location is not the end iterator
4098 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
4100 gint current_offset;
4104 g_return_val_if_fail (iter != NULL, FALSE);
4106 current_offset = gtk_text_iter_get_line_offset (iter);
4107 new_offset = find_paragraph_delimiter_for_line (iter);
4109 if (current_offset < new_offset)
4111 /* Move to end of this line. */
4112 gtk_text_iter_set_line_offset (iter, new_offset);
4113 return !gtk_text_iter_is_end (iter);
4117 /* Move to end of next line. */
4118 if (gtk_text_iter_forward_line (iter))
4120 /* We don't want to move past all
4123 if (!gtk_text_iter_ends_line (iter))
4124 gtk_text_iter_forward_to_line_end (iter);
4125 return !gtk_text_iter_is_end (iter);
4133 * gtk_text_iter_forward_to_tag_toggle:
4134 * @iter: a #GtkTextIter
4135 * @tag: a #GtkTextTag, or %NULL
4137 * Moves forward to the next toggle (on or off) of the
4138 * #GtkTextTag @tag, or to the next toggle of any tag if
4139 * @tag is %NULL. If no matching tag toggles are found,
4140 * returns %FALSE, otherwise %TRUE. Does not return toggles
4141 * located at @iter, only toggles after @iter. Sets @iter to
4142 * the location of the toggle, or to the end of the buffer
4143 * if no toggle is found.
4145 * Return value: whether we found a tag toggle after @iter
4148 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4151 GtkTextLine *next_line;
4152 GtkTextLine *current_line;
4153 GtkTextRealIter *real;
4155 g_return_val_if_fail (iter != NULL, FALSE);
4157 real = gtk_text_iter_make_real (iter);
4162 check_invariants (iter);
4164 current_line = real->line;
4165 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4168 while (_gtk_text_iter_forward_indexable_segment (iter))
4170 /* If we went forward to a line that couldn't contain a toggle
4171 for the tag, then skip forward to a line that could contain
4172 it. This potentially skips huge hunks of the tree, so we
4173 aren't a purely linear search. */
4174 if (real->line != current_line)
4176 if (next_line == NULL)
4178 /* End of search. Set to end of buffer. */
4179 _gtk_text_btree_get_end_iter (real->tree, iter);
4183 if (real->line != next_line)
4184 iter_set_from_byte_offset (real, next_line, 0);
4186 current_line = real->line;
4187 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4192 if (gtk_text_iter_toggles_tag (iter, tag))
4194 /* If there's a toggle here, it isn't indexable so
4195 any_segment can't be the indexable segment. */
4196 g_assert (real->any_segment != real->segment);
4201 /* Check end iterator for tags */
4202 if (gtk_text_iter_toggles_tag (iter, tag))
4204 /* If there's a toggle here, it isn't indexable so
4205 any_segment can't be the indexable segment. */
4206 g_assert (real->any_segment != real->segment);
4210 /* Reached end of buffer */
4215 * gtk_text_iter_backward_to_tag_toggle:
4216 * @iter: a #GtkTextIter
4217 * @tag: a #GtkTextTag, or %NULL
4219 * Moves backward to the next toggle (on or off) of the
4220 * #GtkTextTag @tag, or to the next toggle of any tag if
4221 * @tag is %NULL. If no matching tag toggles are found,
4222 * returns %FALSE, otherwise %TRUE. Does not return toggles
4223 * located at @iter, only toggles before @iter. Sets @iter
4224 * to the location of the toggle, or the start of the buffer
4225 * if no toggle is found.
4227 * Return value: whether we found a tag toggle before @iter
4230 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4233 GtkTextLine *prev_line;
4234 GtkTextLine *current_line;
4235 GtkTextRealIter *real;
4237 g_return_val_if_fail (iter != NULL, FALSE);
4239 real = gtk_text_iter_make_real (iter);
4244 check_invariants (iter);
4246 current_line = real->line;
4247 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4251 /* If we're at segment start, go to the previous segment;
4252 * if mid-segment, snap to start of current segment.
4254 if (is_segment_start (real))
4256 if (!_gtk_text_iter_backward_indexable_segment (iter))
4261 ensure_char_offsets (real);
4263 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4269 /* If we went backward to a line that couldn't contain a toggle
4270 * for the tag, then skip backward further to a line that
4271 * could contain it. This potentially skips huge hunks of the
4272 * tree, so we aren't a purely linear search.
4274 if (real->line != current_line)
4276 if (prev_line == NULL)
4278 /* End of search. Set to start of buffer. */
4279 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4283 if (real->line != prev_line)
4285 /* Set to last segment in prev_line (could do this
4288 iter_set_from_byte_offset (real, prev_line, 0);
4290 while (!at_last_indexable_segment (real))
4291 _gtk_text_iter_forward_indexable_segment (iter);
4294 current_line = real->line;
4295 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4300 if (gtk_text_iter_toggles_tag (iter, tag))
4302 /* If there's a toggle here, it isn't indexable so
4303 * any_segment can't be the indexable segment.
4305 g_assert (real->any_segment != real->segment);
4309 while (_gtk_text_iter_backward_indexable_segment (iter));
4311 /* Reached front of buffer */
4316 matches_pred (GtkTextIter *iter,
4317 GtkTextCharPredicate pred,
4322 ch = gtk_text_iter_get_char (iter);
4324 return (*pred) (ch, user_data);
4328 * gtk_text_iter_forward_find_char:
4329 * @iter: a #GtkTextIter
4330 * @pred: a function to be called on each character
4331 * @user_data: user data for @pred
4332 * @limit: search limit, or %NULL for none
4334 * Advances @iter, calling @pred on each character. If
4335 * @pred returns %TRUE, returns %TRUE and stops scanning.
4336 * If @pred never returns %TRUE, @iter is set to @limit if
4337 * @limit is non-%NULL, otherwise to the end iterator.
4339 * Return value: whether a match was found
4342 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4343 GtkTextCharPredicate pred,
4345 const GtkTextIter *limit)
4347 g_return_val_if_fail (iter != NULL, FALSE);
4348 g_return_val_if_fail (pred != NULL, FALSE);
4351 gtk_text_iter_compare (iter, limit) >= 0)
4354 while ((limit == NULL ||
4355 !gtk_text_iter_equal (limit, iter)) &&
4356 gtk_text_iter_forward_char (iter))
4358 if (matches_pred (iter, pred, user_data))
4366 * gtk_text_iter_backward_find_char:
4367 * @iter: a #GtkTextIter
4368 * @pred: function to be called on each character
4369 * @user_data: user data for @pred
4370 * @limit: search limit, or %NULL for none
4372 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4374 * Return value: whether a match was found
4377 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4378 GtkTextCharPredicate pred,
4380 const GtkTextIter *limit)
4382 g_return_val_if_fail (iter != NULL, FALSE);
4383 g_return_val_if_fail (pred != NULL, FALSE);
4386 gtk_text_iter_compare (iter, limit) <= 0)
4389 while ((limit == NULL ||
4390 !gtk_text_iter_equal (limit, iter)) &&
4391 gtk_text_iter_backward_char (iter))
4393 if (matches_pred (iter, pred, user_data))
4401 forward_chars_with_skipping (GtkTextIter *iter,
4403 gboolean skip_invisible,
4404 gboolean skip_nontext)
4409 g_return_if_fail (count >= 0);
4415 gboolean ignored = FALSE;
4418 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4423 _gtk_text_btree_char_is_invisible (iter))
4426 gtk_text_iter_forward_char (iter);
4434 lines_match (const GtkTextIter *start,
4435 const gchar **lines,
4436 gboolean visible_only,
4438 GtkTextIter *match_start,
4439 GtkTextIter *match_end)
4446 if (*lines == NULL || **lines == '\0')
4449 *match_start = *start;
4452 *match_end = *start;
4457 gtk_text_iter_forward_line (&next);
4459 /* No more text in buffer, but *lines is nonempty */
4460 if (gtk_text_iter_equal (start, &next))
4468 line_text = gtk_text_iter_get_visible_slice (start, &next);
4470 line_text = gtk_text_iter_get_slice (start, &next);
4475 line_text = gtk_text_iter_get_visible_text (start, &next);
4477 line_text = gtk_text_iter_get_text (start, &next);
4480 if (match_start) /* if this is the first line we're matching */
4481 found = strstr (line_text, *lines);
4484 /* If it's not the first line, we have to match from the
4485 * start of the line.
4487 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4499 /* Get offset to start of search string */
4500 offset = g_utf8_strlen (line_text, found - line_text);
4504 /* If match start needs to be returned, set it to the
4505 * start of the search string.
4509 *match_start = next;
4511 forward_chars_with_skipping (match_start, offset,
4512 visible_only, !slice);
4515 /* Go to end of search string */
4516 offset += g_utf8_strlen (*lines, -1);
4518 forward_chars_with_skipping (&next, offset,
4519 visible_only, !slice);
4528 /* pass NULL for match_start, since we don't need to find the
4531 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4534 /* strsplit () that retains the delimiter as part of the string. */
4536 strbreakup (const char *string,
4537 const char *delimiter,
4540 GSList *string_list = NULL, *slist;
4541 gchar **str_array, *s;
4544 g_return_val_if_fail (string != NULL, NULL);
4545 g_return_val_if_fail (delimiter != NULL, NULL);
4548 max_tokens = G_MAXINT;
4550 s = strstr (string, delimiter);
4553 guint delimiter_len = strlen (delimiter);
4560 len = s - string + delimiter_len;
4561 new_string = g_new (gchar, len + 1);
4562 strncpy (new_string, string, len);
4563 new_string[len] = 0;
4564 string_list = g_slist_prepend (string_list, new_string);
4566 string = s + delimiter_len;
4567 s = strstr (string, delimiter);
4569 while (--max_tokens && s);
4574 string_list = g_slist_prepend (string_list, g_strdup (string));
4577 str_array = g_new (gchar*, n);
4581 str_array[i--] = NULL;
4582 for (slist = string_list; slist; slist = slist->next)
4583 str_array[i--] = slist->data;
4585 g_slist_free (string_list);
4591 * gtk_text_iter_forward_search:
4592 * @iter: start of search
4593 * @str: a search string
4594 * @flags: flags affecting how the search is done
4595 * @match_start: return location for start of match, or %NULL
4596 * @match_end: return location for end of match, or %NULL
4597 * @limit: bound for the search, or %NULL for the end of the buffer
4599 * Searches forward for @str. Any match is returned by setting
4600 * @match_start to the first character of the match and @match_end to the
4601 * first character after the match. The search will not continue past
4602 * @limit. Note that a search is a linear or O(n) operation, so you
4603 * may wish to use @limit to avoid locking up your UI on large
4606 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4607 * have invisible text interspersed in @str. i.e. @str will be a
4608 * possibly-noncontiguous subsequence of the matched range. similarly,
4609 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4610 * pixbufs or child widgets mixed inside the matched range. If these
4611 * flags are not given, the match must be exact; the special 0xFFFC
4612 * character in @str will match embedded pixbufs or child widgets.
4614 * Return value: whether a match was found
4617 gtk_text_iter_forward_search (const GtkTextIter *iter,
4619 GtkTextSearchFlags flags,
4620 GtkTextIter *match_start,
4621 GtkTextIter *match_end,
4622 const GtkTextIter *limit)
4624 gchar **lines = NULL;
4626 gboolean retval = FALSE;
4628 gboolean visible_only;
4631 g_return_val_if_fail (iter != NULL, FALSE);
4632 g_return_val_if_fail (str != NULL, FALSE);
4635 gtk_text_iter_compare (iter, limit) >= 0)
4640 /* If we can move one char, return the empty string there */
4643 if (gtk_text_iter_forward_char (&match))
4646 gtk_text_iter_equal (&match, limit))
4650 *match_start = match;
4659 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4660 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4662 /* locate all lines */
4664 lines = strbreakup (str, "\n", -1);
4670 /* This loop has an inefficient worst-case, where
4671 * gtk_text_iter_get_text () is called repeatedly on
4677 gtk_text_iter_compare (&search, limit) >= 0)
4680 if (lines_match (&search, (const gchar**)lines,
4681 visible_only, slice, &match, &end))
4683 if (limit == NULL ||
4685 gtk_text_iter_compare (&end, limit) <= 0))
4690 *match_start = match;
4699 while (gtk_text_iter_forward_line (&search));
4701 g_strfreev ((gchar**)lines);
4707 vectors_equal_ignoring_trailing (gchar **vec1,
4710 /* Ignores trailing chars in vec2's last line */
4719 if (strcmp (*i1, *i2) != 0)
4721 if (*(i2 + 1) == NULL) /* if this is the last line */
4723 gint len1 = strlen (*i1);
4724 gint len2 = strlen (*i2);
4727 strncmp (*i1, *i2, len1) == 0)
4729 /* We matched ignoring the trailing stuff in vec2 */
4754 typedef struct _LinesWindow LinesWindow;
4760 GtkTextIter first_line_start;
4761 GtkTextIter first_line_end;
4763 gboolean visible_only;
4767 lines_window_init (LinesWindow *win,
4768 const GtkTextIter *start)
4771 GtkTextIter line_start;
4772 GtkTextIter line_end;
4774 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4777 if (gtk_text_iter_is_start (start) ||
4778 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4780 /* Already at the end, or not enough lines to match */
4781 win->lines = g_new0 (gchar*, 1);
4786 line_start = *start;
4789 /* Move to start iter to start of line */
4790 gtk_text_iter_set_line_offset (&line_start, 0);
4792 if (gtk_text_iter_equal (&line_start, &line_end))
4794 /* we were already at the start; so go back one line */
4795 gtk_text_iter_backward_line (&line_start);
4798 win->first_line_start = line_start;
4799 win->first_line_end = line_end;
4801 win->lines = g_new0 (gchar*, win->n_lines + 1);
4803 i = win->n_lines - 1;
4810 if (win->visible_only)
4811 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4813 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4817 if (win->visible_only)
4818 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4820 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4823 win->lines[i] = line_text;
4825 line_end = line_start;
4826 gtk_text_iter_backward_line (&line_start);
4833 lines_window_back (LinesWindow *win)
4835 GtkTextIter new_start;
4838 new_start = win->first_line_start;
4840 if (!gtk_text_iter_backward_line (&new_start))
4844 win->first_line_start = new_start;
4845 win->first_line_end = new_start;
4847 gtk_text_iter_forward_line (&win->first_line_end);
4852 if (win->visible_only)
4853 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4854 &win->first_line_end);
4856 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4857 &win->first_line_end);
4861 if (win->visible_only)
4862 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4863 &win->first_line_end);
4865 line_text = gtk_text_iter_get_text (&win->first_line_start,
4866 &win->first_line_end);
4869 /* Move lines to make room for first line. */
4870 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4872 *win->lines = line_text;
4874 /* Free old last line and NULL-terminate */
4875 g_free (win->lines[win->n_lines]);
4876 win->lines[win->n_lines] = NULL;
4882 lines_window_free (LinesWindow *win)
4884 g_strfreev (win->lines);
4888 * gtk_text_iter_backward_search:
4889 * @iter: a #GtkTextIter where the search begins
4890 * @str: search string
4891 * @flags: bitmask of flags affecting the search
4892 * @match_start: return location for start of match, or %NULL
4893 * @match_end: return location for end of match, or %NULL
4894 * @limit: location of last possible @match_start, or %NULL for start of buffer
4896 * Same as gtk_text_iter_forward_search(), but moves backward.
4898 * Return value: whether a match was found
4901 gtk_text_iter_backward_search (const GtkTextIter *iter,
4903 GtkTextSearchFlags flags,
4904 GtkTextIter *match_start,
4905 GtkTextIter *match_end,
4906 const GtkTextIter *limit)
4908 gchar **lines = NULL;
4912 gboolean retval = FALSE;
4913 gboolean visible_only;
4916 g_return_val_if_fail (iter != NULL, FALSE);
4917 g_return_val_if_fail (str != NULL, FALSE);
4920 gtk_text_iter_compare (limit, iter) > 0)
4925 /* If we can move one char, return the empty string there */
4926 GtkTextIter match = *iter;
4928 if (limit && gtk_text_iter_equal (limit, &match))
4931 if (gtk_text_iter_backward_char (&match))
4934 *match_start = match;
4943 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4944 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4946 /* locate all lines */
4948 lines = strbreakup (str, "\n", -1);
4958 win.n_lines = n_lines;
4960 win.visible_only = visible_only;
4962 lines_window_init (&win, iter);
4964 if (*win.lines == NULL)
4969 gchar *first_line_match;
4972 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4974 /* We're now before the search limit, abort. */
4978 /* If there are multiple lines, the first line will
4979 * end in '\n', so this will only match at the
4980 * end of the first line, which is correct.
4982 first_line_match = g_strrstr (*win.lines, *lines);
4984 if (first_line_match &&
4985 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4990 GtkTextIter start_tmp;
4992 /* Offset to start of search string */
4993 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4995 next = win.first_line_start;
4997 forward_chars_with_skipping (&start_tmp, offset,
4998 visible_only, !slice);
5001 gtk_text_iter_compare (limit, &start_tmp) > 0)
5002 goto out; /* match was bogus */
5005 *match_start = start_tmp;
5007 /* Go to end of search string */
5011 offset += g_utf8_strlen (*l, -1);
5015 forward_chars_with_skipping (&next, offset,
5016 visible_only, !slice);
5025 while (lines_window_back (&win));
5028 lines_window_free (&win);
5039 * gtk_text_iter_equal:
5040 * @lhs: a #GtkTextIter
5041 * @rhs: another #GtkTextIter
5043 * Tests whether two iterators are equal, using the fastest possible
5044 * mechanism. This function is very fast; you can expect it to perform
5045 * better than e.g. getting the character offset for each iterator and
5046 * comparing the offsets yourself. Also, it's a bit faster than
5047 * gtk_text_iter_compare().
5049 * Return value: %TRUE if the iterators point to the same place in the buffer
5052 gtk_text_iter_equal (const GtkTextIter *lhs,
5053 const GtkTextIter *rhs)
5055 GtkTextRealIter *real_lhs;
5056 GtkTextRealIter *real_rhs;
5058 real_lhs = (GtkTextRealIter*)lhs;
5059 real_rhs = (GtkTextRealIter*)rhs;
5061 check_invariants (lhs);
5062 check_invariants (rhs);
5064 if (real_lhs->line != real_rhs->line)
5066 else if (real_lhs->line_byte_offset >= 0 &&
5067 real_rhs->line_byte_offset >= 0)
5068 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5071 /* the ensure_char_offsets () calls do nothing if the char offsets
5072 are already up-to-date. */
5073 ensure_char_offsets (real_lhs);
5074 ensure_char_offsets (real_rhs);
5075 return real_lhs->line_char_offset == real_rhs->line_char_offset;
5080 * gtk_text_iter_compare:
5081 * @lhs: a #GtkTextIter
5082 * @rhs: another #GtkTextIter
5084 * A qsort()-style function that returns negative if @lhs is less than
5085 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5086 * Ordering is in character offset order, i.e. the first character in the buffer
5087 * is less than the second character in the buffer.
5089 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5092 gtk_text_iter_compare (const GtkTextIter *lhs,
5093 const GtkTextIter *rhs)
5095 GtkTextRealIter *real_lhs;
5096 GtkTextRealIter *real_rhs;
5098 real_lhs = gtk_text_iter_make_surreal (lhs);
5099 real_rhs = gtk_text_iter_make_surreal (rhs);
5101 if (real_lhs == NULL ||
5103 return -1; /* why not */
5105 check_invariants (lhs);
5106 check_invariants (rhs);
5108 if (real_lhs->line == real_rhs->line)
5110 gint left_index, right_index;
5112 if (real_lhs->line_byte_offset >= 0 &&
5113 real_rhs->line_byte_offset >= 0)
5115 left_index = real_lhs->line_byte_offset;
5116 right_index = real_rhs->line_byte_offset;
5120 /* the ensure_char_offsets () calls do nothing if
5121 the offsets are already up-to-date. */
5122 ensure_char_offsets (real_lhs);
5123 ensure_char_offsets (real_rhs);
5124 left_index = real_lhs->line_char_offset;
5125 right_index = real_rhs->line_char_offset;
5128 if (left_index < right_index)
5130 else if (left_index > right_index)
5139 line1 = gtk_text_iter_get_line (lhs);
5140 line2 = gtk_text_iter_get_line (rhs);
5143 else if (line1 > line2)
5151 * gtk_text_iter_in_range:
5152 * @iter: a #GtkTextIter
5153 * @start: start of range
5154 * @end: end of range
5156 * Checks whether @iter falls in the range [@start, @end).
5157 * @start and @end must be in ascending order.
5159 * Return value: %TRUE if @iter is in the range
5162 gtk_text_iter_in_range (const GtkTextIter *iter,
5163 const GtkTextIter *start,
5164 const GtkTextIter *end)
5166 g_return_val_if_fail (iter != NULL, FALSE);
5167 g_return_val_if_fail (start != NULL, FALSE);
5168 g_return_val_if_fail (end != NULL, FALSE);
5169 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5171 return gtk_text_iter_compare (iter, start) >= 0 &&
5172 gtk_text_iter_compare (iter, end) < 0;
5176 * gtk_text_iter_order:
5177 * @first: a #GtkTextIter
5178 * @second: another #GtkTextIter
5180 * Swaps the value of @first and @second if @second comes before
5181 * @first in the buffer. That is, ensures that @first and @second are
5182 * in sequence. Most text buffer functions that take a range call this
5183 * automatically on your behalf, so there's no real reason to call it yourself
5184 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5185 * that expect a pre-sorted range.
5189 gtk_text_iter_order (GtkTextIter *first,
5190 GtkTextIter *second)
5192 g_return_if_fail (first != NULL);
5193 g_return_if_fail (second != NULL);
5195 if (gtk_text_iter_compare (first, second) > 0)
5206 * Init iterators from the BTree
5210 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5214 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5215 gint real_char_index;
5219 g_return_if_fail (iter != NULL);
5220 g_return_if_fail (tree != NULL);
5222 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5223 &line_start, &real_char_index);
5225 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5227 real->cached_char_index = real_char_index;
5229 check_invariants (iter);
5233 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5238 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5242 g_return_if_fail (iter != NULL);
5243 g_return_if_fail (tree != NULL);
5245 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5247 iter_init_from_char_offset (iter, tree, line, char_on_line);
5249 /* We might as well cache this, since we know it. */
5250 real->cached_line_number = real_line;
5252 check_invariants (iter);
5256 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5261 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5265 g_return_if_fail (iter != NULL);
5266 g_return_if_fail (tree != NULL);
5268 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5270 iter_init_from_byte_offset (iter, tree, line, byte_index);
5272 /* We might as well cache this, since we know it. */
5273 real->cached_line_number = real_line;
5275 check_invariants (iter);
5279 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5284 g_return_if_fail (iter != NULL);
5285 g_return_if_fail (tree != NULL);
5286 g_return_if_fail (line != NULL);
5288 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5290 check_invariants (iter);
5294 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5300 g_return_val_if_fail (iter != NULL, FALSE);
5301 g_return_val_if_fail (tree != NULL, FALSE);
5303 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5307 /* Set iter to last in tree */
5308 _gtk_text_btree_get_end_iter (tree, iter);
5309 check_invariants (iter);
5314 iter_init_from_byte_offset (iter, tree, line, 0);
5316 if (!gtk_text_iter_toggles_tag (iter, tag))
5317 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5319 check_invariants (iter);
5325 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5329 g_return_val_if_fail (iter != NULL, FALSE);
5330 g_return_val_if_fail (tree != NULL, FALSE);
5332 _gtk_text_btree_get_end_iter (tree, iter);
5333 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5334 check_invariants (iter);
5340 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5342 const gchar *mark_name)
5346 g_return_val_if_fail (iter != NULL, FALSE);
5347 g_return_val_if_fail (tree != NULL, FALSE);
5349 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5355 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5356 check_invariants (iter);
5362 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5366 GtkTextLineSegment *seg;
5368 g_return_if_fail (iter != NULL);
5369 g_return_if_fail (tree != NULL);
5370 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5372 seg = mark->segment;
5374 iter_init_from_segment (iter, tree,
5375 seg->body.mark.line, seg);
5376 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5377 check_invariants (iter);
5381 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5383 GtkTextChildAnchor *anchor)
5385 GtkTextLineSegment *seg;
5387 g_return_if_fail (iter != NULL);
5388 g_return_if_fail (tree != NULL);
5389 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5391 seg = anchor->segment;
5393 g_assert (seg->body.child.line != NULL);
5395 iter_init_from_segment (iter, tree,
5396 seg->body.child.line, seg);
5397 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5398 check_invariants (iter);
5402 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5405 g_return_if_fail (iter != NULL);
5406 g_return_if_fail (tree != NULL);
5408 _gtk_text_btree_get_iter_at_char (tree,
5410 _gtk_text_btree_char_count (tree));
5411 check_invariants (iter);
5415 _gtk_text_iter_check (const GtkTextIter *iter)
5417 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5418 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5419 GtkTextLineSegment *byte_segment = NULL;
5420 GtkTextLineSegment *byte_any_segment = NULL;
5421 GtkTextLineSegment *char_segment = NULL;
5422 GtkTextLineSegment *char_any_segment = NULL;
5423 gboolean segments_updated;
5425 /* This function checks our class invariants for the Iter class. */
5427 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5429 if (real->chars_changed_stamp !=
5430 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5431 g_error ("iterator check failed: invalid iterator");
5433 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5434 g_error ("iterator check failed: both char and byte offsets are invalid");
5436 segments_updated = (real->segments_changed_stamp ==
5437 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5440 printf ("checking iter, segments %s updated, byte %d char %d\n",
5441 segments_updated ? "are" : "aren't",
5442 real->line_byte_offset,
5443 real->line_char_offset);
5446 if (segments_updated)
5448 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5449 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5451 if (real->segment->char_count == 0)
5452 g_error ("iterator check failed: segment is not indexable.");
5454 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5455 g_error ("segment char offset is not properly up-to-date");
5457 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5458 g_error ("segment byte offset is not properly up-to-date");
5460 if (real->segment_byte_offset >= 0 &&
5461 real->segment_byte_offset >= real->segment->byte_count)
5462 g_error ("segment byte offset is too large.");
5464 if (real->segment_char_offset >= 0 &&
5465 real->segment_char_offset >= real->segment->char_count)
5466 g_error ("segment char offset is too large.");
5469 if (real->line_byte_offset >= 0)
5471 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5472 &byte_segment, &byte_any_segment,
5473 &seg_byte_offset, &line_byte_offset);
5475 if (line_byte_offset != real->line_byte_offset)
5476 g_error ("wrong byte offset was stored in iterator");
5478 if (segments_updated)
5480 if (real->segment != byte_segment)
5481 g_error ("wrong segment was stored in iterator");
5483 if (real->any_segment != byte_any_segment)
5484 g_error ("wrong any_segment was stored in iterator");
5486 if (seg_byte_offset != real->segment_byte_offset)
5487 g_error ("wrong segment byte offset was stored in iterator");
5489 if (byte_segment->type == >k_text_char_type)
5492 p = byte_segment->body.chars + seg_byte_offset;
5494 if (!gtk_text_byte_begins_utf8_char (p))
5495 g_error ("broken iterator byte index pointed into the middle of a character");
5500 if (real->line_char_offset >= 0)
5502 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5503 &char_segment, &char_any_segment,
5504 &seg_char_offset, &line_char_offset);
5506 if (line_char_offset != real->line_char_offset)
5507 g_error ("wrong char offset was stored in iterator");
5509 if (segments_updated)
5511 if (real->segment != char_segment)
5512 g_error ("wrong segment was stored in iterator");
5514 if (real->any_segment != char_any_segment)
5515 g_error ("wrong any_segment was stored in iterator");
5517 if (seg_char_offset != real->segment_char_offset)
5518 g_error ("wrong segment char offset was stored in iterator");
5520 if (char_segment->type == >k_text_char_type)
5523 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5526 /* hmm, not likely to happen eh */
5527 if (!gtk_text_byte_begins_utf8_char (p))
5528 g_error ("broken iterator char offset pointed into the middle of a character");
5533 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5535 if (byte_segment != char_segment)
5536 g_error ("char and byte offsets did not point to the same segment");
5538 if (byte_any_segment != char_any_segment)
5539 g_error ("char and byte offsets did not point to the same any segment");
5541 /* Make sure the segment offsets are equivalent, if it's a char
5543 if (char_segment->type == >k_text_char_type)
5545 gint byte_offset = 0;
5546 gint char_offset = 0;
5547 while (char_offset < seg_char_offset)
5549 const char * start = char_segment->body.chars + byte_offset;
5550 byte_offset += g_utf8_next_char (start) - start;
5554 if (byte_offset != seg_byte_offset)
5555 g_error ("byte offset did not correspond to char offset");
5558 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5560 if (char_offset != seg_char_offset)
5561 g_error ("char offset did not correspond to byte offset");
5563 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5564 g_error ("byte index for iterator does not index the start of a character");
5568 if (real->cached_line_number >= 0)
5572 should_be = _gtk_text_line_get_number (real->line);
5573 if (real->cached_line_number != should_be)
5574 g_error ("wrong line number was cached");
5577 if (real->cached_char_index >= 0)
5579 if (real->line_char_offset >= 0) /* only way we can check it
5580 efficiently, not a real
5585 char_index = _gtk_text_line_char_index (real->line);
5586 char_index += real->line_char_offset;
5588 if (real->cached_char_index != char_index)
5589 g_error ("wrong char index was cached");
5593 if (_gtk_text_line_is_last (real->line, real->tree))
5594 g_error ("Iterator was on last line (past the end iterator)");
5597 #define __GTK_TEXT_ITER_C__
5598 #include "gtkaliasdef.c"