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)
1550 GtkTextRealIter *real;
1553 g_return_val_if_fail (iter != NULL, FALSE);
1555 real = gtk_text_iter_make_real (iter);
1557 check_invariants (iter);
1559 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1560 * Unicode 3.0; update this if that changes.
1562 #define PARAGRAPH_SEPARATOR 0x2029
1564 wc = gtk_text_iter_get_char (iter);
1566 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1568 else if (wc == '\n')
1570 /* need to determine if a \r precedes the \n, in which case
1571 * we aren't the end of the line
1573 GtkTextIter tmp = *iter;
1574 if (!gtk_text_iter_backward_char (&tmp))
1577 return gtk_text_iter_get_char (&tmp) != '\r';
1584 * gtk_text_iter_is_end:
1585 * @iter: an iterator
1587 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1588 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1589 * the most efficient way to check whether an iterator is the end
1592 * Return value: whether @iter is the end iterator
1595 gtk_text_iter_is_end (const GtkTextIter *iter)
1597 GtkTextRealIter *real;
1599 g_return_val_if_fail (iter != NULL, FALSE);
1601 real = gtk_text_iter_make_surreal (iter);
1606 check_invariants (iter);
1608 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1611 /* Now we need the segments validated */
1612 real = gtk_text_iter_make_real (iter);
1617 return _gtk_text_btree_is_end (real->tree, real->line,
1619 real->segment_byte_offset,
1620 real->segment_char_offset);
1624 * gtk_text_iter_is_start:
1625 * @iter: an iterator
1627 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1628 * if @iter has a character offset of 0.
1630 * Return value: whether @iter is the first in the buffer
1633 gtk_text_iter_is_start (const GtkTextIter *iter)
1635 return gtk_text_iter_get_offset (iter) == 0;
1639 * gtk_text_iter_get_chars_in_line:
1640 * @iter: an iterator
1642 * Returns the number of characters in the line containing @iter,
1643 * including the paragraph delimiters.
1645 * Return value: number of characters in the line
1648 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1650 GtkTextRealIter *real;
1652 GtkTextLineSegment *seg;
1654 g_return_val_if_fail (iter != NULL, 0);
1656 real = gtk_text_iter_make_surreal (iter);
1661 check_invariants (iter);
1663 if (real->line_char_offset >= 0)
1665 /* We can start at the segments we've already found. */
1666 count = real->line_char_offset - real->segment_char_offset;
1667 seg = _gtk_text_iter_get_indexable_segment (iter);
1671 /* count whole line. */
1672 seg = real->line->segments;
1679 count += seg->char_count;
1684 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1685 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1691 * gtk_text_iter_get_bytes_in_line:
1692 * @iter: an iterator
1694 * Returns the number of bytes in the line containing @iter,
1695 * including the paragraph delimiters.
1697 * Return value: number of bytes in the line
1700 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1702 GtkTextRealIter *real;
1704 GtkTextLineSegment *seg;
1706 g_return_val_if_fail (iter != NULL, 0);
1708 real = gtk_text_iter_make_surreal (iter);
1713 check_invariants (iter);
1715 if (real->line_byte_offset >= 0)
1717 /* We can start at the segments we've already found. */
1718 count = real->line_byte_offset - real->segment_byte_offset;
1719 seg = _gtk_text_iter_get_indexable_segment (iter);
1723 /* count whole line. */
1724 seg = real->line->segments;
1730 count += seg->byte_count;
1735 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1736 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1742 * gtk_text_iter_get_attributes:
1743 * @iter: an iterator
1744 * @values: a #GtkTextAttributes to be filled in
1746 * Computes the effect of any tags applied to this spot in the
1747 * text. The @values parameter should be initialized to the default
1748 * settings you wish to use if no tags are in effect. You'd typically
1749 * obtain the defaults from gtk_text_view_get_default_attributes().
1751 * gtk_text_iter_get_attributes () will modify @values, applying the
1752 * effects of any tags present at @iter. If any tags affected @values,
1753 * the function returns %TRUE.
1755 * Return value: %TRUE if @values was modified
1758 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1759 GtkTextAttributes *values)
1764 /* Get the tags at this spot */
1765 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1767 /* No tags, use default style */
1768 if (tags == NULL || tag_count == 0)
1776 /* Sort tags in ascending order of priority */
1777 _gtk_text_tag_array_sort (tags, tag_count);
1779 _gtk_text_attributes_fill_from_tags (values,
1789 * Increments/decrements
1792 /* The return value of this indicates WHETHER WE MOVED.
1793 * The return value of public functions indicates
1794 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1796 * This function will not change the iterator if
1797 * it's already on the last (end iter) line, i.e. it
1798 * won't move to the end of the last line.
1801 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1803 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1805 GtkTextLine *new_line;
1807 new_line = _gtk_text_line_next (real->line);
1808 g_assert (new_line);
1809 g_assert (new_line != real->line);
1810 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1812 real->line = new_line;
1814 real->line_byte_offset = 0;
1815 real->line_char_offset = 0;
1817 real->segment_byte_offset = 0;
1818 real->segment_char_offset = 0;
1820 /* Find first segments in new line */
1821 real->any_segment = real->line->segments;
1822 real->segment = real->any_segment;
1823 while (real->segment->char_count == 0)
1824 real->segment = real->segment->next;
1830 /* There is no way to move forward a line; we were already at
1831 * the line containing the end iterator.
1832 * However we may not be at the end iterator itself.
1840 /* The return value of this indicates WHETHER WE MOVED.
1841 * The return value of public functions indicates
1842 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1844 * This function is currently unused, thus it is #if-0-ed. It is
1845 * left here, since it's non-trivial code that might be useful in
1849 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1851 GtkTextLine *new_line;
1853 new_line = _gtk_text_line_previous (real->line);
1855 g_assert (new_line != real->line);
1857 if (new_line != NULL)
1859 real->line = new_line;
1861 real->line_byte_offset = 0;
1862 real->line_char_offset = 0;
1864 real->segment_byte_offset = 0;
1865 real->segment_char_offset = 0;
1867 /* Find first segments in new line */
1868 real->any_segment = real->line->segments;
1869 real->segment = real->any_segment;
1870 while (real->segment->char_count == 0)
1871 real->segment = real->segment->next;
1877 /* There is no way to move backward; we were already
1878 at the first line. */
1880 /* We leave real->line as-is */
1882 /* Note that we didn't clamp to the start of the first line. */
1889 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1893 forward_char (GtkTextRealIter *real)
1895 GtkTextIter *iter = (GtkTextIter*)real;
1897 check_invariants ((GtkTextIter*)real);
1899 ensure_char_offsets (real);
1901 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1903 /* Need to move to the next segment; if no next segment,
1904 need to move to next line. */
1905 return _gtk_text_iter_forward_indexable_segment (iter);
1909 /* Just moving within a segment. Keep byte count
1910 up-to-date, if it was already up-to-date. */
1912 g_assert (real->segment->type == >k_text_char_type);
1914 if (real->line_byte_offset >= 0)
1917 const char * start =
1918 real->segment->body.chars + real->segment_byte_offset;
1920 bytes = g_utf8_next_char (start) - start;
1922 real->line_byte_offset += bytes;
1923 real->segment_byte_offset += bytes;
1925 g_assert (real->segment_byte_offset < real->segment->byte_count);
1928 real->line_char_offset += 1;
1929 real->segment_char_offset += 1;
1931 adjust_char_index (real, 1);
1933 g_assert (real->segment_char_offset < real->segment->char_count);
1935 /* We moved into the middle of a segment, so the any_segment
1936 must now be the segment we're in the middle of. */
1937 real->any_segment = real->segment;
1939 check_invariants ((GtkTextIter*)real);
1941 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1949 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1951 /* Need to move to the next segment; if no next segment,
1952 need to move to next line. */
1953 GtkTextLineSegment *seg;
1954 GtkTextLineSegment *any_seg;
1955 GtkTextRealIter *real;
1959 g_return_val_if_fail (iter != NULL, FALSE);
1961 real = gtk_text_iter_make_real (iter);
1966 check_invariants (iter);
1968 if (real->line_char_offset >= 0)
1970 chars_skipped = real->segment->char_count - real->segment_char_offset;
1971 g_assert (chars_skipped > 0);
1976 if (real->line_byte_offset >= 0)
1978 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1979 g_assert (bytes_skipped > 0);
1984 /* Get first segment of any kind */
1985 any_seg = real->segment->next;
1986 /* skip non-indexable segments, if any */
1988 while (seg != NULL && seg->char_count == 0)
1993 real->any_segment = any_seg;
1994 real->segment = seg;
1996 if (real->line_byte_offset >= 0)
1998 g_assert (bytes_skipped > 0);
1999 real->segment_byte_offset = 0;
2000 real->line_byte_offset += bytes_skipped;
2003 if (real->line_char_offset >= 0)
2005 g_assert (chars_skipped > 0);
2006 real->segment_char_offset = 0;
2007 real->line_char_offset += chars_skipped;
2008 adjust_char_index (real, chars_skipped);
2011 check_invariants (iter);
2013 return !gtk_text_iter_is_end (iter);
2017 /* End of the line */
2018 if (forward_line_leaving_caches_unmodified (real))
2020 adjust_line_number (real, 1);
2021 if (real->line_char_offset >= 0)
2022 adjust_char_index (real, chars_skipped);
2024 g_assert (real->line_byte_offset == 0);
2025 g_assert (real->line_char_offset == 0);
2026 g_assert (real->segment_byte_offset == 0);
2027 g_assert (real->segment_char_offset == 0);
2028 g_assert (gtk_text_iter_starts_line (iter));
2030 check_invariants (iter);
2032 return !gtk_text_iter_is_end (iter);
2036 /* End of buffer, but iter is still at start of last segment,
2037 * not at the end iterator. We put it on the end iterator.
2040 check_invariants (iter);
2042 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2043 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2045 gtk_text_iter_forward_to_line_end (iter);
2047 g_assert (gtk_text_iter_is_end (iter));
2055 at_last_indexable_segment (GtkTextRealIter *real)
2057 GtkTextLineSegment *seg;
2059 /* Return TRUE if there are no indexable segments after
2063 seg = real->segment->next;
2066 if (seg->char_count > 0)
2073 /* Goes back to the start of the next segment, even if
2074 * we're not at the start of the current segment (always
2075 * ends up on a different segment if it returns TRUE)
2078 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2080 /* Move to the start of the previous segment; if no previous
2081 * segment, to the last segment in the previous line. This is
2082 * inherently a bit inefficient due to the singly-linked list and
2083 * tree nodes, but we can't afford the RAM for doubly-linked.
2085 GtkTextRealIter *real;
2086 GtkTextLineSegment *seg;
2087 GtkTextLineSegment *any_seg;
2088 GtkTextLineSegment *prev_seg;
2089 GtkTextLineSegment *prev_any_seg;
2093 g_return_val_if_fail (iter != NULL, FALSE);
2095 real = gtk_text_iter_make_real (iter);
2100 check_invariants (iter);
2102 /* Find first segments in line */
2103 any_seg = real->line->segments;
2105 while (seg->char_count == 0)
2108 if (seg == real->segment)
2110 /* Could probably do this case faster by hand-coding the
2114 /* We were already at the start of a line;
2115 * go back to the previous line.
2117 if (gtk_text_iter_backward_line (iter))
2119 /* Go forward to last indexable segment in line. */
2120 while (!at_last_indexable_segment (real))
2121 _gtk_text_iter_forward_indexable_segment (iter);
2123 check_invariants (iter);
2128 return FALSE; /* We were at the start of the first line. */
2131 /* We must be in the middle of a line; so find the indexable
2132 * segment just before our current segment.
2134 g_assert (seg != real->segment);
2138 prev_any_seg = any_seg;
2140 any_seg = seg->next;
2142 while (seg->char_count == 0)
2145 while (seg != real->segment);
2147 g_assert (prev_seg != NULL);
2148 g_assert (prev_any_seg != NULL);
2149 g_assert (prev_seg->char_count > 0);
2151 /* We skipped the entire previous segment, plus any
2152 * chars we were into the current segment.
2154 if (real->segment_byte_offset >= 0)
2155 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2159 if (real->segment_char_offset >= 0)
2160 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2164 real->segment = prev_seg;
2165 real->any_segment = prev_any_seg;
2166 real->segment_byte_offset = 0;
2167 real->segment_char_offset = 0;
2169 if (bytes_skipped >= 0)
2171 if (real->line_byte_offset >= 0)
2173 real->line_byte_offset -= bytes_skipped;
2174 g_assert (real->line_byte_offset >= 0);
2178 real->line_byte_offset = -1;
2180 if (chars_skipped >= 0)
2182 if (real->line_char_offset >= 0)
2184 real->line_char_offset -= chars_skipped;
2185 g_assert (real->line_char_offset >= 0);
2188 if (real->cached_char_index >= 0)
2190 real->cached_char_index -= chars_skipped;
2191 g_assert (real->cached_char_index >= 0);
2196 real->line_char_offset = -1;
2197 real->cached_char_index = -1;
2200 /* line number is unchanged. */
2202 check_invariants (iter);
2208 * gtk_text_iter_forward_char:
2209 * @iter: an iterator
2211 * Moves @iter forward by one character offset. Note that images
2212 * embedded in the buffer occupy 1 character slot, so
2213 * gtk_text_iter_forward_char () may actually move onto an image instead
2214 * of a character, if you have images in your buffer. If @iter is the
2215 * end iterator or one character before it, @iter will now point at
2216 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2217 * convenience when writing loops.
2219 * Return value: whether @iter moved and is dereferenceable
2222 gtk_text_iter_forward_char (GtkTextIter *iter)
2224 GtkTextRealIter *real;
2226 g_return_val_if_fail (iter != NULL, FALSE);
2228 real = gtk_text_iter_make_real (iter);
2234 check_invariants (iter);
2235 return forward_char (real);
2240 * gtk_text_iter_backward_char:
2241 * @iter: an iterator
2243 * Moves backward by one character offset. Returns %TRUE if movement
2244 * was possible; if @iter was the first in the buffer (character
2245 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2248 * Return value: whether movement was possible
2251 gtk_text_iter_backward_char (GtkTextIter *iter)
2253 g_return_val_if_fail (iter != NULL, FALSE);
2255 check_invariants (iter);
2257 return gtk_text_iter_backward_chars (iter, 1);
2261 Definitely we should try to linear scan as often as possible for
2262 movement within a single line, because we can't use the BTree to
2263 speed within-line searches up; for movement between lines, we would
2264 like to avoid the linear scan probably.
2266 Instead of using this constant, it might be nice to cache the line
2267 length in the iterator and linear scan if motion is within a single
2270 I guess you'd have to profile the various approaches.
2272 #define MAX_LINEAR_SCAN 150
2276 * gtk_text_iter_forward_chars:
2277 * @iter: an iterator
2278 * @count: number of characters to move, may be negative
2280 * Moves @count characters if possible (if @count would move past the
2281 * start or end of the buffer, moves to the start or end of the
2282 * buffer). The return value indicates whether the new position of
2283 * @iter is different from its original position, and dereferenceable
2284 * (the last iterator in the buffer is not dereferenceable). If @count
2285 * is 0, the function does nothing and returns %FALSE.
2287 * Return value: whether @iter moved and is dereferenceable
2290 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2292 GtkTextRealIter *real;
2294 g_return_val_if_fail (iter != NULL, FALSE);
2296 FIX_OVERFLOWS (count);
2298 real = gtk_text_iter_make_real (iter);
2302 else if (count == 0)
2305 return gtk_text_iter_backward_chars (iter, 0 - count);
2306 else if (count < MAX_LINEAR_SCAN)
2308 check_invariants (iter);
2312 if (!forward_char (real))
2317 return forward_char (real);
2321 gint current_char_index;
2322 gint new_char_index;
2324 check_invariants (iter);
2326 current_char_index = gtk_text_iter_get_offset (iter);
2328 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2329 return FALSE; /* can't move forward */
2331 new_char_index = current_char_index + count;
2332 gtk_text_iter_set_offset (iter, new_char_index);
2334 check_invariants (iter);
2336 /* Return FALSE if we're on the non-dereferenceable end
2339 if (gtk_text_iter_is_end (iter))
2347 * gtk_text_iter_backward_chars:
2348 * @iter: an iterator
2349 * @count: number of characters to move
2351 * Moves @count characters backward, if possible (if @count would move
2352 * past the start or end of the buffer, moves to the start or end of
2353 * the buffer). The return value indicates whether the iterator moved
2354 * onto a dereferenceable position; if the iterator didn't move, or
2355 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2356 * the function does nothing and returns %FALSE.
2358 * Return value: whether @iter moved and is dereferenceable
2362 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2364 GtkTextRealIter *real;
2366 g_return_val_if_fail (iter != NULL, FALSE);
2368 FIX_OVERFLOWS (count);
2370 real = gtk_text_iter_make_real (iter);
2374 else if (count == 0)
2377 return gtk_text_iter_forward_chars (iter, 0 - count);
2379 ensure_char_offsets (real);
2380 check_invariants (iter);
2382 /* <, not <=, because if count == segment_char_offset
2383 * we're going to the front of the segment and the any_segment
2386 if (count < real->segment_char_offset)
2388 /* Optimize the within-segment case */
2389 g_assert (real->segment->char_count > 0);
2390 g_assert (real->segment->type == >k_text_char_type);
2392 real->segment_char_offset -= count;
2393 g_assert (real->segment_char_offset >= 0);
2395 if (real->line_byte_offset >= 0)
2397 gint new_byte_offset;
2400 new_byte_offset = 0;
2402 while (i < real->segment_char_offset)
2404 const char * start = real->segment->body.chars + new_byte_offset;
2405 new_byte_offset += g_utf8_next_char (start) - start;
2410 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2411 real->segment_byte_offset = new_byte_offset;
2414 real->line_char_offset -= count;
2416 adjust_char_index (real, 0 - count);
2418 check_invariants (iter);
2424 /* We need to go back into previous segments. For now,
2425 * just keep this really simple. FIXME
2426 * use backward_indexable_segment.
2428 if (TRUE || count > MAX_LINEAR_SCAN)
2430 gint current_char_index;
2431 gint new_char_index;
2433 current_char_index = gtk_text_iter_get_offset (iter);
2435 if (current_char_index == 0)
2436 return FALSE; /* can't move backward */
2438 new_char_index = current_char_index - count;
2439 if (new_char_index < 0)
2442 gtk_text_iter_set_offset (iter, new_char_index);
2444 check_invariants (iter);
2450 /* FIXME backward_indexable_segment here */
2459 /* These two can't be implemented efficiently (always have to use
2460 * a linear scan, since that's the only way to find all the non-text
2465 * gtk_text_iter_forward_text_chars:
2466 * @iter: a #GtkTextIter
2467 * @count: number of chars to move
2469 * Moves forward by @count text characters (pixbufs, widgets,
2470 * etc. do not count as characters for this). Equivalent to moving
2471 * through the results of gtk_text_iter_get_text (), rather than
2472 * gtk_text_iter_get_slice ().
2474 * Return value: whether @iter moved and is dereferenceable
2477 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2486 * gtk_text_iter_forward_text_chars:
2487 * @iter: a #GtkTextIter
2488 * @count: number of chars to move
2490 * Moves backward by @count text characters (pixbufs, widgets,
2491 * etc. do not count as characters for this). Equivalent to moving
2492 * through the results of gtk_text_iter_get_text (), rather than
2493 * gtk_text_iter_get_slice ().
2495 * Return value: whether @iter moved and is dereferenceable
2498 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2507 * gtk_text_iter_forward_line:
2508 * @iter: an iterator
2510 * Moves @iter to the start of the next line. Returns %TRUE if there
2511 * was a next line to move to, and %FALSE if @iter was simply moved to
2512 * the end of the buffer and is now not dereferenceable, or if @iter was
2513 * already at the end of the buffer.
2515 * Return value: whether @iter can be dereferenced
2518 gtk_text_iter_forward_line (GtkTextIter *iter)
2520 GtkTextRealIter *real;
2522 g_return_val_if_fail (iter != NULL, FALSE);
2524 real = gtk_text_iter_make_real (iter);
2529 check_invariants (iter);
2531 if (forward_line_leaving_caches_unmodified (real))
2533 invalidate_char_index (real);
2534 adjust_line_number (real, 1);
2536 check_invariants (iter);
2538 if (gtk_text_iter_is_end (iter))
2545 /* On the last line, move to end of it */
2547 if (!gtk_text_iter_is_end (iter))
2548 gtk_text_iter_forward_to_end (iter);
2550 check_invariants (iter);
2556 * gtk_text_iter_backward_line:
2557 * @iter: an iterator
2559 * Moves @iter to the start of the previous line. Returns %TRUE if
2560 * @iter could be moved; i.e. if @iter was at character offset 0, this
2561 * function returns %FALSE. Therefore if @iter was already on line 0,
2562 * but not at the start of the line, @iter is snapped to the start of
2563 * the line and the function returns %TRUE. (Note that this implies that
2564 * in a loop calling this function, the line number may not change on
2565 * every iteration, if your first iteration is on line 0.)
2567 * Return value: whether @iter moved
2570 gtk_text_iter_backward_line (GtkTextIter *iter)
2572 GtkTextLine *new_line;
2573 GtkTextRealIter *real;
2574 gboolean offset_will_change;
2577 g_return_val_if_fail (iter != NULL, FALSE);
2579 real = gtk_text_iter_make_real (iter);
2584 check_invariants (iter);
2586 new_line = _gtk_text_line_previous (real->line);
2588 offset_will_change = FALSE;
2589 if (real->line_char_offset > 0)
2590 offset_will_change = TRUE;
2592 if (new_line != NULL)
2594 real->line = new_line;
2596 adjust_line_number (real, -1);
2600 if (!offset_will_change)
2604 invalidate_char_index (real);
2606 real->line_byte_offset = 0;
2607 real->line_char_offset = 0;
2609 real->segment_byte_offset = 0;
2610 real->segment_char_offset = 0;
2612 /* Find first segment in line */
2613 real->any_segment = real->line->segments;
2614 real->segment = _gtk_text_line_byte_to_segment (real->line,
2617 g_assert (offset == 0);
2619 /* Note that if we are on the first line, we snap to the start of
2620 * the first line and return TRUE, so TRUE means the iterator
2621 * changed, not that the line changed; this is maybe a bit
2622 * weird. I'm not sure there's an obvious right thing to do though.
2625 check_invariants (iter);
2632 * gtk_text_iter_forward_lines:
2633 * @iter: a #GtkTextIter
2634 * @count: number of lines to move forward
2636 * Moves @count lines forward, if possible (if @count would move
2637 * past the start or end of the buffer, moves to the start or end of
2638 * the buffer). The return value indicates whether the iterator moved
2639 * onto a dereferenceable position; if the iterator didn't move, or
2640 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2641 * the function does nothing and returns %FALSE. If @count is negative,
2642 * moves backward by 0 - @count lines.
2644 * Return value: whether @iter moved and is dereferenceable
2647 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2649 FIX_OVERFLOWS (count);
2652 return gtk_text_iter_backward_lines (iter, 0 - count);
2653 else if (count == 0)
2655 else if (count == 1)
2657 check_invariants (iter);
2658 return gtk_text_iter_forward_line (iter);
2664 if (gtk_text_iter_is_end (iter))
2667 old_line = gtk_text_iter_get_line (iter);
2669 gtk_text_iter_set_line (iter, old_line + count);
2671 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2673 /* count went past the last line, so move to end of last line */
2674 if (!gtk_text_iter_is_end (iter))
2675 gtk_text_iter_forward_to_end (iter);
2678 return !gtk_text_iter_is_end (iter);
2683 * gtk_text_iter_backward_lines:
2684 * @iter: a #GtkTextIter
2685 * @count: number of lines to move backward
2687 * Moves @count lines backward, if possible (if @count would move
2688 * past the start or end of the buffer, moves to the start or end of
2689 * the buffer). The return value indicates whether the iterator moved
2690 * onto a dereferenceable position; if the iterator didn't move, or
2691 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2692 * the function does nothing and returns %FALSE. If @count is negative,
2693 * moves forward by 0 - @count lines.
2695 * Return value: whether @iter moved and is dereferenceable
2698 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2700 FIX_OVERFLOWS (count);
2703 return gtk_text_iter_forward_lines (iter, 0 - count);
2704 else if (count == 0)
2706 else if (count == 1)
2708 return gtk_text_iter_backward_line (iter);
2714 old_line = gtk_text_iter_get_line (iter);
2716 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2718 return (gtk_text_iter_get_line (iter) != old_line);
2723 * gtk_text_iter_forward_visible_line:
2724 * @iter: an iterator
2726 * Moves @iter to the start of the next visible line. Returns %TRUE if there
2727 * was a next line to move to, and %FALSE if @iter was simply moved to
2728 * the end of the buffer and is now not dereferenceable, or if @iter was
2729 * already at the end of the buffer.
2731 * Return value: whether @iter can be dereferenced
2736 gtk_text_iter_forward_visible_line (GtkTextIter *iter)
2738 while (gtk_text_iter_forward_line (iter))
2740 if (!_gtk_text_btree_char_is_invisible (iter))
2746 if (!gtk_text_iter_forward_char (iter))
2749 if (!_gtk_text_btree_char_is_invisible (iter))
2752 while (!gtk_text_iter_ends_line (iter));
2760 * gtk_text_iter_backward_visible_line:
2761 * @iter: an iterator
2763 * Moves @iter to the start of the previous visible line. Returns %TRUE if
2764 * @iter could be moved; i.e. if @iter was at character offset 0, this
2765 * function returns %FALSE. Therefore if @iter was already on line 0,
2766 * but not at the start of the line, @iter is snapped to the start of
2767 * the line and the function returns %TRUE. (Note that this implies that
2768 * in a loop calling this function, the line number may not change on
2769 * every iteration, if your first iteration is on line 0.)
2771 * Return value: whether @iter moved
2776 gtk_text_iter_backward_visible_line (GtkTextIter *iter)
2778 while (gtk_text_iter_backward_line (iter))
2780 if (!_gtk_text_btree_char_is_invisible (iter))
2786 if (!gtk_text_iter_backward_char (iter))
2789 if (!_gtk_text_btree_char_is_invisible (iter))
2792 while (!gtk_text_iter_starts_line (iter));
2800 * gtk_text_iter_forward_visible_lines:
2801 * @iter: a #GtkTextIter
2802 * @count: number of lines to move forward
2804 * Moves @count visible lines forward, if possible (if @count would move
2805 * past the start or end of the buffer, moves to the start or end of
2806 * the buffer). The return value indicates whether the iterator moved
2807 * onto a dereferenceable position; if the iterator didn't move, or
2808 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2809 * the function does nothing and returns %FALSE. If @count is negative,
2810 * moves backward by 0 - @count lines.
2812 * Return value: whether @iter moved and is dereferenceable
2817 gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
2820 FIX_OVERFLOWS (count);
2823 return gtk_text_iter_backward_visible_lines (iter, 0 - count);
2824 else if (count == 0)
2826 else if (count == 1)
2828 check_invariants (iter);
2829 return gtk_text_iter_forward_visible_line (iter);
2833 while (gtk_text_iter_forward_visible_line (iter) && count > 0)
2840 * gtk_text_iter_backward_visible_lines:
2841 * @iter: a #GtkTextIter
2842 * @count: number of lines to move backward
2844 * Moves @count visible lines backward, if possible (if @count would move
2845 * past the start or end of the buffer, moves to the start or end of
2846 * the buffer). The return value indicates whether the iterator moved
2847 * onto a dereferenceable position; if the iterator didn't move, or
2848 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2849 * the function does nothing and returns %FALSE. If @count is negative,
2850 * moves forward by 0 - @count lines.
2852 * Return value: whether @iter moved and is dereferenceable
2857 gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
2860 FIX_OVERFLOWS (count);
2863 return gtk_text_iter_forward_visible_lines (iter, 0 - count);
2864 else if (count == 0)
2866 else if (count == 1)
2868 return gtk_text_iter_backward_visible_line (iter);
2872 while (gtk_text_iter_backward_visible_line (iter) && count > 0)
2878 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2883 gboolean already_moved_initially);
2885 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2893 find_word_end_func (const PangoLogAttr *attrs,
2898 gboolean already_moved_initially)
2900 if (!already_moved_initially)
2903 /* Find end of next word */
2904 while (offset < min_offset + len &&
2905 !attrs[offset].is_word_end)
2908 *found_offset = offset;
2910 return offset < min_offset + len;
2914 is_word_end_func (const PangoLogAttr *attrs,
2919 return attrs[offset].is_word_end;
2923 find_word_start_func (const PangoLogAttr *attrs,
2928 gboolean already_moved_initially)
2930 if (!already_moved_initially)
2933 /* Find start of prev word */
2934 while (offset >= min_offset &&
2935 !attrs[offset].is_word_start)
2938 *found_offset = offset;
2940 return offset >= min_offset;
2944 is_word_start_func (const PangoLogAttr *attrs,
2949 return attrs[offset].is_word_start;
2953 inside_word_func (const PangoLogAttr *attrs,
2958 /* Find next word start or end */
2959 while (offset >= min_offset &&
2960 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2964 return attrs[offset].is_word_start;
2969 /* Sentence funcs */
2972 find_sentence_end_func (const PangoLogAttr *attrs,
2977 gboolean already_moved_initially)
2979 if (!already_moved_initially)
2982 /* Find end of next sentence */
2983 while (offset < min_offset + len &&
2984 !attrs[offset].is_sentence_end)
2987 *found_offset = offset;
2989 return offset < min_offset + len;
2993 is_sentence_end_func (const PangoLogAttr *attrs,
2998 return attrs[offset].is_sentence_end;
3002 find_sentence_start_func (const PangoLogAttr *attrs,
3007 gboolean already_moved_initially)
3009 if (!already_moved_initially)
3012 /* Find start of prev sentence */
3013 while (offset >= min_offset &&
3014 !attrs[offset].is_sentence_start)
3017 *found_offset = offset;
3019 return offset >= min_offset;
3023 is_sentence_start_func (const PangoLogAttr *attrs,
3028 return attrs[offset].is_sentence_start;
3032 inside_sentence_func (const PangoLogAttr *attrs,
3037 /* Find next sentence start or end */
3038 while (offset >= min_offset &&
3039 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
3042 return attrs[offset].is_sentence_start;
3046 test_log_attrs (const GtkTextIter *iter,
3047 TestLogAttrFunc func)
3050 const PangoLogAttr *attrs;
3052 gboolean result = FALSE;
3054 g_return_val_if_fail (iter != NULL, FALSE);
3056 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3059 offset = gtk_text_iter_get_line_offset (iter);
3061 /* char_len may be 0 and attrs will be NULL if so, if
3062 * iter is the end iter and the last line is empty.
3064 * offset may be equal to char_len, since attrs contains an entry
3065 * for one past the end
3068 if (attrs && offset <= char_len)
3069 result = (* func) (attrs, offset, 0, char_len);
3075 find_line_log_attrs (const GtkTextIter *iter,
3076 FindLogAttrFunc func,
3078 gboolean already_moved_initially)
3081 const PangoLogAttr *attrs;
3083 gboolean result = FALSE;
3085 g_return_val_if_fail (iter != NULL, FALSE);
3087 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3090 offset = gtk_text_iter_get_line_offset (iter);
3092 /* char_len may be 0 and attrs will be NULL if so, if
3093 * iter is the end iter and the last line is empty
3097 result = (* func) (attrs, offset, 0, char_len, found_offset,
3098 already_moved_initially);
3103 /* FIXME this function is very, very gratuitously slow */
3105 find_by_log_attrs (GtkTextIter *iter,
3106 FindLogAttrFunc func,
3108 gboolean already_moved_initially)
3112 gboolean found = FALSE;
3114 g_return_val_if_fail (iter != NULL, FALSE);
3118 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
3124 if (gtk_text_iter_forward_line (iter))
3125 return find_by_log_attrs (iter, func, forward,
3132 /* go to end of previous line. need to check that
3133 * line is > 0 because backward_line snaps to start of
3134 * line 0 if it's on line 0
3136 if (gtk_text_iter_get_line (iter) > 0 &&
3137 gtk_text_iter_backward_line (iter))
3139 if (!gtk_text_iter_ends_line (iter))
3140 gtk_text_iter_forward_to_line_end (iter);
3142 return find_by_log_attrs (iter, func, forward,
3151 gtk_text_iter_set_line_offset (iter, offset);
3154 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
3155 !gtk_text_iter_is_end (iter);
3160 find_visible_by_log_attrs (GtkTextIter *iter,
3161 FindLogAttrFunc func,
3163 gboolean already_moved_initially)
3167 g_return_val_if_fail (iter != NULL, FALSE);
3171 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3173 if (!_gtk_text_btree_char_is_invisible (&pos))
3183 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3184 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3187 move_multiple_steps (GtkTextIter *iter,
3189 OneStepFunc step_forward,
3190 MultipleStepFunc n_steps_backward)
3192 g_return_val_if_fail (iter != NULL, FALSE);
3194 FIX_OVERFLOWS (count);
3200 return n_steps_backward (iter, -count);
3202 if (!step_forward (iter))
3208 if (!step_forward (iter))
3213 return !gtk_text_iter_is_end (iter);
3218 * gtk_text_iter_forward_word_end:
3219 * @iter: a #GtkTextIter
3221 * Moves forward to the next word end. (If @iter is currently on a
3222 * word end, moves forward to the next one after that.) Word breaks
3223 * are determined by Pango and should be correct for nearly any
3224 * language (if not, the correct fix would be to the Pango word break
3227 * Return value: %TRUE if @iter moved and is not the end iterator
3230 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3232 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3236 * gtk_text_iter_backward_word_start:
3237 * @iter: a #GtkTextIter
3239 * Moves backward to the previous word start. (If @iter is currently on a
3240 * word start, moves backward to the next one after that.) Word breaks
3241 * are determined by Pango and should be correct for nearly any
3242 * language (if not, the correct fix would be to the Pango word break
3245 * Return value: %TRUE if @iter moved and is not the end iterator
3248 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3250 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3253 /* FIXME a loop around a truly slow function means
3254 * a truly spectacularly slow function.
3258 * gtk_text_iter_forward_word_ends:
3259 * @iter: a #GtkTextIter
3260 * @count: number of times to move
3262 * Calls gtk_text_iter_forward_word_end() up to @count times.
3264 * Return value: %TRUE if @iter moved and is not the end iterator
3267 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3270 return move_multiple_steps (iter, count,
3271 gtk_text_iter_forward_word_end,
3272 gtk_text_iter_backward_word_starts);
3276 * gtk_text_iter_backward_word_starts
3277 * @iter: a #GtkTextIter
3278 * @count: number of times to move
3280 * Calls gtk_text_iter_backward_word_start() up to @count times.
3282 * Return value: %TRUE if @iter moved and is not the end iterator
3285 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3288 return move_multiple_steps (iter, count,
3289 gtk_text_iter_backward_word_start,
3290 gtk_text_iter_forward_word_ends);
3294 * gtk_text_iter_forward_visible_word_end:
3295 * @iter: a #GtkTextIter
3297 * Moves forward to the next visible word end. (If @iter is currently on a
3298 * word end, moves forward to the next one after that.) Word breaks
3299 * are determined by Pango and should be correct for nearly any
3300 * language (if not, the correct fix would be to the Pango word break
3303 * Return value: %TRUE if @iter moved and is not the end iterator
3308 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3310 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3314 * gtk_text_iter_backward_visible_word_start:
3315 * @iter: a #GtkTextIter
3317 * Moves backward to the previous visible word start. (If @iter is currently
3318 * on a word start, moves backward to the next one after that.) Word breaks
3319 * are determined by Pango and should be correct for nearly any
3320 * language (if not, the correct fix would be to the Pango word break
3323 * Return value: %TRUE if @iter moved and is not the end iterator
3328 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3330 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3334 * gtk_text_iter_forward_visible_word_ends:
3335 * @iter: a #GtkTextIter
3336 * @count: number of times to move
3338 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3340 * Return value: %TRUE if @iter moved and is not the end iterator
3345 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3348 return move_multiple_steps (iter, count,
3349 gtk_text_iter_forward_visible_word_end,
3350 gtk_text_iter_backward_visible_word_starts);
3354 * gtk_text_iter_backward_visible_word_starts
3355 * @iter: a #GtkTextIter
3356 * @count: number of times to move
3358 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3360 * Return value: %TRUE if @iter moved and is not the end iterator
3365 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3368 return move_multiple_steps (iter, count,
3369 gtk_text_iter_backward_visible_word_start,
3370 gtk_text_iter_forward_visible_word_ends);
3374 * gtk_text_iter_starts_word:
3375 * @iter: a #GtkTextIter
3377 * Determines whether @iter begins a natural-language word. Word
3378 * breaks are determined by Pango and should be correct for nearly any
3379 * language (if not, the correct fix would be to the Pango word break
3382 * Return value: %TRUE if @iter is at the start of a word
3385 gtk_text_iter_starts_word (const GtkTextIter *iter)
3387 return test_log_attrs (iter, is_word_start_func);
3391 * gtk_text_iter_ends_word:
3392 * @iter: a #GtkTextIter
3394 * Determines whether @iter ends a natural-language word. Word breaks
3395 * are determined by Pango and should be correct for nearly any
3396 * language (if not, the correct fix would be to the Pango word break
3399 * Return value: %TRUE if @iter is at the end of a word
3402 gtk_text_iter_ends_word (const GtkTextIter *iter)
3404 return test_log_attrs (iter, is_word_end_func);
3408 * gtk_text_iter_inside_word:
3409 * @iter: a #GtkTextIter
3411 * Determines whether @iter is inside a natural-language word (as
3412 * opposed to say inside some whitespace). Word breaks are determined
3413 * by Pango and should be correct for nearly any language (if not, the
3414 * correct fix would be to the Pango word break algorithms).
3416 * Return value: %TRUE if @iter is inside a word
3419 gtk_text_iter_inside_word (const GtkTextIter *iter)
3421 return test_log_attrs (iter, inside_word_func);
3425 * gtk_text_iter_starts_sentence:
3426 * @iter: a #GtkTextIter
3428 * Determines whether @iter begins a sentence. Sentence boundaries are
3429 * determined by Pango and should be correct for nearly any language
3430 * (if not, the correct fix would be to the Pango text boundary
3433 * Return value: %TRUE if @iter is at the start of a sentence.
3436 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3438 return test_log_attrs (iter, is_sentence_start_func);
3442 * gtk_text_iter_ends_sentence:
3443 * @iter: a #GtkTextIter
3445 * Determines whether @iter ends a sentence. Sentence boundaries are
3446 * determined by Pango and should be correct for nearly any language
3447 * (if not, the correct fix would be to the Pango text boundary
3450 * Return value: %TRUE if @iter is at the end of a sentence.
3453 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3455 return test_log_attrs (iter, is_sentence_end_func);
3459 * gtk_text_iter_inside_sentence:
3460 * @iter: a #GtkTextIter
3462 * Determines whether @iter is inside a sentence (as opposed to in
3463 * between two sentences, e.g. after a period and before the first
3464 * letter of the next sentence). Sentence boundaries are determined
3465 * by Pango and should be correct for nearly any language (if not, the
3466 * correct fix would be to the Pango text boundary algorithms).
3468 * Return value: %TRUE if @iter is inside a sentence.
3471 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3473 return test_log_attrs (iter, inside_sentence_func);
3477 * gtk_text_iter_forward_sentence_end:
3478 * @iter: a #GtkTextIter
3480 * Moves forward to the next sentence end. (If @iter is at the end of
3481 * a sentence, moves to the next end of sentence.) Sentence
3482 * boundaries are determined by Pango and should be correct for nearly
3483 * any language (if not, the correct fix would be to the Pango text
3484 * boundary algorithms).
3486 * Return value: %TRUE if @iter moved and is not the end iterator
3489 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3491 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3495 * gtk_text_iter_backward_sentence_start:
3496 * @iter: a #GtkTextIter
3498 * Moves backward to the previous sentence start; if @iter is already at
3499 * the start of a sentence, moves backward to the next one. Sentence
3500 * boundaries are determined by Pango and should be correct for nearly
3501 * any language (if not, the correct fix would be to the Pango text
3502 * boundary algorithms).
3504 * Return value: %TRUE if @iter moved and is not the end iterator
3507 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3509 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3512 /* FIXME a loop around a truly slow function means
3513 * a truly spectacularly slow function.
3516 * gtk_text_iter_forward_sentence_ends:
3517 * @iter: a #GtkTextIter
3518 * @count: number of sentences to move
3520 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3521 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3522 * negative, moves backward instead of forward.
3524 * Return value: %TRUE if @iter moved and is not the end iterator
3527 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3530 return move_multiple_steps (iter, count,
3531 gtk_text_iter_forward_sentence_end,
3532 gtk_text_iter_backward_sentence_starts);
3536 * gtk_text_iter_backward_sentence_starts:
3537 * @iter: a #GtkTextIter
3538 * @count: number of sentences to move
3540 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3541 * or until it returns %FALSE. If @count is negative, moves forward
3542 * instead of backward.
3544 * Return value: %TRUE if @iter moved and is not the end iterator
3547 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3550 return move_multiple_steps (iter, count,
3551 gtk_text_iter_backward_sentence_start,
3552 gtk_text_iter_forward_sentence_ends);
3556 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3561 gboolean already_moved_initially)
3563 if (!already_moved_initially)
3566 while (offset < (min_offset + len) &&
3567 !attrs[offset].is_cursor_position)
3570 *found_offset = offset;
3572 return offset < (min_offset + len);
3576 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3581 gboolean already_moved_initially)
3583 if (!already_moved_initially)
3586 while (offset > min_offset &&
3587 !attrs[offset].is_cursor_position)
3590 *found_offset = offset;
3592 return offset >= min_offset;
3596 is_cursor_pos_func (const PangoLogAttr *attrs,
3601 return attrs[offset].is_cursor_position;
3605 * gtk_text_iter_forward_cursor_position:
3606 * @iter: a #GtkTextIter
3608 * Moves @iter forward by a single cursor position. Cursor positions
3609 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3610 * surprisingly, there may not be a cursor position between all
3611 * characters. The most common example for European languages would be
3612 * a carriage return/newline sequence. For some Unicode characters,
3613 * the equivalent of say the letter "a" with an accent mark will be
3614 * represented as two characters, first the letter then a "combining
3615 * mark" that causes the accent to be rendered; so the cursor can't go
3616 * between those two characters. See also the #PangoLogAttr structure and
3617 * pango_break() function.
3619 * Return value: %TRUE if we moved and the new position is dereferenceable
3622 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3624 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3628 * gtk_text_iter_backward_cursor_position:
3629 * @iter: a #GtkTextIter
3631 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3633 * Return value: %TRUE if we moved
3636 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3638 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3642 * gtk_text_iter_forward_cursor_positions:
3643 * @iter: a #GtkTextIter
3644 * @count: number of positions to move
3646 * Moves up to @count cursor positions. See
3647 * gtk_text_iter_forward_cursor_position() for details.
3649 * Return value: %TRUE if we moved and the new position is dereferenceable
3652 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3655 return move_multiple_steps (iter, count,
3656 gtk_text_iter_forward_cursor_position,
3657 gtk_text_iter_backward_cursor_positions);
3661 * gtk_text_iter_backward_cursor_positions:
3662 * @iter: a #GtkTextIter
3663 * @count: number of positions to move
3665 * Moves up to @count cursor positions. See
3666 * gtk_text_iter_forward_cursor_position() for details.
3668 * Return value: %TRUE if we moved and the new position is dereferenceable
3671 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3674 return move_multiple_steps (iter, count,
3675 gtk_text_iter_backward_cursor_position,
3676 gtk_text_iter_forward_cursor_positions);
3680 * gtk_text_iter_forward_visible_cursor_position:
3681 * @iter: a #GtkTextIter
3683 * Moves @iter forward to the next visible cursor position. See
3684 * gtk_text_iter_forward_cursor_position() for details.
3686 * Return value: %TRUE if we moved and the new position is dereferenceable
3691 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3693 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3697 * gtk_text_iter_backward_visible_cursor_position:
3698 * @iter: a #GtkTextIter
3700 * Moves @iter forward to the previous visible cursor position. See
3701 * gtk_text_iter_backward_cursor_position() for details.
3703 * Return value: %TRUE if we moved and the new position is dereferenceable
3708 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3710 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3714 * gtk_text_iter_forward_visible_cursor_positions:
3715 * @iter: a #GtkTextIter
3716 * @count: number of positions to move
3718 * Moves up to @count visible cursor positions. See
3719 * gtk_text_iter_forward_cursor_position() for details.
3721 * Return value: %TRUE if we moved and the new position is dereferenceable
3726 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3729 return move_multiple_steps (iter, count,
3730 gtk_text_iter_forward_visible_cursor_position,
3731 gtk_text_iter_backward_visible_cursor_positions);
3735 * gtk_text_iter_backward_visible_cursor_positions:
3736 * @iter: a #GtkTextIter
3737 * @count: number of positions to move
3739 * Moves up to @count visible cursor positions. See
3740 * gtk_text_iter_forward_cursor_position() for details.
3742 * Return value: %TRUE if we moved and the new position is dereferenceable
3747 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3750 return move_multiple_steps (iter, count,
3751 gtk_text_iter_backward_visible_cursor_position,
3752 gtk_text_iter_forward_visible_cursor_positions);
3756 * gtk_text_iter_is_cursor_position:
3757 * @iter: a #GtkTextIter
3759 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3760 * pango_break() for details on what a cursor position is.
3762 * Return value: %TRUE if the cursor can be placed at @iter
3765 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3767 return test_log_attrs (iter, is_cursor_pos_func);
3771 * gtk_text_iter_set_line_offset:
3772 * @iter: a #GtkTextIter
3773 * @char_on_line: a character offset relative to the start of @iter's current line
3775 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3776 * (not byte) offset. The given character offset must be less than or
3777 * equal to the number of characters in the line; if equal, @iter
3778 * moves to the start of the next line. See
3779 * gtk_text_iter_set_line_index() if you have a byte index rather than
3780 * a character offset.
3784 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3787 GtkTextRealIter *real;
3790 g_return_if_fail (iter != NULL);
3792 real = gtk_text_iter_make_surreal (iter);
3797 check_invariants (iter);
3799 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3801 g_return_if_fail (char_on_line <= chars_in_line);
3803 if (char_on_line < chars_in_line)
3804 iter_set_from_char_offset (real, real->line, char_on_line);
3806 gtk_text_iter_forward_line (iter); /* set to start of next line */
3808 check_invariants (iter);
3812 * gtk_text_iter_set_line_index:
3813 * @iter: a #GtkTextIter
3814 * @byte_on_line: a byte index relative to the start of @iter's current line
3816 * Same as gtk_text_iter_set_line_offset(), but works with a
3817 * <emphasis>byte</emphasis> index. The given byte index must be at
3818 * the start of a character, it can't be in the middle of a UTF-8
3819 * encoded character.
3823 gtk_text_iter_set_line_index (GtkTextIter *iter,
3826 GtkTextRealIter *real;
3829 g_return_if_fail (iter != NULL);
3831 real = gtk_text_iter_make_surreal (iter);
3836 check_invariants (iter);
3838 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3840 g_return_if_fail (byte_on_line <= bytes_in_line);
3842 if (byte_on_line < bytes_in_line)
3843 iter_set_from_byte_offset (real, real->line, byte_on_line);
3845 gtk_text_iter_forward_line (iter);
3847 if (real->segment->type == >k_text_char_type &&
3848 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3849 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3850 "character; this will crash the text buffer. "
3851 "Byte indexes must refer to the start of a character.",
3852 G_STRLOC, byte_on_line);
3854 check_invariants (iter);
3859 * gtk_text_iter_set_visible_line_offset:
3860 * @iter: a #GtkTextIter
3861 * @char_on_line: a character offset
3863 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3864 * characters, i.e. text with a tag making it invisible is not
3865 * counted in the offset.
3868 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3871 gint chars_seen = 0;
3874 g_return_if_fail (iter != NULL);
3876 gtk_text_iter_set_line_offset (iter, 0);
3880 /* For now we use a ludicrously slow implementation */
3881 while (chars_seen < char_on_line)
3883 if (!_gtk_text_btree_char_is_invisible (&pos))
3886 if (!gtk_text_iter_forward_char (&pos))
3889 if (chars_seen == char_on_line)
3893 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3896 gtk_text_iter_forward_line (iter);
3900 bytes_in_char (GtkTextIter *iter)
3902 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3906 * gtk_text_iter_set_visible_line_index:
3907 * @iter: a #GtkTextIter
3908 * @byte_on_line: a byte index
3910 * Like gtk_text_iter_set_line_index(), but the index is in visible
3911 * bytes, i.e. text with a tag making it invisible is not counted
3915 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3918 gint bytes_seen = 0;
3922 g_return_if_fail (iter != NULL);
3924 gtk_text_iter_set_line_offset (iter, 0);
3928 /* For now we use a ludicrously slow implementation */
3929 while (bytes_seen < byte_on_line)
3931 if (!_gtk_text_btree_char_is_invisible (&pos))
3932 bytes_seen += bytes_in_char (&pos);
3935 if (!gtk_text_iter_forward_char (&pos))
3938 if (bytes_seen >= byte_on_line)
3942 if (bytes_seen > byte_on_line)
3943 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3944 "character; this will crash the text buffer. "
3945 "Byte indexes must refer to the start of a character.",
3946 G_STRLOC, byte_on_line);
3948 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3951 gtk_text_iter_forward_line (iter);
3955 * gtk_text_iter_set_line:
3956 * @iter: a #GtkTextIter
3957 * @line_number: line number (counted from 0)
3959 * Moves iterator @iter to the start of the line @line_number. If
3960 * @line_number is negative or larger than the number of lines in the
3961 * buffer, moves @iter to the start of the last line in the buffer.
3965 gtk_text_iter_set_line (GtkTextIter *iter,
3970 GtkTextRealIter *real;
3972 g_return_if_fail (iter != NULL);
3974 real = gtk_text_iter_make_surreal (iter);
3979 check_invariants (iter);
3981 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3983 iter_set_from_char_offset (real, line, 0);
3985 /* We might as well cache this, since we know it. */
3986 real->cached_line_number = real_line;
3988 check_invariants (iter);
3992 * gtk_text_iter_set_offset:
3993 * @iter: a #GtkTextIter
3994 * @char_offset: a character number
3996 * Sets @iter to point to @char_offset. @char_offset counts from the start
3997 * of the entire text buffer, starting with 0.
4000 gtk_text_iter_set_offset (GtkTextIter *iter,
4004 GtkTextRealIter *real;
4006 gint real_char_index;
4008 g_return_if_fail (iter != NULL);
4010 real = gtk_text_iter_make_surreal (iter);
4015 check_invariants (iter);
4017 if (real->cached_char_index >= 0 &&
4018 real->cached_char_index == char_offset)
4021 line = _gtk_text_btree_get_line_at_char (real->tree,
4026 iter_set_from_char_offset (real, line, real_char_index - line_start);
4028 /* Go ahead and cache this since we have it. */
4029 real->cached_char_index = real_char_index;
4031 check_invariants (iter);
4035 * gtk_text_iter_forward_to_end:
4036 * @iter: a #GtkTextIter
4038 * Moves @iter forward to the "end iterator," which points one past the last
4039 * valid character in the buffer. gtk_text_iter_get_char() called on the
4040 * end iterator returns 0, which is convenient for writing loops.
4043 gtk_text_iter_forward_to_end (GtkTextIter *iter)
4045 GtkTextBuffer *buffer;
4046 GtkTextRealIter *real;
4048 g_return_if_fail (iter != NULL);
4050 real = gtk_text_iter_make_surreal (iter);
4055 buffer = _gtk_text_btree_get_buffer (real->tree);
4057 gtk_text_buffer_get_end_iter (buffer, iter);
4060 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
4061 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
4062 * If all else fails we could cache the para delimiter pos in the iter.
4063 * I think forward_to_line_end() actually gets called fairly often.
4066 find_paragraph_delimiter_for_line (GtkTextIter *iter)
4071 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
4072 _gtk_text_iter_get_btree (&end)))
4074 gtk_text_iter_forward_to_end (&end);
4078 /* if we aren't on the last line, go forward to start of next line, then scan
4079 * back for the delimiters on the previous line
4081 gtk_text_iter_forward_line (&end);
4082 gtk_text_iter_backward_char (&end);
4083 while (!gtk_text_iter_ends_line (&end))
4084 gtk_text_iter_backward_char (&end);
4087 return gtk_text_iter_get_line_offset (&end);
4091 * gtk_text_iter_forward_to_line_end:
4092 * @iter: a #GtkTextIter
4094 * Moves the iterator to point to the paragraph delimiter characters,
4095 * which will be either a newline, a carriage return, a carriage
4096 * return/newline in sequence, or the Unicode paragraph separator
4097 * character. If the iterator is already at the paragraph delimiter
4098 * characters, moves to the paragraph delimiter characters for the
4099 * next line. If @iter is on the last line in the buffer, which does
4100 * not end in paragraph delimiters, moves to the end iterator (end of
4101 * the last line), and returns %FALSE.
4103 * Return value: %TRUE if we moved and the new location is not the end iterator
4106 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
4108 gint current_offset;
4112 g_return_val_if_fail (iter != NULL, FALSE);
4114 current_offset = gtk_text_iter_get_line_offset (iter);
4115 new_offset = find_paragraph_delimiter_for_line (iter);
4117 if (current_offset < new_offset)
4119 /* Move to end of this line. */
4120 gtk_text_iter_set_line_offset (iter, new_offset);
4121 return !gtk_text_iter_is_end (iter);
4125 /* Move to end of next line. */
4126 if (gtk_text_iter_forward_line (iter))
4128 /* We don't want to move past all
4131 if (!gtk_text_iter_ends_line (iter))
4132 gtk_text_iter_forward_to_line_end (iter);
4133 return !gtk_text_iter_is_end (iter);
4141 * gtk_text_iter_forward_to_tag_toggle:
4142 * @iter: a #GtkTextIter
4143 * @tag: a #GtkTextTag, or %NULL
4145 * Moves forward to the next toggle (on or off) of the
4146 * #GtkTextTag @tag, or to the next toggle of any tag if
4147 * @tag is %NULL. If no matching tag toggles are found,
4148 * returns %FALSE, otherwise %TRUE. Does not return toggles
4149 * located at @iter, only toggles after @iter. Sets @iter to
4150 * the location of the toggle, or to the end of the buffer
4151 * if no toggle is found.
4153 * Return value: whether we found a tag toggle after @iter
4156 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4159 GtkTextLine *next_line;
4160 GtkTextLine *current_line;
4161 GtkTextRealIter *real;
4163 g_return_val_if_fail (iter != NULL, FALSE);
4165 real = gtk_text_iter_make_real (iter);
4170 check_invariants (iter);
4172 current_line = real->line;
4173 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4176 while (_gtk_text_iter_forward_indexable_segment (iter))
4178 /* If we went forward to a line that couldn't contain a toggle
4179 for the tag, then skip forward to a line that could contain
4180 it. This potentially skips huge hunks of the tree, so we
4181 aren't a purely linear search. */
4182 if (real->line != current_line)
4184 if (next_line == NULL)
4186 /* End of search. Set to end of buffer. */
4187 _gtk_text_btree_get_end_iter (real->tree, iter);
4191 if (real->line != next_line)
4192 iter_set_from_byte_offset (real, next_line, 0);
4194 current_line = real->line;
4195 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4200 if (gtk_text_iter_toggles_tag (iter, tag))
4202 /* If there's a toggle here, it isn't indexable so
4203 any_segment can't be the indexable segment. */
4204 g_assert (real->any_segment != real->segment);
4209 /* Check end iterator for tags */
4210 if (gtk_text_iter_toggles_tag (iter, tag))
4212 /* If there's a toggle here, it isn't indexable so
4213 any_segment can't be the indexable segment. */
4214 g_assert (real->any_segment != real->segment);
4218 /* Reached end of buffer */
4223 * gtk_text_iter_backward_to_tag_toggle:
4224 * @iter: a #GtkTextIter
4225 * @tag: a #GtkTextTag, or %NULL
4227 * Moves backward to the next toggle (on or off) of the
4228 * #GtkTextTag @tag, or to the next toggle of any tag if
4229 * @tag is %NULL. If no matching tag toggles are found,
4230 * returns %FALSE, otherwise %TRUE. Does not return toggles
4231 * located at @iter, only toggles before @iter. Sets @iter
4232 * to the location of the toggle, or the start of the buffer
4233 * if no toggle is found.
4235 * Return value: whether we found a tag toggle before @iter
4238 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4241 GtkTextLine *prev_line;
4242 GtkTextLine *current_line;
4243 GtkTextRealIter *real;
4245 g_return_val_if_fail (iter != NULL, FALSE);
4247 real = gtk_text_iter_make_real (iter);
4252 check_invariants (iter);
4254 current_line = real->line;
4255 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4259 /* If we're at segment start, go to the previous segment;
4260 * if mid-segment, snap to start of current segment.
4262 if (is_segment_start (real))
4264 if (!_gtk_text_iter_backward_indexable_segment (iter))
4269 ensure_char_offsets (real);
4271 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4277 /* If we went backward to a line that couldn't contain a toggle
4278 * for the tag, then skip backward further to a line that
4279 * could contain it. This potentially skips huge hunks of the
4280 * tree, so we aren't a purely linear search.
4282 if (real->line != current_line)
4284 if (prev_line == NULL)
4286 /* End of search. Set to start of buffer. */
4287 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4291 if (real->line != prev_line)
4293 /* Set to last segment in prev_line (could do this
4296 iter_set_from_byte_offset (real, prev_line, 0);
4298 while (!at_last_indexable_segment (real))
4299 _gtk_text_iter_forward_indexable_segment (iter);
4302 current_line = real->line;
4303 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4308 if (gtk_text_iter_toggles_tag (iter, tag))
4310 /* If there's a toggle here, it isn't indexable so
4311 * any_segment can't be the indexable segment.
4313 g_assert (real->any_segment != real->segment);
4317 while (_gtk_text_iter_backward_indexable_segment (iter));
4319 /* Reached front of buffer */
4324 matches_pred (GtkTextIter *iter,
4325 GtkTextCharPredicate pred,
4330 ch = gtk_text_iter_get_char (iter);
4332 return (*pred) (ch, user_data);
4336 * gtk_text_iter_forward_find_char:
4337 * @iter: a #GtkTextIter
4338 * @pred: a function to be called on each character
4339 * @user_data: user data for @pred
4340 * @limit: search limit, or %NULL for none
4342 * Advances @iter, calling @pred on each character. If
4343 * @pred returns %TRUE, returns %TRUE and stops scanning.
4344 * If @pred never returns %TRUE, @iter is set to @limit if
4345 * @limit is non-%NULL, otherwise to the end iterator.
4347 * Return value: whether a match was found
4350 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4351 GtkTextCharPredicate pred,
4353 const GtkTextIter *limit)
4355 g_return_val_if_fail (iter != NULL, FALSE);
4356 g_return_val_if_fail (pred != NULL, FALSE);
4359 gtk_text_iter_compare (iter, limit) >= 0)
4362 while ((limit == NULL ||
4363 !gtk_text_iter_equal (limit, iter)) &&
4364 gtk_text_iter_forward_char (iter))
4366 if (matches_pred (iter, pred, user_data))
4374 * gtk_text_iter_backward_find_char:
4375 * @iter: a #GtkTextIter
4376 * @pred: function to be called on each character
4377 * @user_data: user data for @pred
4378 * @limit: search limit, or %NULL for none
4380 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4382 * Return value: whether a match was found
4385 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4386 GtkTextCharPredicate pred,
4388 const GtkTextIter *limit)
4390 g_return_val_if_fail (iter != NULL, FALSE);
4391 g_return_val_if_fail (pred != NULL, FALSE);
4394 gtk_text_iter_compare (iter, limit) <= 0)
4397 while ((limit == NULL ||
4398 !gtk_text_iter_equal (limit, iter)) &&
4399 gtk_text_iter_backward_char (iter))
4401 if (matches_pred (iter, pred, user_data))
4409 forward_chars_with_skipping (GtkTextIter *iter,
4411 gboolean skip_invisible,
4412 gboolean skip_nontext)
4417 g_return_if_fail (count >= 0);
4423 gboolean ignored = FALSE;
4426 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4431 _gtk_text_btree_char_is_invisible (iter))
4434 gtk_text_iter_forward_char (iter);
4442 lines_match (const GtkTextIter *start,
4443 const gchar **lines,
4444 gboolean visible_only,
4446 GtkTextIter *match_start,
4447 GtkTextIter *match_end)
4454 if (*lines == NULL || **lines == '\0')
4457 *match_start = *start;
4460 *match_end = *start;
4465 gtk_text_iter_forward_line (&next);
4467 /* No more text in buffer, but *lines is nonempty */
4468 if (gtk_text_iter_equal (start, &next))
4476 line_text = gtk_text_iter_get_visible_slice (start, &next);
4478 line_text = gtk_text_iter_get_slice (start, &next);
4483 line_text = gtk_text_iter_get_visible_text (start, &next);
4485 line_text = gtk_text_iter_get_text (start, &next);
4488 if (match_start) /* if this is the first line we're matching */
4489 found = strstr (line_text, *lines);
4492 /* If it's not the first line, we have to match from the
4493 * start of the line.
4495 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4507 /* Get offset to start of search string */
4508 offset = g_utf8_strlen (line_text, found - line_text);
4512 /* If match start needs to be returned, set it to the
4513 * start of the search string.
4517 *match_start = next;
4519 forward_chars_with_skipping (match_start, offset,
4520 visible_only, !slice);
4523 /* Go to end of search string */
4524 offset += g_utf8_strlen (*lines, -1);
4526 forward_chars_with_skipping (&next, offset,
4527 visible_only, !slice);
4536 /* pass NULL for match_start, since we don't need to find the
4539 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4542 /* strsplit () that retains the delimiter as part of the string. */
4544 strbreakup (const char *string,
4545 const char *delimiter,
4548 GSList *string_list = NULL, *slist;
4549 gchar **str_array, *s;
4552 g_return_val_if_fail (string != NULL, NULL);
4553 g_return_val_if_fail (delimiter != NULL, NULL);
4556 max_tokens = G_MAXINT;
4558 s = strstr (string, delimiter);
4561 guint delimiter_len = strlen (delimiter);
4568 len = s - string + delimiter_len;
4569 new_string = g_new (gchar, len + 1);
4570 strncpy (new_string, string, len);
4571 new_string[len] = 0;
4572 string_list = g_slist_prepend (string_list, new_string);
4574 string = s + delimiter_len;
4575 s = strstr (string, delimiter);
4577 while (--max_tokens && s);
4582 string_list = g_slist_prepend (string_list, g_strdup (string));
4585 str_array = g_new (gchar*, n);
4589 str_array[i--] = NULL;
4590 for (slist = string_list; slist; slist = slist->next)
4591 str_array[i--] = slist->data;
4593 g_slist_free (string_list);
4599 * gtk_text_iter_forward_search:
4600 * @iter: start of search
4601 * @str: a search string
4602 * @flags: flags affecting how the search is done
4603 * @match_start: return location for start of match, or %NULL
4604 * @match_end: return location for end of match, or %NULL
4605 * @limit: bound for the search, or %NULL for the end of the buffer
4607 * Searches forward for @str. Any match is returned by setting
4608 * @match_start to the first character of the match and @match_end to the
4609 * first character after the match. The search will not continue past
4610 * @limit. Note that a search is a linear or O(n) operation, so you
4611 * may wish to use @limit to avoid locking up your UI on large
4614 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4615 * have invisible text interspersed in @str. i.e. @str will be a
4616 * possibly-noncontiguous subsequence of the matched range. similarly,
4617 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4618 * pixbufs or child widgets mixed inside the matched range. If these
4619 * flags are not given, the match must be exact; the special 0xFFFC
4620 * character in @str will match embedded pixbufs or child widgets.
4622 * Return value: whether a match was found
4625 gtk_text_iter_forward_search (const GtkTextIter *iter,
4627 GtkTextSearchFlags flags,
4628 GtkTextIter *match_start,
4629 GtkTextIter *match_end,
4630 const GtkTextIter *limit)
4632 gchar **lines = NULL;
4634 gboolean retval = FALSE;
4636 gboolean visible_only;
4639 g_return_val_if_fail (iter != NULL, FALSE);
4640 g_return_val_if_fail (str != NULL, FALSE);
4643 gtk_text_iter_compare (iter, limit) >= 0)
4648 /* If we can move one char, return the empty string there */
4651 if (gtk_text_iter_forward_char (&match))
4654 gtk_text_iter_equal (&match, limit))
4658 *match_start = match;
4667 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4668 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4670 /* locate all lines */
4672 lines = strbreakup (str, "\n", -1);
4678 /* This loop has an inefficient worst-case, where
4679 * gtk_text_iter_get_text () is called repeatedly on
4685 gtk_text_iter_compare (&search, limit) >= 0)
4688 if (lines_match (&search, (const gchar**)lines,
4689 visible_only, slice, &match, &end))
4691 if (limit == NULL ||
4693 gtk_text_iter_compare (&end, limit) < 0))
4698 *match_start = match;
4707 while (gtk_text_iter_forward_line (&search));
4709 g_strfreev ((gchar**)lines);
4715 vectors_equal_ignoring_trailing (gchar **vec1,
4718 /* Ignores trailing chars in vec2's last line */
4727 if (strcmp (*i1, *i2) != 0)
4729 if (*(i2 + 1) == NULL) /* if this is the last line */
4731 gint len1 = strlen (*i1);
4732 gint len2 = strlen (*i2);
4735 strncmp (*i1, *i2, len1) == 0)
4737 /* We matched ignoring the trailing stuff in vec2 */
4762 typedef struct _LinesWindow LinesWindow;
4768 GtkTextIter first_line_start;
4769 GtkTextIter first_line_end;
4771 gboolean visible_only;
4775 lines_window_init (LinesWindow *win,
4776 const GtkTextIter *start)
4779 GtkTextIter line_start;
4780 GtkTextIter line_end;
4782 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4785 if (gtk_text_iter_is_start (start) ||
4786 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4788 /* Already at the end, or not enough lines to match */
4789 win->lines = g_new0 (gchar*, 1);
4794 line_start = *start;
4797 /* Move to start iter to start of line */
4798 gtk_text_iter_set_line_offset (&line_start, 0);
4800 if (gtk_text_iter_equal (&line_start, &line_end))
4802 /* we were already at the start; so go back one line */
4803 gtk_text_iter_backward_line (&line_start);
4806 win->first_line_start = line_start;
4807 win->first_line_end = line_end;
4809 win->lines = g_new0 (gchar*, win->n_lines + 1);
4811 i = win->n_lines - 1;
4818 if (win->visible_only)
4819 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4821 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4825 if (win->visible_only)
4826 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4828 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4831 win->lines[i] = line_text;
4833 line_end = line_start;
4834 gtk_text_iter_backward_line (&line_start);
4841 lines_window_back (LinesWindow *win)
4843 GtkTextIter new_start;
4846 new_start = win->first_line_start;
4848 if (!gtk_text_iter_backward_line (&new_start))
4852 win->first_line_start = new_start;
4853 win->first_line_end = new_start;
4855 gtk_text_iter_forward_line (&win->first_line_end);
4860 if (win->visible_only)
4861 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4862 &win->first_line_end);
4864 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4865 &win->first_line_end);
4869 if (win->visible_only)
4870 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4871 &win->first_line_end);
4873 line_text = gtk_text_iter_get_text (&win->first_line_start,
4874 &win->first_line_end);
4877 /* Move lines to make room for first line. */
4878 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4880 *win->lines = line_text;
4882 /* Free old last line and NULL-terminate */
4883 g_free (win->lines[win->n_lines]);
4884 win->lines[win->n_lines] = NULL;
4890 lines_window_free (LinesWindow *win)
4892 g_strfreev (win->lines);
4896 * gtk_text_iter_backward_search:
4897 * @iter: a #GtkTextIter where the search begins
4898 * @str: search string
4899 * @flags: bitmask of flags affecting the search
4900 * @match_start: return location for start of match, or %NULL
4901 * @match_end: return location for end of match, or %NULL
4902 * @limit: location of last possible @match_start, or %NULL for start of buffer
4904 * Same as gtk_text_iter_forward_search(), but moves backward.
4906 * Return value: whether a match was found
4909 gtk_text_iter_backward_search (const GtkTextIter *iter,
4911 GtkTextSearchFlags flags,
4912 GtkTextIter *match_start,
4913 GtkTextIter *match_end,
4914 const GtkTextIter *limit)
4916 gchar **lines = NULL;
4920 gboolean retval = FALSE;
4921 gboolean visible_only;
4924 g_return_val_if_fail (iter != NULL, FALSE);
4925 g_return_val_if_fail (str != NULL, FALSE);
4928 gtk_text_iter_compare (limit, iter) > 0)
4933 /* If we can move one char, return the empty string there */
4934 GtkTextIter match = *iter;
4936 if (limit && gtk_text_iter_equal (limit, &match))
4939 if (gtk_text_iter_backward_char (&match))
4942 *match_start = match;
4951 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4952 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4954 /* locate all lines */
4956 lines = strbreakup (str, "\n", -1);
4966 win.n_lines = n_lines;
4968 win.visible_only = visible_only;
4970 lines_window_init (&win, iter);
4972 if (*win.lines == NULL)
4977 gchar *first_line_match;
4980 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4982 /* We're now before the search limit, abort. */
4986 /* If there are multiple lines, the first line will
4987 * end in '\n', so this will only match at the
4988 * end of the first line, which is correct.
4990 first_line_match = g_strrstr (*win.lines, *lines);
4992 if (first_line_match &&
4993 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4998 GtkTextIter start_tmp;
5000 /* Offset to start of search string */
5001 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
5003 next = win.first_line_start;
5005 forward_chars_with_skipping (&start_tmp, offset,
5006 visible_only, !slice);
5009 gtk_text_iter_compare (limit, &start_tmp) > 0)
5010 goto out; /* match was bogus */
5013 *match_start = start_tmp;
5015 /* Go to end of search string */
5019 offset += g_utf8_strlen (*l, -1);
5023 forward_chars_with_skipping (&next, offset,
5024 visible_only, !slice);
5033 while (lines_window_back (&win));
5036 lines_window_free (&win);
5047 * gtk_text_iter_equal:
5048 * @lhs: a #GtkTextIter
5049 * @rhs: another #GtkTextIter
5051 * Tests whether two iterators are equal, using the fastest possible
5052 * mechanism. This function is very fast; you can expect it to perform
5053 * better than e.g. getting the character offset for each iterator and
5054 * comparing the offsets yourself. Also, it's a bit faster than
5055 * gtk_text_iter_compare().
5057 * Return value: %TRUE if the iterators point to the same place in the buffer
5060 gtk_text_iter_equal (const GtkTextIter *lhs,
5061 const GtkTextIter *rhs)
5063 GtkTextRealIter *real_lhs;
5064 GtkTextRealIter *real_rhs;
5066 real_lhs = (GtkTextRealIter*)lhs;
5067 real_rhs = (GtkTextRealIter*)rhs;
5069 check_invariants (lhs);
5070 check_invariants (rhs);
5072 if (real_lhs->line != real_rhs->line)
5074 else if (real_lhs->line_byte_offset >= 0 &&
5075 real_rhs->line_byte_offset >= 0)
5076 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5079 /* the ensure_char_offsets () calls do nothing if the char offsets
5080 are already up-to-date. */
5081 ensure_char_offsets (real_lhs);
5082 ensure_char_offsets (real_rhs);
5083 return real_lhs->line_char_offset == real_rhs->line_char_offset;
5088 * gtk_text_iter_compare:
5089 * @lhs: a #GtkTextIter
5090 * @rhs: another #GtkTextIter
5092 * A qsort()-style function that returns negative if @lhs is less than
5093 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5094 * Ordering is in character offset order, i.e. the first character in the buffer
5095 * is less than the second character in the buffer.
5097 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5100 gtk_text_iter_compare (const GtkTextIter *lhs,
5101 const GtkTextIter *rhs)
5103 GtkTextRealIter *real_lhs;
5104 GtkTextRealIter *real_rhs;
5106 real_lhs = gtk_text_iter_make_surreal (lhs);
5107 real_rhs = gtk_text_iter_make_surreal (rhs);
5109 if (real_lhs == NULL ||
5111 return -1; /* why not */
5113 check_invariants (lhs);
5114 check_invariants (rhs);
5116 if (real_lhs->line == real_rhs->line)
5118 gint left_index, right_index;
5120 if (real_lhs->line_byte_offset >= 0 &&
5121 real_rhs->line_byte_offset >= 0)
5123 left_index = real_lhs->line_byte_offset;
5124 right_index = real_rhs->line_byte_offset;
5128 /* the ensure_char_offsets () calls do nothing if
5129 the offsets are already up-to-date. */
5130 ensure_char_offsets (real_lhs);
5131 ensure_char_offsets (real_rhs);
5132 left_index = real_lhs->line_char_offset;
5133 right_index = real_rhs->line_char_offset;
5136 if (left_index < right_index)
5138 else if (left_index > right_index)
5147 line1 = gtk_text_iter_get_line (lhs);
5148 line2 = gtk_text_iter_get_line (rhs);
5151 else if (line1 > line2)
5159 * gtk_text_iter_in_range:
5160 * @iter: a #GtkTextIter
5161 * @start: start of range
5162 * @end: end of range
5164 * Checks whether @iter falls in the range [@start, @end).
5165 * @start and @end must be in ascending order.
5167 * Return value: %TRUE if @iter is in the range
5170 gtk_text_iter_in_range (const GtkTextIter *iter,
5171 const GtkTextIter *start,
5172 const GtkTextIter *end)
5174 g_return_val_if_fail (iter != NULL, FALSE);
5175 g_return_val_if_fail (start != NULL, FALSE);
5176 g_return_val_if_fail (end != NULL, FALSE);
5177 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5179 return gtk_text_iter_compare (iter, start) >= 0 &&
5180 gtk_text_iter_compare (iter, end) < 0;
5184 * gtk_text_iter_order:
5185 * @first: a #GtkTextIter
5186 * @second: another #GtkTextIter
5188 * Swaps the value of @first and @second if @second comes before
5189 * @first in the buffer. That is, ensures that @first and @second are
5190 * in sequence. Most text buffer functions that take a range call this
5191 * automatically on your behalf, so there's no real reason to call it yourself
5192 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5193 * that expect a pre-sorted range.
5197 gtk_text_iter_order (GtkTextIter *first,
5198 GtkTextIter *second)
5200 g_return_if_fail (first != NULL);
5201 g_return_if_fail (second != NULL);
5203 if (gtk_text_iter_compare (first, second) > 0)
5214 * Init iterators from the BTree
5218 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5222 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5223 gint real_char_index;
5227 g_return_if_fail (iter != NULL);
5228 g_return_if_fail (tree != NULL);
5230 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5231 &line_start, &real_char_index);
5233 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5235 real->cached_char_index = real_char_index;
5237 check_invariants (iter);
5241 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5246 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5250 g_return_if_fail (iter != NULL);
5251 g_return_if_fail (tree != NULL);
5253 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5255 iter_init_from_char_offset (iter, tree, line, char_on_line);
5257 /* We might as well cache this, since we know it. */
5258 real->cached_line_number = real_line;
5260 check_invariants (iter);
5264 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5269 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5273 g_return_if_fail (iter != NULL);
5274 g_return_if_fail (tree != NULL);
5276 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5278 iter_init_from_byte_offset (iter, tree, line, byte_index);
5280 /* We might as well cache this, since we know it. */
5281 real->cached_line_number = real_line;
5283 check_invariants (iter);
5287 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5292 g_return_if_fail (iter != NULL);
5293 g_return_if_fail (tree != NULL);
5294 g_return_if_fail (line != NULL);
5296 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5298 check_invariants (iter);
5302 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5308 g_return_val_if_fail (iter != NULL, FALSE);
5309 g_return_val_if_fail (tree != NULL, FALSE);
5311 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5315 /* Set iter to last in tree */
5316 _gtk_text_btree_get_end_iter (tree, iter);
5317 check_invariants (iter);
5322 iter_init_from_byte_offset (iter, tree, line, 0);
5324 if (!gtk_text_iter_toggles_tag (iter, tag))
5325 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5327 check_invariants (iter);
5333 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5337 g_return_val_if_fail (iter != NULL, FALSE);
5338 g_return_val_if_fail (tree != NULL, FALSE);
5340 _gtk_text_btree_get_end_iter (tree, iter);
5341 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5342 check_invariants (iter);
5348 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5350 const gchar *mark_name)
5354 g_return_val_if_fail (iter != NULL, FALSE);
5355 g_return_val_if_fail (tree != NULL, FALSE);
5357 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5363 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5364 check_invariants (iter);
5370 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5374 GtkTextLineSegment *seg;
5376 g_return_if_fail (iter != NULL);
5377 g_return_if_fail (tree != NULL);
5378 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5380 seg = mark->segment;
5382 iter_init_from_segment (iter, tree,
5383 seg->body.mark.line, seg);
5384 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5385 check_invariants (iter);
5389 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5391 GtkTextChildAnchor *anchor)
5393 GtkTextLineSegment *seg;
5395 g_return_if_fail (iter != NULL);
5396 g_return_if_fail (tree != NULL);
5397 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5399 seg = anchor->segment;
5401 g_assert (seg->body.child.line != NULL);
5403 iter_init_from_segment (iter, tree,
5404 seg->body.child.line, seg);
5405 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5406 check_invariants (iter);
5410 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5413 g_return_if_fail (iter != NULL);
5414 g_return_if_fail (tree != NULL);
5416 _gtk_text_btree_get_iter_at_char (tree,
5418 _gtk_text_btree_char_count (tree));
5419 check_invariants (iter);
5423 _gtk_text_iter_check (const GtkTextIter *iter)
5425 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5426 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5427 GtkTextLineSegment *byte_segment = NULL;
5428 GtkTextLineSegment *byte_any_segment = NULL;
5429 GtkTextLineSegment *char_segment = NULL;
5430 GtkTextLineSegment *char_any_segment = NULL;
5431 gboolean segments_updated;
5433 /* This function checks our class invariants for the Iter class. */
5435 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5437 if (real->chars_changed_stamp !=
5438 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5439 g_error ("iterator check failed: invalid iterator");
5441 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5442 g_error ("iterator check failed: both char and byte offsets are invalid");
5444 segments_updated = (real->segments_changed_stamp ==
5445 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5448 printf ("checking iter, segments %s updated, byte %d char %d\n",
5449 segments_updated ? "are" : "aren't",
5450 real->line_byte_offset,
5451 real->line_char_offset);
5454 if (segments_updated)
5456 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5457 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5459 if (real->segment->char_count == 0)
5460 g_error ("iterator check failed: segment is not indexable.");
5462 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5463 g_error ("segment char offset is not properly up-to-date");
5465 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5466 g_error ("segment byte offset is not properly up-to-date");
5468 if (real->segment_byte_offset >= 0 &&
5469 real->segment_byte_offset >= real->segment->byte_count)
5470 g_error ("segment byte offset is too large.");
5472 if (real->segment_char_offset >= 0 &&
5473 real->segment_char_offset >= real->segment->char_count)
5474 g_error ("segment char offset is too large.");
5477 if (real->line_byte_offset >= 0)
5479 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5480 &byte_segment, &byte_any_segment,
5481 &seg_byte_offset, &line_byte_offset);
5483 if (line_byte_offset != real->line_byte_offset)
5484 g_error ("wrong byte offset was stored in iterator");
5486 if (segments_updated)
5488 if (real->segment != byte_segment)
5489 g_error ("wrong segment was stored in iterator");
5491 if (real->any_segment != byte_any_segment)
5492 g_error ("wrong any_segment was stored in iterator");
5494 if (seg_byte_offset != real->segment_byte_offset)
5495 g_error ("wrong segment byte offset was stored in iterator");
5497 if (byte_segment->type == >k_text_char_type)
5500 p = byte_segment->body.chars + seg_byte_offset;
5502 if (!gtk_text_byte_begins_utf8_char (p))
5503 g_error ("broken iterator byte index pointed into the middle of a character");
5508 if (real->line_char_offset >= 0)
5510 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5511 &char_segment, &char_any_segment,
5512 &seg_char_offset, &line_char_offset);
5514 if (line_char_offset != real->line_char_offset)
5515 g_error ("wrong char offset was stored in iterator");
5517 if (segments_updated)
5519 if (real->segment != char_segment)
5520 g_error ("wrong segment was stored in iterator");
5522 if (real->any_segment != char_any_segment)
5523 g_error ("wrong any_segment was stored in iterator");
5525 if (seg_char_offset != real->segment_char_offset)
5526 g_error ("wrong segment char offset was stored in iterator");
5528 if (char_segment->type == >k_text_char_type)
5531 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5534 /* hmm, not likely to happen eh */
5535 if (!gtk_text_byte_begins_utf8_char (p))
5536 g_error ("broken iterator char offset pointed into the middle of a character");
5541 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5543 if (byte_segment != char_segment)
5544 g_error ("char and byte offsets did not point to the same segment");
5546 if (byte_any_segment != char_any_segment)
5547 g_error ("char and byte offsets did not point to the same any segment");
5549 /* Make sure the segment offsets are equivalent, if it's a char
5551 if (char_segment->type == >k_text_char_type)
5553 gint byte_offset = 0;
5554 gint char_offset = 0;
5555 while (char_offset < seg_char_offset)
5557 const char * start = char_segment->body.chars + byte_offset;
5558 byte_offset += g_utf8_next_char (start) - start;
5562 if (byte_offset != seg_byte_offset)
5563 g_error ("byte offset did not correspond to char offset");
5566 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5568 if (char_offset != seg_char_offset)
5569 g_error ("char offset did not correspond to byte offset");
5571 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5572 g_error ("byte index for iterator does not index the start of a character");
5576 if (real->cached_line_number >= 0)
5580 should_be = _gtk_text_line_get_number (real->line);
5581 if (real->cached_line_number != should_be)
5582 g_error ("wrong line number was cached");
5585 if (real->cached_char_index >= 0)
5587 if (real->line_char_offset >= 0) /* only way we can check it
5588 efficiently, not a real
5593 char_index = _gtk_text_line_char_index (real->line);
5594 char_index += real->line_char_offset;
5596 if (real->cached_char_index != char_index)
5597 g_error ("wrong char index was cached");
5601 if (_gtk_text_line_is_last (real->line, real->tree))
5602 g_error ("Iterator was on last line (past the end iterator)");
5605 #define __GTK_TEXT_ITER_C__
5606 #include "gtkaliasdef.c"