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_slice_new (GtkTextIter);
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);
465 g_slice_free (GtkTextIter, iter);
469 gtk_text_iter_get_type (void)
471 static GType our_type = 0;
474 our_type = g_boxed_type_register_static ("GtkTextIter",
475 (GBoxedCopyFunc) gtk_text_iter_copy,
476 (GBoxedFreeFunc) gtk_text_iter_free);
482 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
484 GtkTextRealIter *real;
486 g_return_val_if_fail (iter != NULL, NULL);
488 real = gtk_text_iter_make_real (iter);
493 check_invariants (iter);
495 g_assert (real->segment != NULL);
497 return real->segment;
501 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
503 GtkTextRealIter *real;
505 g_return_val_if_fail (iter != NULL, NULL);
507 real = gtk_text_iter_make_real (iter);
512 check_invariants (iter);
514 g_assert (real->any_segment != NULL);
516 return real->any_segment;
520 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
522 GtkTextRealIter *real;
524 g_return_val_if_fail (iter != NULL, 0);
526 real = gtk_text_iter_make_real (iter);
531 ensure_byte_offsets (real);
533 check_invariants (iter);
535 return real->segment_byte_offset;
539 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
541 GtkTextRealIter *real;
543 g_return_val_if_fail (iter != NULL, 0);
545 real = gtk_text_iter_make_real (iter);
550 ensure_char_offsets (real);
552 check_invariants (iter);
554 return real->segment_char_offset;
557 /* This function does not require a still-valid
560 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
562 const GtkTextRealIter *real;
564 g_return_val_if_fail (iter != NULL, NULL);
566 real = (const GtkTextRealIter*)iter;
571 /* This function does not require a still-valid
574 _gtk_text_iter_get_btree (const GtkTextIter *iter)
576 const GtkTextRealIter *real;
578 g_return_val_if_fail (iter != NULL, NULL);
580 real = (const GtkTextRealIter*)iter;
590 * gtk_text_iter_get_offset:
593 * Returns the character offset of an iterator.
594 * Each character in a #GtkTextBuffer has an offset,
595 * starting with 0 for the first character in the buffer.
596 * Use gtk_text_buffer_get_iter_at_offset () to convert an
597 * offset back into an iterator.
599 * Return value: a character offset
602 gtk_text_iter_get_offset (const GtkTextIter *iter)
604 GtkTextRealIter *real;
606 g_return_val_if_fail (iter != NULL, 0);
608 real = gtk_text_iter_make_surreal (iter);
613 check_invariants (iter);
615 if (real->cached_char_index < 0)
617 ensure_char_offsets (real);
619 real->cached_char_index =
620 _gtk_text_line_char_index (real->line);
621 real->cached_char_index += real->line_char_offset;
624 check_invariants (iter);
626 return real->cached_char_index;
630 * gtk_text_iter_get_line:
633 * Returns the line number containing the iterator. Lines in
634 * a #GtkTextBuffer are numbered beginning with 0 for the first
635 * line in the buffer.
637 * Return value: a line number
640 gtk_text_iter_get_line (const GtkTextIter *iter)
642 GtkTextRealIter *real;
644 g_return_val_if_fail (iter != NULL, 0);
646 real = gtk_text_iter_make_surreal (iter);
651 if (real->cached_line_number < 0)
652 real->cached_line_number =
653 _gtk_text_line_get_number (real->line);
655 check_invariants (iter);
657 return real->cached_line_number;
661 * gtk_text_iter_get_line_offset:
664 * Returns the character offset of the iterator,
665 * counting from the start of a newline-terminated line.
666 * The first character on the line has offset 0.
668 * Return value: offset from start of line
671 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
673 GtkTextRealIter *real;
675 g_return_val_if_fail (iter != NULL, 0);
677 real = gtk_text_iter_make_surreal (iter);
682 ensure_char_offsets (real);
684 check_invariants (iter);
686 return real->line_char_offset;
690 * gtk_text_iter_get_line_index:
693 * Returns the byte index of the iterator, counting
694 * from the start of a newline-terminated line.
695 * Remember that #GtkTextBuffer encodes text in
696 * UTF-8, and that characters can require a variable
697 * number of bytes to represent.
699 * Return value: distance from start of line, in bytes
702 gtk_text_iter_get_line_index (const GtkTextIter *iter)
704 GtkTextRealIter *real;
706 g_return_val_if_fail (iter != NULL, 0);
708 real = gtk_text_iter_make_surreal (iter);
713 ensure_byte_offsets (real);
715 check_invariants (iter);
717 return real->line_byte_offset;
721 * gtk_text_iter_get_visible_line_offset:
722 * @iter: a #GtkTextIter
724 * Returns the offset in characters from the start of the
725 * line to the given @iter, not counting characters that
726 * are invisible due to tags with the "invisible" flag
729 * Return value: offset in visible characters from the start of the line
732 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
734 GtkTextRealIter *real;
736 GtkTextLineSegment *seg;
739 g_return_val_if_fail (iter != NULL, 0);
741 real = gtk_text_iter_make_real (iter);
746 ensure_char_offsets (real);
748 check_invariants (iter);
750 vis_offset = real->line_char_offset;
752 g_assert (vis_offset >= 0);
754 _gtk_text_btree_get_iter_at_line (real->tree,
759 seg = _gtk_text_iter_get_indexable_segment (&pos);
761 while (seg != real->segment)
763 /* This is a pretty expensive call, making the
764 * whole function pretty lame; we could keep track
765 * of current invisibility state by looking at toggle
766 * segments as we loop, and then call this function
767 * only once per line, in order to speed up the loop
770 if (_gtk_text_btree_char_is_invisible (&pos))
771 vis_offset -= seg->char_count;
773 _gtk_text_iter_forward_indexable_segment (&pos);
775 seg = _gtk_text_iter_get_indexable_segment (&pos);
778 if (_gtk_text_btree_char_is_invisible (&pos))
779 vis_offset -= real->segment_char_offset;
786 * gtk_text_iter_get_visible_line_index:
787 * @iter: a #GtkTextIter
789 * Returns the number of bytes from the start of the
790 * line to the given @iter, not counting bytes that
791 * are invisible due to tags with the "invisible" flag
794 * Return value: byte index of @iter with respect to the start of the line
797 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
799 GtkTextRealIter *real;
801 GtkTextLineSegment *seg;
804 g_return_val_if_fail (iter != NULL, 0);
806 real = gtk_text_iter_make_real (iter);
811 ensure_byte_offsets (real);
813 check_invariants (iter);
815 vis_offset = real->line_byte_offset;
817 g_assert (vis_offset >= 0);
819 _gtk_text_btree_get_iter_at_line (real->tree,
824 seg = _gtk_text_iter_get_indexable_segment (&pos);
826 while (seg != real->segment)
828 /* This is a pretty expensive call, making the
829 * whole function pretty lame; we could keep track
830 * of current invisibility state by looking at toggle
831 * segments as we loop, and then call this function
832 * only once per line, in order to speed up the loop
835 if (_gtk_text_btree_char_is_invisible (&pos))
836 vis_offset -= seg->byte_count;
838 _gtk_text_iter_forward_indexable_segment (&pos);
840 seg = _gtk_text_iter_get_indexable_segment (&pos);
843 if (_gtk_text_btree_char_is_invisible (&pos))
844 vis_offset -= real->segment_byte_offset;
854 * gtk_text_iter_get_char:
857 * Returns the Unicode character at this iterator. (Equivalent to
858 * operator* on a C++ iterator.) If the element at this iterator is a
859 * non-character element, such as an image embedded in the buffer, the
860 * Unicode "unknown" character 0xFFFC is returned. If invoked on
861 * the end iterator, zero is returned; zero is not a valid Unicode character.
862 * So you can write a loop which ends when gtk_text_iter_get_char ()
865 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
868 gtk_text_iter_get_char (const GtkTextIter *iter)
870 GtkTextRealIter *real;
872 g_return_val_if_fail (iter != NULL, 0);
874 real = gtk_text_iter_make_real (iter);
879 check_invariants (iter);
881 if (gtk_text_iter_is_end (iter))
883 else if (real->segment->type == >k_text_char_type)
885 ensure_byte_offsets (real);
887 return g_utf8_get_char (real->segment->body.chars +
888 real->segment_byte_offset);
892 /* Unicode "unknown character" 0xFFFC */
893 return GTK_TEXT_UNKNOWN_CHAR;
898 * gtk_text_iter_get_slice:
899 * @start: iterator at start of a range
900 * @end: iterator at end of a range
902 * Returns the text in the given range. A "slice" is an array of
903 * characters encoded in UTF-8 format, including the Unicode "unknown"
904 * character 0xFFFC for iterable non-character elements in the buffer,
905 * such as images. Because images are encoded in the slice, byte and
906 * character offsets in the returned array will correspond to byte
907 * offsets in the text buffer. Note that 0xFFFC can occur in normal
908 * text as well, so it is not a reliable indicator that a pixbuf or
909 * widget is in the buffer.
911 * Return value: slice of text from the buffer
914 gtk_text_iter_get_slice (const GtkTextIter *start,
915 const GtkTextIter *end)
917 g_return_val_if_fail (start != NULL, NULL);
918 g_return_val_if_fail (end != NULL, NULL);
920 check_invariants (start);
921 check_invariants (end);
923 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
927 * gtk_text_iter_get_text:
928 * @start: iterator at start of a range
929 * @end: iterator at end of a range
931 * Returns <emphasis>text</emphasis> in the given range. If the range
932 * contains non-text elements such as images, the character and byte
933 * offsets in the returned string will not correspond to character and
934 * byte offsets in the buffer. If you want offsets to correspond, see
935 * gtk_text_iter_get_slice ().
937 * Return value: array of characters from the buffer
940 gtk_text_iter_get_text (const GtkTextIter *start,
941 const GtkTextIter *end)
943 g_return_val_if_fail (start != NULL, NULL);
944 g_return_val_if_fail (end != NULL, NULL);
946 check_invariants (start);
947 check_invariants (end);
949 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
953 * gtk_text_iter_get_visible_slice:
954 * @start: iterator at start of range
955 * @end: iterator at end of range
957 * Like gtk_text_iter_get_slice (), but invisible text is not included.
958 * Invisible text is usually invisible because a #GtkTextTag with the
959 * "invisible" attribute turned on has been applied to it.
961 * Return value: slice of text from the buffer
964 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
965 const GtkTextIter *end)
967 g_return_val_if_fail (start != NULL, NULL);
968 g_return_val_if_fail (end != NULL, NULL);
970 check_invariants (start);
971 check_invariants (end);
973 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
977 * gtk_text_iter_get_visible_text:
978 * @start: iterator at start of range
979 * @end: iterator at end of range
981 * Like gtk_text_iter_get_text (), but invisible text is not included.
982 * Invisible text is usually invisible because a #GtkTextTag with the
983 * "invisible" attribute turned on has been applied to it.
985 * Return value: string containing visible text in the range
988 gtk_text_iter_get_visible_text (const GtkTextIter *start,
989 const GtkTextIter *end)
991 g_return_val_if_fail (start != NULL, NULL);
992 g_return_val_if_fail (end != NULL, NULL);
994 check_invariants (start);
995 check_invariants (end);
997 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
1001 * gtk_text_iter_get_pixbuf:
1002 * @iter: an iterator
1004 * If the element at @iter is a pixbuf, the pixbuf is returned
1005 * (with no new reference count added). Otherwise,
1006 * %NULL is returned.
1008 * Return value: the pixbuf at @iter
1011 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1013 GtkTextRealIter *real;
1015 g_return_val_if_fail (iter != NULL, NULL);
1017 real = gtk_text_iter_make_real (iter);
1022 check_invariants (iter);
1024 if (real->segment->type != >k_text_pixbuf_type)
1027 return real->segment->body.pixbuf.pixbuf;
1031 * gtk_text_iter_get_child_anchor:
1032 * @iter: an iterator
1034 * If the location at @iter contains a child anchor, the
1035 * anchor is returned (with no new reference count added). Otherwise,
1036 * %NULL is returned.
1038 * Return value: the anchor at @iter
1041 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1043 GtkTextRealIter *real;
1045 g_return_val_if_fail (iter != NULL, NULL);
1047 real = gtk_text_iter_make_real (iter);
1052 check_invariants (iter);
1054 if (real->segment->type != >k_text_child_type)
1057 return real->segment->body.child.obj;
1061 * gtk_text_iter_get_marks:
1062 * @iter: an iterator
1064 * Returns a list of all #GtkTextMark at this location. Because marks
1065 * are not iterable (they don't take up any "space" in the buffer,
1066 * they are just marks in between iterable locations), multiple marks
1067 * can exist in the same place. The returned list is not in any
1070 * Return value: list of #GtkTextMark
1073 gtk_text_iter_get_marks (const GtkTextIter *iter)
1075 GtkTextRealIter *real;
1076 GtkTextLineSegment *seg;
1079 g_return_val_if_fail (iter != NULL, NULL);
1081 real = gtk_text_iter_make_real (iter);
1086 check_invariants (iter);
1089 seg = real->any_segment;
1090 while (seg != real->segment)
1092 if (seg->type == >k_text_left_mark_type ||
1093 seg->type == >k_text_right_mark_type)
1094 retval = g_slist_prepend (retval, seg->body.mark.obj);
1099 /* The returned list isn't guaranteed to be in any special order,
1105 * gtk_text_iter_get_toggled_tags:
1106 * @iter: an iterator
1107 * @toggled_on: %TRUE to get toggled-on tags
1109 * Returns a list of #GtkTextTag that are toggled on or off at this
1110 * point. (If @toggled_on is %TRUE, the list contains tags that are
1111 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1112 * range of characters following @iter has that tag applied to it. If
1113 * a tag is toggled off, then some non-empty range following @iter
1114 * does <emphasis>not</emphasis> have the tag applied to it.
1116 * Return value: tags toggled at this point
1119 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1120 gboolean toggled_on)
1122 GtkTextRealIter *real;
1123 GtkTextLineSegment *seg;
1126 g_return_val_if_fail (iter != NULL, NULL);
1128 real = gtk_text_iter_make_real (iter);
1133 check_invariants (iter);
1136 seg = real->any_segment;
1137 while (seg != real->segment)
1141 if (seg->type == >k_text_toggle_on_type)
1143 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1148 if (seg->type == >k_text_toggle_off_type)
1150 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1157 /* The returned list isn't guaranteed to be in any special order,
1163 * gtk_text_iter_begins_tag:
1164 * @iter: an iterator
1165 * @tag: a #GtkTextTag, or %NULL
1167 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1168 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1169 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1170 * <emphasis>start</emphasis> of the tagged range;
1171 * gtk_text_iter_has_tag () tells you whether an iterator is
1172 * <emphasis>within</emphasis> a tagged range.
1174 * Return value: whether @iter is the start of a range tagged with @tag
1177 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1180 GtkTextRealIter *real;
1181 GtkTextLineSegment *seg;
1183 g_return_val_if_fail (iter != NULL, FALSE);
1185 real = gtk_text_iter_make_real (iter);
1190 check_invariants (iter);
1192 seg = real->any_segment;
1193 while (seg != real->segment)
1195 if (seg->type == >k_text_toggle_on_type)
1198 seg->body.toggle.info->tag == tag)
1209 * gtk_text_iter_ends_tag:
1210 * @iter: an iterator
1211 * @tag: a #GtkTextTag, or %NULL
1213 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1214 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1215 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1216 * <emphasis>end</emphasis> of the tagged range;
1217 * gtk_text_iter_has_tag () tells you whether an iterator is
1218 * <emphasis>within</emphasis> a tagged range.
1220 * Return value: whether @iter is the end of a range tagged with @tag
1224 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1227 GtkTextRealIter *real;
1228 GtkTextLineSegment *seg;
1230 g_return_val_if_fail (iter != NULL, FALSE);
1232 real = gtk_text_iter_make_real (iter);
1237 check_invariants (iter);
1239 seg = real->any_segment;
1240 while (seg != real->segment)
1242 if (seg->type == >k_text_toggle_off_type)
1245 seg->body.toggle.info->tag == tag)
1256 * gtk_text_iter_toggles_tag:
1257 * @iter: an iterator
1258 * @tag: a #GtkTextTag, or %NULL
1260 * This is equivalent to (gtk_text_iter_begins_tag () ||
1261 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1262 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1264 * Return value: whether @tag is toggled on or off at @iter
1267 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1270 GtkTextRealIter *real;
1271 GtkTextLineSegment *seg;
1273 g_return_val_if_fail (iter != NULL, FALSE);
1275 real = gtk_text_iter_make_real (iter);
1280 check_invariants (iter);
1282 seg = real->any_segment;
1283 while (seg != real->segment)
1285 if ( (seg->type == >k_text_toggle_off_type ||
1286 seg->type == >k_text_toggle_on_type) &&
1288 seg->body.toggle.info->tag == tag) )
1298 * gtk_text_iter_has_tag:
1299 * @iter: an iterator
1300 * @tag: a #GtkTextTag
1302 * Returns %TRUE if @iter is within a range tagged with @tag.
1304 * Return value: whether @iter is tagged with @tag
1307 gtk_text_iter_has_tag (const GtkTextIter *iter,
1310 GtkTextRealIter *real;
1312 g_return_val_if_fail (iter != NULL, FALSE);
1313 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1315 real = gtk_text_iter_make_surreal (iter);
1320 check_invariants (iter);
1322 if (real->line_byte_offset >= 0)
1324 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1325 real->line_byte_offset, tag);
1329 g_assert (real->line_char_offset >= 0);
1330 return _gtk_text_line_char_has_tag (real->line, real->tree,
1331 real->line_char_offset, tag);
1336 * gtk_text_iter_get_tags:
1337 * @iter: a #GtkTextIter
1339 * Returns a list of tags that apply to @iter, in ascending order of
1340 * priority (highest-priority tags are last). The #GtkTextTag in the
1341 * list don't have a reference added, but you have to free the list
1344 * Return value: list of #GtkTextTag
1347 gtk_text_iter_get_tags (const GtkTextIter *iter)
1354 g_return_val_if_fail (iter != NULL, NULL);
1356 /* Get the tags at this spot */
1357 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1359 /* No tags, use default style */
1360 if (tags == NULL || tag_count == 0)
1368 /* Sort tags in ascending order of priority */
1369 _gtk_text_tag_array_sort (tags, tag_count);
1373 while (i < tag_count)
1375 retval = g_slist_prepend (retval, tags[i]);
1381 /* Return tags in ascending order of priority */
1382 return g_slist_reverse (retval);
1386 * gtk_text_iter_editable:
1387 * @iter: an iterator
1388 * @default_setting: %TRUE if text is editable by default
1390 * Returns whether the character at @iter is within an editable region
1391 * of text. Non-editable text is "locked" and can't be changed by the
1392 * user via #GtkTextView. This function is simply a convenience
1393 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1394 * to this text affect editability, @default_setting will be returned.
1396 * You don't want to use this function to decide whether text can be
1397 * inserted at @iter, because for insertion you don't want to know
1398 * whether the char at @iter is inside an editable range, you want to
1399 * know whether a new character inserted at @iter would be inside an
1400 * editable range. Use gtk_text_iter_can_insert() to handle this
1403 * Return value: whether @iter is inside an editable range
1406 gtk_text_iter_editable (const GtkTextIter *iter,
1407 gboolean default_setting)
1409 GtkTextAttributes *values;
1412 g_return_val_if_fail (iter != NULL, FALSE);
1414 values = gtk_text_attributes_new ();
1416 values->editable = default_setting;
1418 gtk_text_iter_get_attributes (iter, values);
1420 retval = values->editable;
1422 gtk_text_attributes_unref (values);
1428 * gtk_text_iter_can_insert:
1429 * @iter: an iterator
1430 * @default_editability: %TRUE if text is editable by default
1432 * Considering the default editability of the buffer, and tags that
1433 * affect editability, determines whether text inserted at @iter would
1434 * be editable. If text inserted at @iter would be editable then the
1435 * user should be allowed to insert text at @iter.
1436 * gtk_text_buffer_insert_interactive() uses this function to decide
1437 * whether insertions are allowed at a given position.
1439 * Return value: whether text inserted at @iter would be editable
1442 gtk_text_iter_can_insert (const GtkTextIter *iter,
1443 gboolean default_editability)
1445 g_return_val_if_fail (iter != NULL, FALSE);
1447 if (gtk_text_iter_editable (iter, default_editability))
1449 /* If at start/end of buffer, default editability is used */
1450 else if ((gtk_text_iter_is_start (iter) ||
1451 gtk_text_iter_is_end (iter)) &&
1452 default_editability)
1456 /* if iter isn't editable, and the char before iter is,
1457 * then iter is the first char in an editable region
1458 * and thus insertion at iter results in editable text.
1460 GtkTextIter prev = *iter;
1461 gtk_text_iter_backward_char (&prev);
1462 return gtk_text_iter_editable (&prev, default_editability);
1468 * gtk_text_iter_get_language:
1469 * @iter: an iterator
1471 * A convenience wrapper around gtk_text_iter_get_attributes (),
1472 * which returns the language in effect at @iter. If no tags affecting
1473 * language apply to @iter, the return value is identical to that of
1474 * gtk_get_default_language ().
1476 * Return value: language in effect at @iter
1479 gtk_text_iter_get_language (const GtkTextIter *iter)
1481 GtkTextAttributes *values;
1482 PangoLanguage *retval;
1484 values = gtk_text_attributes_new ();
1486 gtk_text_iter_get_attributes (iter, values);
1488 retval = values->language;
1490 gtk_text_attributes_unref (values);
1496 * gtk_text_iter_starts_line:
1497 * @iter: an iterator
1499 * Returns %TRUE if @iter begins a paragraph,
1500 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1501 * However this function is potentially more efficient than
1502 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1503 * the offset, it just has to see whether it's 0.
1505 * Return value: whether @iter begins a line
1508 gtk_text_iter_starts_line (const GtkTextIter *iter)
1510 GtkTextRealIter *real;
1512 g_return_val_if_fail (iter != NULL, FALSE);
1514 real = gtk_text_iter_make_surreal (iter);
1519 check_invariants (iter);
1521 if (real->line_byte_offset >= 0)
1523 return (real->line_byte_offset == 0);
1527 g_assert (real->line_char_offset >= 0);
1528 return (real->line_char_offset == 0);
1533 * gtk_text_iter_ends_line:
1534 * @iter: an iterator
1536 * Returns %TRUE if @iter points to the start of the paragraph
1537 * delimiter characters for a line (delimiters will be either a
1538 * newline, a carriage return, a carriage return followed by a
1539 * newline, or a Unicode paragraph separator character). Note that an
1540 * iterator pointing to the \n of a \r\n pair will not be counted as
1541 * the end of a line, the line ends before the \r. The end iterator is
1542 * considered to be at the end of a line, even though there are no
1543 * paragraph delimiter chars there.
1545 * Return value: whether @iter is at the end of a line
1548 gtk_text_iter_ends_line (const GtkTextIter *iter)
1552 g_return_val_if_fail (iter != NULL, FALSE);
1554 check_invariants (iter);
1556 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1557 * Unicode 3.0; update this if that changes.
1559 #define PARAGRAPH_SEPARATOR 0x2029
1561 wc = gtk_text_iter_get_char (iter);
1563 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1565 else if (wc == '\n')
1567 /* need to determine if a \r precedes the \n, in which case
1568 * we aren't the end of the line
1570 GtkTextIter tmp = *iter;
1571 if (!gtk_text_iter_backward_char (&tmp))
1574 return gtk_text_iter_get_char (&tmp) != '\r';
1581 * gtk_text_iter_is_end:
1582 * @iter: an iterator
1584 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1585 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1586 * the most efficient way to check whether an iterator is the end
1589 * Return value: whether @iter is the end iterator
1592 gtk_text_iter_is_end (const GtkTextIter *iter)
1594 GtkTextRealIter *real;
1596 g_return_val_if_fail (iter != NULL, FALSE);
1598 real = gtk_text_iter_make_surreal (iter);
1603 check_invariants (iter);
1605 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1608 /* Now we need the segments validated */
1609 real = gtk_text_iter_make_real (iter);
1614 return _gtk_text_btree_is_end (real->tree, real->line,
1616 real->segment_byte_offset,
1617 real->segment_char_offset);
1621 * gtk_text_iter_is_start:
1622 * @iter: an iterator
1624 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1625 * if @iter has a character offset of 0.
1627 * Return value: whether @iter is the first in the buffer
1630 gtk_text_iter_is_start (const GtkTextIter *iter)
1632 return gtk_text_iter_get_offset (iter) == 0;
1636 * gtk_text_iter_get_chars_in_line:
1637 * @iter: an iterator
1639 * Returns the number of characters in the line containing @iter,
1640 * including the paragraph delimiters.
1642 * Return value: number of characters in the line
1645 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1647 GtkTextRealIter *real;
1649 GtkTextLineSegment *seg;
1651 g_return_val_if_fail (iter != NULL, 0);
1653 real = gtk_text_iter_make_surreal (iter);
1658 check_invariants (iter);
1660 if (real->line_char_offset >= 0)
1662 /* We can start at the segments we've already found. */
1663 count = real->line_char_offset - real->segment_char_offset;
1664 seg = _gtk_text_iter_get_indexable_segment (iter);
1668 /* count whole line. */
1669 seg = real->line->segments;
1676 count += seg->char_count;
1681 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1682 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1688 * gtk_text_iter_get_bytes_in_line:
1689 * @iter: an iterator
1691 * Returns the number of bytes in the line containing @iter,
1692 * including the paragraph delimiters.
1694 * Return value: number of bytes in the line
1697 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1699 GtkTextRealIter *real;
1701 GtkTextLineSegment *seg;
1703 g_return_val_if_fail (iter != NULL, 0);
1705 real = gtk_text_iter_make_surreal (iter);
1710 check_invariants (iter);
1712 if (real->line_byte_offset >= 0)
1714 /* We can start at the segments we've already found. */
1715 count = real->line_byte_offset - real->segment_byte_offset;
1716 seg = _gtk_text_iter_get_indexable_segment (iter);
1720 /* count whole line. */
1721 seg = real->line->segments;
1727 count += seg->byte_count;
1732 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1733 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1739 * gtk_text_iter_get_attributes:
1740 * @iter: an iterator
1741 * @values: a #GtkTextAttributes to be filled in
1743 * Computes the effect of any tags applied to this spot in the
1744 * text. The @values parameter should be initialized to the default
1745 * settings you wish to use if no tags are in effect. You'd typically
1746 * obtain the defaults from gtk_text_view_get_default_attributes().
1748 * gtk_text_iter_get_attributes () will modify @values, applying the
1749 * effects of any tags present at @iter. If any tags affected @values,
1750 * the function returns %TRUE.
1752 * Return value: %TRUE if @values was modified
1755 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1756 GtkTextAttributes *values)
1761 /* Get the tags at this spot */
1762 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1764 /* No tags, use default style */
1765 if (tags == NULL || tag_count == 0)
1773 /* Sort tags in ascending order of priority */
1774 _gtk_text_tag_array_sort (tags, tag_count);
1776 _gtk_text_attributes_fill_from_tags (values,
1786 * Increments/decrements
1789 /* The return value of this indicates WHETHER WE MOVED.
1790 * The return value of public functions indicates
1791 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1793 * This function will not change the iterator if
1794 * it's already on the last (end iter) line, i.e. it
1795 * won't move to the end of the last line.
1798 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1800 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1802 GtkTextLine *new_line;
1804 new_line = _gtk_text_line_next (real->line);
1805 g_assert (new_line);
1806 g_assert (new_line != real->line);
1807 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1809 real->line = new_line;
1811 real->line_byte_offset = 0;
1812 real->line_char_offset = 0;
1814 real->segment_byte_offset = 0;
1815 real->segment_char_offset = 0;
1817 /* Find first segments in new line */
1818 real->any_segment = real->line->segments;
1819 real->segment = real->any_segment;
1820 while (real->segment->char_count == 0)
1821 real->segment = real->segment->next;
1827 /* There is no way to move forward a line; we were already at
1828 * the line containing the end iterator.
1829 * However we may not be at the end iterator itself.
1837 /* The return value of this indicates WHETHER WE MOVED.
1838 * The return value of public functions indicates
1839 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1841 * This function is currently unused, thus it is #if-0-ed. It is
1842 * left here, since it's non-trivial code that might be useful in
1846 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1848 GtkTextLine *new_line;
1850 new_line = _gtk_text_line_previous (real->line);
1852 g_assert (new_line != real->line);
1854 if (new_line != NULL)
1856 real->line = new_line;
1858 real->line_byte_offset = 0;
1859 real->line_char_offset = 0;
1861 real->segment_byte_offset = 0;
1862 real->segment_char_offset = 0;
1864 /* Find first segments in new line */
1865 real->any_segment = real->line->segments;
1866 real->segment = real->any_segment;
1867 while (real->segment->char_count == 0)
1868 real->segment = real->segment->next;
1874 /* There is no way to move backward; we were already
1875 at the first line. */
1877 /* We leave real->line as-is */
1879 /* Note that we didn't clamp to the start of the first line. */
1886 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1890 forward_char (GtkTextRealIter *real)
1892 GtkTextIter *iter = (GtkTextIter*)real;
1894 check_invariants ((GtkTextIter*)real);
1896 ensure_char_offsets (real);
1898 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1900 /* Need to move to the next segment; if no next segment,
1901 need to move to next line. */
1902 return _gtk_text_iter_forward_indexable_segment (iter);
1906 /* Just moving within a segment. Keep byte count
1907 up-to-date, if it was already up-to-date. */
1909 g_assert (real->segment->type == >k_text_char_type);
1911 if (real->line_byte_offset >= 0)
1914 const char * start =
1915 real->segment->body.chars + real->segment_byte_offset;
1917 bytes = g_utf8_next_char (start) - start;
1919 real->line_byte_offset += bytes;
1920 real->segment_byte_offset += bytes;
1922 g_assert (real->segment_byte_offset < real->segment->byte_count);
1925 real->line_char_offset += 1;
1926 real->segment_char_offset += 1;
1928 adjust_char_index (real, 1);
1930 g_assert (real->segment_char_offset < real->segment->char_count);
1932 /* We moved into the middle of a segment, so the any_segment
1933 must now be the segment we're in the middle of. */
1934 real->any_segment = real->segment;
1936 check_invariants ((GtkTextIter*)real);
1938 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1946 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1948 /* Need to move to the next segment; if no next segment,
1949 need to move to next line. */
1950 GtkTextLineSegment *seg;
1951 GtkTextLineSegment *any_seg;
1952 GtkTextRealIter *real;
1956 g_return_val_if_fail (iter != NULL, FALSE);
1958 real = gtk_text_iter_make_real (iter);
1963 check_invariants (iter);
1965 if (real->line_char_offset >= 0)
1967 chars_skipped = real->segment->char_count - real->segment_char_offset;
1968 g_assert (chars_skipped > 0);
1973 if (real->line_byte_offset >= 0)
1975 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1976 g_assert (bytes_skipped > 0);
1981 /* Get first segment of any kind */
1982 any_seg = real->segment->next;
1983 /* skip non-indexable segments, if any */
1985 while (seg != NULL && seg->char_count == 0)
1990 real->any_segment = any_seg;
1991 real->segment = seg;
1993 if (real->line_byte_offset >= 0)
1995 g_assert (bytes_skipped > 0);
1996 real->segment_byte_offset = 0;
1997 real->line_byte_offset += bytes_skipped;
2000 if (real->line_char_offset >= 0)
2002 g_assert (chars_skipped > 0);
2003 real->segment_char_offset = 0;
2004 real->line_char_offset += chars_skipped;
2005 adjust_char_index (real, chars_skipped);
2008 check_invariants (iter);
2010 return !gtk_text_iter_is_end (iter);
2014 /* End of the line */
2015 if (forward_line_leaving_caches_unmodified (real))
2017 adjust_line_number (real, 1);
2018 if (real->line_char_offset >= 0)
2019 adjust_char_index (real, chars_skipped);
2021 g_assert (real->line_byte_offset == 0);
2022 g_assert (real->line_char_offset == 0);
2023 g_assert (real->segment_byte_offset == 0);
2024 g_assert (real->segment_char_offset == 0);
2025 g_assert (gtk_text_iter_starts_line (iter));
2027 check_invariants (iter);
2029 return !gtk_text_iter_is_end (iter);
2033 /* End of buffer, but iter is still at start of last segment,
2034 * not at the end iterator. We put it on the end iterator.
2037 check_invariants (iter);
2039 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2040 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2042 gtk_text_iter_forward_to_line_end (iter);
2044 g_assert (gtk_text_iter_is_end (iter));
2052 at_last_indexable_segment (GtkTextRealIter *real)
2054 GtkTextLineSegment *seg;
2056 /* Return TRUE if there are no indexable segments after
2060 seg = real->segment->next;
2063 if (seg->char_count > 0)
2070 /* Goes back to the start of the next segment, even if
2071 * we're not at the start of the current segment (always
2072 * ends up on a different segment if it returns TRUE)
2075 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2077 /* Move to the start of the previous segment; if no previous
2078 * segment, to the last segment in the previous line. This is
2079 * inherently a bit inefficient due to the singly-linked list and
2080 * tree nodes, but we can't afford the RAM for doubly-linked.
2082 GtkTextRealIter *real;
2083 GtkTextLineSegment *seg;
2084 GtkTextLineSegment *any_seg;
2085 GtkTextLineSegment *prev_seg;
2086 GtkTextLineSegment *prev_any_seg;
2090 g_return_val_if_fail (iter != NULL, FALSE);
2092 real = gtk_text_iter_make_real (iter);
2097 check_invariants (iter);
2099 /* Find first segments in line */
2100 any_seg = real->line->segments;
2102 while (seg->char_count == 0)
2105 if (seg == real->segment)
2107 /* Could probably do this case faster by hand-coding the
2111 /* We were already at the start of a line;
2112 * go back to the previous line.
2114 if (gtk_text_iter_backward_line (iter))
2116 /* Go forward to last indexable segment in line. */
2117 while (!at_last_indexable_segment (real))
2118 _gtk_text_iter_forward_indexable_segment (iter);
2120 check_invariants (iter);
2125 return FALSE; /* We were at the start of the first line. */
2128 /* We must be in the middle of a line; so find the indexable
2129 * segment just before our current segment.
2131 g_assert (seg != real->segment);
2135 prev_any_seg = any_seg;
2137 any_seg = seg->next;
2139 while (seg->char_count == 0)
2142 while (seg != real->segment);
2144 g_assert (prev_seg != NULL);
2145 g_assert (prev_any_seg != NULL);
2146 g_assert (prev_seg->char_count > 0);
2148 /* We skipped the entire previous segment, plus any
2149 * chars we were into the current segment.
2151 if (real->segment_byte_offset >= 0)
2152 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2156 if (real->segment_char_offset >= 0)
2157 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2161 real->segment = prev_seg;
2162 real->any_segment = prev_any_seg;
2163 real->segment_byte_offset = 0;
2164 real->segment_char_offset = 0;
2166 if (bytes_skipped >= 0)
2168 if (real->line_byte_offset >= 0)
2170 real->line_byte_offset -= bytes_skipped;
2171 g_assert (real->line_byte_offset >= 0);
2175 real->line_byte_offset = -1;
2177 if (chars_skipped >= 0)
2179 if (real->line_char_offset >= 0)
2181 real->line_char_offset -= chars_skipped;
2182 g_assert (real->line_char_offset >= 0);
2185 if (real->cached_char_index >= 0)
2187 real->cached_char_index -= chars_skipped;
2188 g_assert (real->cached_char_index >= 0);
2193 real->line_char_offset = -1;
2194 real->cached_char_index = -1;
2197 /* line number is unchanged. */
2199 check_invariants (iter);
2205 * gtk_text_iter_forward_char:
2206 * @iter: an iterator
2208 * Moves @iter forward by one character offset. Note that images
2209 * embedded in the buffer occupy 1 character slot, so
2210 * gtk_text_iter_forward_char () may actually move onto an image instead
2211 * of a character, if you have images in your buffer. If @iter is the
2212 * end iterator or one character before it, @iter will now point at
2213 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2214 * convenience when writing loops.
2216 * Return value: whether @iter moved and is dereferenceable
2219 gtk_text_iter_forward_char (GtkTextIter *iter)
2221 GtkTextRealIter *real;
2223 g_return_val_if_fail (iter != NULL, FALSE);
2225 real = gtk_text_iter_make_real (iter);
2231 check_invariants (iter);
2232 return forward_char (real);
2237 * gtk_text_iter_backward_char:
2238 * @iter: an iterator
2240 * Moves backward by one character offset. Returns %TRUE if movement
2241 * was possible; if @iter was the first in the buffer (character
2242 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2245 * Return value: whether movement was possible
2248 gtk_text_iter_backward_char (GtkTextIter *iter)
2250 g_return_val_if_fail (iter != NULL, FALSE);
2252 check_invariants (iter);
2254 return gtk_text_iter_backward_chars (iter, 1);
2258 Definitely we should try to linear scan as often as possible for
2259 movement within a single line, because we can't use the BTree to
2260 speed within-line searches up; for movement between lines, we would
2261 like to avoid the linear scan probably.
2263 Instead of using this constant, it might be nice to cache the line
2264 length in the iterator and linear scan if motion is within a single
2267 I guess you'd have to profile the various approaches.
2269 #define MAX_LINEAR_SCAN 150
2273 * gtk_text_iter_forward_chars:
2274 * @iter: an iterator
2275 * @count: number of characters to move, may be negative
2277 * Moves @count characters if possible (if @count would move past the
2278 * start or end of the buffer, moves to the start or end of the
2279 * buffer). The return value indicates whether the new position of
2280 * @iter is different from its original position, and dereferenceable
2281 * (the last iterator in the buffer is not dereferenceable). If @count
2282 * is 0, the function does nothing and returns %FALSE.
2284 * Return value: whether @iter moved and is dereferenceable
2287 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2289 GtkTextRealIter *real;
2291 g_return_val_if_fail (iter != NULL, FALSE);
2293 FIX_OVERFLOWS (count);
2295 real = gtk_text_iter_make_real (iter);
2299 else if (count == 0)
2302 return gtk_text_iter_backward_chars (iter, 0 - count);
2303 else if (count < MAX_LINEAR_SCAN)
2305 check_invariants (iter);
2309 if (!forward_char (real))
2314 return forward_char (real);
2318 gint current_char_index;
2319 gint new_char_index;
2321 check_invariants (iter);
2323 current_char_index = gtk_text_iter_get_offset (iter);
2325 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2326 return FALSE; /* can't move forward */
2328 new_char_index = current_char_index + count;
2329 gtk_text_iter_set_offset (iter, new_char_index);
2331 check_invariants (iter);
2333 /* Return FALSE if we're on the non-dereferenceable end
2336 if (gtk_text_iter_is_end (iter))
2344 * gtk_text_iter_backward_chars:
2345 * @iter: an iterator
2346 * @count: number of characters to move
2348 * Moves @count characters backward, if possible (if @count would move
2349 * past the start or end of the buffer, moves to the start or end of
2350 * the buffer). The return value indicates whether the iterator moved
2351 * onto a dereferenceable position; if the iterator didn't move, or
2352 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2353 * the function does nothing and returns %FALSE.
2355 * Return value: whether @iter moved and is dereferenceable
2359 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2361 GtkTextRealIter *real;
2363 g_return_val_if_fail (iter != NULL, FALSE);
2365 FIX_OVERFLOWS (count);
2367 real = gtk_text_iter_make_real (iter);
2371 else if (count == 0)
2374 return gtk_text_iter_forward_chars (iter, 0 - count);
2376 ensure_char_offsets (real);
2377 check_invariants (iter);
2379 /* <, not <=, because if count == segment_char_offset
2380 * we're going to the front of the segment and the any_segment
2383 if (count < real->segment_char_offset)
2385 /* Optimize the within-segment case */
2386 g_assert (real->segment->char_count > 0);
2387 g_assert (real->segment->type == >k_text_char_type);
2389 if (real->line_byte_offset >= 0)
2392 gint new_byte_offset;
2394 /* if in the last fourth of the segment walk backwards */
2395 if (count < real->segment_char_offset / 4)
2396 p = g_utf8_offset_to_pointer (real->segment->body.chars + real->segment_byte_offset,
2399 p = g_utf8_offset_to_pointer (real->segment->body.chars,
2400 real->segment_char_offset - count);
2402 new_byte_offset = p - real->segment->body.chars;
2403 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2404 real->segment_byte_offset = new_byte_offset;
2407 real->segment_char_offset -= count;
2408 real->line_char_offset -= count;
2410 adjust_char_index (real, 0 - count);
2412 check_invariants (iter);
2418 /* We need to go back into previous segments. For now,
2419 * just keep this really simple. FIXME
2420 * use backward_indexable_segment.
2422 if (TRUE || count > MAX_LINEAR_SCAN)
2424 gint current_char_index;
2425 gint new_char_index;
2427 current_char_index = gtk_text_iter_get_offset (iter);
2429 if (current_char_index == 0)
2430 return FALSE; /* can't move backward */
2432 new_char_index = current_char_index - count;
2433 if (new_char_index < 0)
2436 gtk_text_iter_set_offset (iter, new_char_index);
2438 check_invariants (iter);
2444 /* FIXME backward_indexable_segment here */
2453 /* These two can't be implemented efficiently (always have to use
2454 * a linear scan, since that's the only way to find all the non-text
2459 * gtk_text_iter_forward_text_chars:
2460 * @iter: a #GtkTextIter
2461 * @count: number of chars to move
2463 * Moves forward by @count text characters (pixbufs, widgets,
2464 * etc. do not count as characters for this). Equivalent to moving
2465 * through the results of gtk_text_iter_get_text (), rather than
2466 * gtk_text_iter_get_slice ().
2468 * Return value: whether @iter moved and is dereferenceable
2471 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2480 * gtk_text_iter_forward_text_chars:
2481 * @iter: a #GtkTextIter
2482 * @count: number of chars to move
2484 * Moves backward by @count text characters (pixbufs, widgets,
2485 * etc. do not count as characters for this). Equivalent to moving
2486 * through the results of gtk_text_iter_get_text (), rather than
2487 * gtk_text_iter_get_slice ().
2489 * Return value: whether @iter moved and is dereferenceable
2492 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2501 * gtk_text_iter_forward_line:
2502 * @iter: an iterator
2504 * Moves @iter to the start of the next line. Returns %TRUE if there
2505 * was a next line to move to, and %FALSE if @iter was simply moved to
2506 * the end of the buffer and is now not dereferenceable, or if @iter was
2507 * already at the end of the buffer.
2509 * Return value: whether @iter can be dereferenced
2512 gtk_text_iter_forward_line (GtkTextIter *iter)
2514 GtkTextRealIter *real;
2516 g_return_val_if_fail (iter != NULL, FALSE);
2518 real = gtk_text_iter_make_real (iter);
2523 check_invariants (iter);
2525 if (forward_line_leaving_caches_unmodified (real))
2527 invalidate_char_index (real);
2528 adjust_line_number (real, 1);
2530 check_invariants (iter);
2532 if (gtk_text_iter_is_end (iter))
2539 /* On the last line, move to end of it */
2541 if (!gtk_text_iter_is_end (iter))
2542 gtk_text_iter_forward_to_end (iter);
2544 check_invariants (iter);
2550 * gtk_text_iter_backward_line:
2551 * @iter: an iterator
2553 * Moves @iter to the start of the previous line. Returns %TRUE if
2554 * @iter could be moved; i.e. if @iter was at character offset 0, this
2555 * function returns %FALSE. Therefore if @iter was already on line 0,
2556 * but not at the start of the line, @iter is snapped to the start of
2557 * the line and the function returns %TRUE. (Note that this implies that
2558 * in a loop calling this function, the line number may not change on
2559 * every iteration, if your first iteration is on line 0.)
2561 * Return value: whether @iter moved
2564 gtk_text_iter_backward_line (GtkTextIter *iter)
2566 GtkTextLine *new_line;
2567 GtkTextRealIter *real;
2568 gboolean offset_will_change;
2571 g_return_val_if_fail (iter != NULL, FALSE);
2573 real = gtk_text_iter_make_real (iter);
2578 check_invariants (iter);
2580 new_line = _gtk_text_line_previous (real->line);
2582 offset_will_change = FALSE;
2583 if (real->line_char_offset > 0)
2584 offset_will_change = TRUE;
2586 if (new_line != NULL)
2588 real->line = new_line;
2590 adjust_line_number (real, -1);
2594 if (!offset_will_change)
2598 invalidate_char_index (real);
2600 real->line_byte_offset = 0;
2601 real->line_char_offset = 0;
2603 real->segment_byte_offset = 0;
2604 real->segment_char_offset = 0;
2606 /* Find first segment in line */
2607 real->any_segment = real->line->segments;
2608 real->segment = _gtk_text_line_byte_to_segment (real->line,
2611 g_assert (offset == 0);
2613 /* Note that if we are on the first line, we snap to the start of
2614 * the first line and return TRUE, so TRUE means the iterator
2615 * changed, not that the line changed; this is maybe a bit
2616 * weird. I'm not sure there's an obvious right thing to do though.
2619 check_invariants (iter);
2626 * gtk_text_iter_forward_lines:
2627 * @iter: a #GtkTextIter
2628 * @count: number of lines to move forward
2630 * Moves @count lines forward, if possible (if @count would move
2631 * past the start or end of the buffer, moves to the start or end of
2632 * the buffer). The return value indicates whether the iterator moved
2633 * onto a dereferenceable position; if the iterator didn't move, or
2634 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2635 * the function does nothing and returns %FALSE. If @count is negative,
2636 * moves backward by 0 - @count lines.
2638 * Return value: whether @iter moved and is dereferenceable
2641 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2643 FIX_OVERFLOWS (count);
2646 return gtk_text_iter_backward_lines (iter, 0 - count);
2647 else if (count == 0)
2649 else if (count == 1)
2651 check_invariants (iter);
2652 return gtk_text_iter_forward_line (iter);
2658 if (gtk_text_iter_is_end (iter))
2661 old_line = gtk_text_iter_get_line (iter);
2663 gtk_text_iter_set_line (iter, old_line + count);
2665 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2667 /* count went past the last line, so move to end of last line */
2668 if (!gtk_text_iter_is_end (iter))
2669 gtk_text_iter_forward_to_end (iter);
2672 return !gtk_text_iter_is_end (iter);
2677 * gtk_text_iter_backward_lines:
2678 * @iter: a #GtkTextIter
2679 * @count: number of lines to move backward
2681 * Moves @count lines backward, if possible (if @count would move
2682 * past the start or end of the buffer, moves to the start or end of
2683 * the buffer). The return value indicates whether the iterator moved
2684 * onto a dereferenceable position; if the iterator didn't move, or
2685 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2686 * the function does nothing and returns %FALSE. If @count is negative,
2687 * moves forward by 0 - @count lines.
2689 * Return value: whether @iter moved and is dereferenceable
2692 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2694 FIX_OVERFLOWS (count);
2697 return gtk_text_iter_forward_lines (iter, 0 - count);
2698 else if (count == 0)
2700 else if (count == 1)
2702 return gtk_text_iter_backward_line (iter);
2708 old_line = gtk_text_iter_get_line (iter);
2710 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2712 return (gtk_text_iter_get_line (iter) != old_line);
2717 * gtk_text_iter_forward_visible_line:
2718 * @iter: an iterator
2720 * Moves @iter to the start of the next visible line. Returns %TRUE if there
2721 * was a next line to move to, and %FALSE if @iter was simply moved to
2722 * the end of the buffer and is now not dereferenceable, or if @iter was
2723 * already at the end of the buffer.
2725 * Return value: whether @iter can be dereferenced
2730 gtk_text_iter_forward_visible_line (GtkTextIter *iter)
2732 while (gtk_text_iter_forward_line (iter))
2734 if (!_gtk_text_btree_char_is_invisible (iter))
2740 if (!gtk_text_iter_forward_char (iter))
2743 if (!_gtk_text_btree_char_is_invisible (iter))
2746 while (!gtk_text_iter_ends_line (iter));
2754 * gtk_text_iter_backward_visible_line:
2755 * @iter: an iterator
2757 * Moves @iter to the start of the previous visible line. Returns %TRUE if
2758 * @iter could be moved; i.e. if @iter was at character offset 0, this
2759 * function returns %FALSE. Therefore if @iter was already on line 0,
2760 * but not at the start of the line, @iter is snapped to the start of
2761 * the line and the function returns %TRUE. (Note that this implies that
2762 * in a loop calling this function, the line number may not change on
2763 * every iteration, if your first iteration is on line 0.)
2765 * Return value: whether @iter moved
2770 gtk_text_iter_backward_visible_line (GtkTextIter *iter)
2772 while (gtk_text_iter_backward_line (iter))
2774 if (!_gtk_text_btree_char_is_invisible (iter))
2780 if (!gtk_text_iter_backward_char (iter))
2783 if (!_gtk_text_btree_char_is_invisible (iter))
2786 while (!gtk_text_iter_starts_line (iter));
2794 * gtk_text_iter_forward_visible_lines:
2795 * @iter: a #GtkTextIter
2796 * @count: number of lines to move forward
2798 * Moves @count visible lines forward, if possible (if @count would move
2799 * past the start or end of the buffer, moves to the start or end of
2800 * the buffer). The return value indicates whether the iterator moved
2801 * onto a dereferenceable position; if the iterator didn't move, or
2802 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2803 * the function does nothing and returns %FALSE. If @count is negative,
2804 * moves backward by 0 - @count lines.
2806 * Return value: whether @iter moved and is dereferenceable
2811 gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
2814 FIX_OVERFLOWS (count);
2817 return gtk_text_iter_backward_visible_lines (iter, 0 - count);
2818 else if (count == 0)
2820 else if (count == 1)
2822 check_invariants (iter);
2823 return gtk_text_iter_forward_visible_line (iter);
2827 while (gtk_text_iter_forward_visible_line (iter) && count > 0)
2834 * gtk_text_iter_backward_visible_lines:
2835 * @iter: a #GtkTextIter
2836 * @count: number of lines to move backward
2838 * Moves @count visible lines backward, if possible (if @count would move
2839 * past the start or end of the buffer, moves to the start or end of
2840 * the buffer). The return value indicates whether the iterator moved
2841 * onto a dereferenceable position; if the iterator didn't move, or
2842 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2843 * the function does nothing and returns %FALSE. If @count is negative,
2844 * moves forward by 0 - @count lines.
2846 * Return value: whether @iter moved and is dereferenceable
2851 gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
2854 FIX_OVERFLOWS (count);
2857 return gtk_text_iter_forward_visible_lines (iter, 0 - count);
2858 else if (count == 0)
2860 else if (count == 1)
2862 return gtk_text_iter_backward_visible_line (iter);
2866 while (gtk_text_iter_backward_visible_line (iter) && count > 0)
2872 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2877 gboolean already_moved_initially);
2879 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2887 find_word_end_func (const PangoLogAttr *attrs,
2892 gboolean already_moved_initially)
2894 if (!already_moved_initially)
2897 /* Find end of next word */
2898 while (offset < min_offset + len &&
2899 !attrs[offset].is_word_end)
2902 *found_offset = offset;
2904 return offset < min_offset + len;
2908 is_word_end_func (const PangoLogAttr *attrs,
2913 return attrs[offset].is_word_end;
2917 find_word_start_func (const PangoLogAttr *attrs,
2922 gboolean already_moved_initially)
2924 if (!already_moved_initially)
2927 /* Find start of prev word */
2928 while (offset >= min_offset &&
2929 !attrs[offset].is_word_start)
2932 *found_offset = offset;
2934 return offset >= min_offset;
2938 is_word_start_func (const PangoLogAttr *attrs,
2943 return attrs[offset].is_word_start;
2947 inside_word_func (const PangoLogAttr *attrs,
2952 /* Find next word start or end */
2953 while (offset >= min_offset &&
2954 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2958 return attrs[offset].is_word_start;
2963 /* Sentence funcs */
2966 find_sentence_end_func (const PangoLogAttr *attrs,
2971 gboolean already_moved_initially)
2973 if (!already_moved_initially)
2976 /* Find end of next sentence */
2977 while (offset < min_offset + len &&
2978 !attrs[offset].is_sentence_end)
2981 *found_offset = offset;
2983 return offset < min_offset + len;
2987 is_sentence_end_func (const PangoLogAttr *attrs,
2992 return attrs[offset].is_sentence_end;
2996 find_sentence_start_func (const PangoLogAttr *attrs,
3001 gboolean already_moved_initially)
3003 if (!already_moved_initially)
3006 /* Find start of prev sentence */
3007 while (offset >= min_offset &&
3008 !attrs[offset].is_sentence_start)
3011 *found_offset = offset;
3013 return offset >= min_offset;
3017 is_sentence_start_func (const PangoLogAttr *attrs,
3022 return attrs[offset].is_sentence_start;
3026 inside_sentence_func (const PangoLogAttr *attrs,
3031 /* Find next sentence start or end */
3032 while (offset >= min_offset &&
3033 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
3036 return attrs[offset].is_sentence_start;
3040 test_log_attrs (const GtkTextIter *iter,
3041 TestLogAttrFunc func)
3044 const PangoLogAttr *attrs;
3046 gboolean result = FALSE;
3048 g_return_val_if_fail (iter != NULL, FALSE);
3050 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3053 offset = gtk_text_iter_get_line_offset (iter);
3055 /* char_len may be 0 and attrs will be NULL if so, if
3056 * iter is the end iter and the last line is empty.
3058 * offset may be equal to char_len, since attrs contains an entry
3059 * for one past the end
3062 if (attrs && offset <= char_len)
3063 result = (* func) (attrs, offset, 0, char_len);
3069 find_line_log_attrs (const GtkTextIter *iter,
3070 FindLogAttrFunc func,
3072 gboolean already_moved_initially)
3075 const PangoLogAttr *attrs;
3077 gboolean result = FALSE;
3079 g_return_val_if_fail (iter != NULL, FALSE);
3081 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3084 offset = gtk_text_iter_get_line_offset (iter);
3086 /* char_len may be 0 and attrs will be NULL if so, if
3087 * iter is the end iter and the last line is empty
3091 result = (* func) (attrs, offset, 0, char_len, found_offset,
3092 already_moved_initially);
3097 /* FIXME this function is very, very gratuitously slow */
3099 find_by_log_attrs (GtkTextIter *iter,
3100 FindLogAttrFunc func,
3102 gboolean already_moved_initially)
3106 gboolean found = FALSE;
3108 g_return_val_if_fail (iter != NULL, FALSE);
3112 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
3118 if (gtk_text_iter_forward_line (iter))
3119 return find_by_log_attrs (iter, func, forward,
3126 /* go to end of previous line. need to check that
3127 * line is > 0 because backward_line snaps to start of
3128 * line 0 if it's on line 0
3130 if (gtk_text_iter_get_line (iter) > 0 &&
3131 gtk_text_iter_backward_line (iter))
3133 if (!gtk_text_iter_ends_line (iter))
3134 gtk_text_iter_forward_to_line_end (iter);
3136 return find_by_log_attrs (iter, func, forward,
3145 gtk_text_iter_set_line_offset (iter, offset);
3148 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
3149 !gtk_text_iter_is_end (iter);
3154 find_visible_by_log_attrs (GtkTextIter *iter,
3155 FindLogAttrFunc func,
3157 gboolean already_moved_initially)
3161 g_return_val_if_fail (iter != NULL, FALSE);
3165 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3167 if (!_gtk_text_btree_char_is_invisible (&pos))
3177 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3178 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3181 move_multiple_steps (GtkTextIter *iter,
3183 OneStepFunc step_forward,
3184 MultipleStepFunc n_steps_backward)
3186 g_return_val_if_fail (iter != NULL, FALSE);
3188 FIX_OVERFLOWS (count);
3194 return n_steps_backward (iter, -count);
3196 if (!step_forward (iter))
3202 if (!step_forward (iter))
3207 return !gtk_text_iter_is_end (iter);
3212 * gtk_text_iter_forward_word_end:
3213 * @iter: a #GtkTextIter
3215 * Moves forward to the next word end. (If @iter is currently on a
3216 * word end, moves forward to the next one after that.) Word breaks
3217 * are determined by Pango and should be correct for nearly any
3218 * language (if not, the correct fix would be to the Pango word break
3221 * Return value: %TRUE if @iter moved and is not the end iterator
3224 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3226 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3230 * gtk_text_iter_backward_word_start:
3231 * @iter: a #GtkTextIter
3233 * Moves backward to the previous word start. (If @iter is currently on a
3234 * word start, moves backward to the next one after that.) Word breaks
3235 * are determined by Pango and should be correct for nearly any
3236 * language (if not, the correct fix would be to the Pango word break
3239 * Return value: %TRUE if @iter moved and is not the end iterator
3242 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3244 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3247 /* FIXME a loop around a truly slow function means
3248 * a truly spectacularly slow function.
3252 * gtk_text_iter_forward_word_ends:
3253 * @iter: a #GtkTextIter
3254 * @count: number of times to move
3256 * Calls gtk_text_iter_forward_word_end() up to @count times.
3258 * Return value: %TRUE if @iter moved and is not the end iterator
3261 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3264 return move_multiple_steps (iter, count,
3265 gtk_text_iter_forward_word_end,
3266 gtk_text_iter_backward_word_starts);
3270 * gtk_text_iter_backward_word_starts
3271 * @iter: a #GtkTextIter
3272 * @count: number of times to move
3274 * Calls gtk_text_iter_backward_word_start() up to @count times.
3276 * Return value: %TRUE if @iter moved and is not the end iterator
3279 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3282 return move_multiple_steps (iter, count,
3283 gtk_text_iter_backward_word_start,
3284 gtk_text_iter_forward_word_ends);
3288 * gtk_text_iter_forward_visible_word_end:
3289 * @iter: a #GtkTextIter
3291 * Moves forward to the next visible word end. (If @iter is currently on a
3292 * word end, moves forward to the next one after that.) Word breaks
3293 * are determined by Pango and should be correct for nearly any
3294 * language (if not, the correct fix would be to the Pango word break
3297 * Return value: %TRUE if @iter moved and is not the end iterator
3302 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3304 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3308 * gtk_text_iter_backward_visible_word_start:
3309 * @iter: a #GtkTextIter
3311 * Moves backward to the previous visible word start. (If @iter is currently
3312 * on a word start, moves backward to the next one after that.) Word breaks
3313 * are determined by Pango and should be correct for nearly any
3314 * language (if not, the correct fix would be to the Pango word break
3317 * Return value: %TRUE if @iter moved and is not the end iterator
3322 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3324 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3328 * gtk_text_iter_forward_visible_word_ends:
3329 * @iter: a #GtkTextIter
3330 * @count: number of times to move
3332 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3334 * Return value: %TRUE if @iter moved and is not the end iterator
3339 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3342 return move_multiple_steps (iter, count,
3343 gtk_text_iter_forward_visible_word_end,
3344 gtk_text_iter_backward_visible_word_starts);
3348 * gtk_text_iter_backward_visible_word_starts
3349 * @iter: a #GtkTextIter
3350 * @count: number of times to move
3352 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3354 * Return value: %TRUE if @iter moved and is not the end iterator
3359 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3362 return move_multiple_steps (iter, count,
3363 gtk_text_iter_backward_visible_word_start,
3364 gtk_text_iter_forward_visible_word_ends);
3368 * gtk_text_iter_starts_word:
3369 * @iter: a #GtkTextIter
3371 * Determines whether @iter begins a natural-language word. Word
3372 * breaks are determined by Pango and should be correct for nearly any
3373 * language (if not, the correct fix would be to the Pango word break
3376 * Return value: %TRUE if @iter is at the start of a word
3379 gtk_text_iter_starts_word (const GtkTextIter *iter)
3381 return test_log_attrs (iter, is_word_start_func);
3385 * gtk_text_iter_ends_word:
3386 * @iter: a #GtkTextIter
3388 * Determines whether @iter ends a natural-language word. Word breaks
3389 * are determined by Pango and should be correct for nearly any
3390 * language (if not, the correct fix would be to the Pango word break
3393 * Return value: %TRUE if @iter is at the end of a word
3396 gtk_text_iter_ends_word (const GtkTextIter *iter)
3398 return test_log_attrs (iter, is_word_end_func);
3402 * gtk_text_iter_inside_word:
3403 * @iter: a #GtkTextIter
3405 * Determines whether @iter is inside a natural-language word (as
3406 * opposed to say inside some whitespace). Word breaks are determined
3407 * by Pango and should be correct for nearly any language (if not, the
3408 * correct fix would be to the Pango word break algorithms).
3410 * Return value: %TRUE if @iter is inside a word
3413 gtk_text_iter_inside_word (const GtkTextIter *iter)
3415 return test_log_attrs (iter, inside_word_func);
3419 * gtk_text_iter_starts_sentence:
3420 * @iter: a #GtkTextIter
3422 * Determines whether @iter begins a sentence. Sentence boundaries are
3423 * determined by Pango and should be correct for nearly any language
3424 * (if not, the correct fix would be to the Pango text boundary
3427 * Return value: %TRUE if @iter is at the start of a sentence.
3430 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3432 return test_log_attrs (iter, is_sentence_start_func);
3436 * gtk_text_iter_ends_sentence:
3437 * @iter: a #GtkTextIter
3439 * Determines whether @iter ends a sentence. Sentence boundaries are
3440 * determined by Pango and should be correct for nearly any language
3441 * (if not, the correct fix would be to the Pango text boundary
3444 * Return value: %TRUE if @iter is at the end of a sentence.
3447 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3449 return test_log_attrs (iter, is_sentence_end_func);
3453 * gtk_text_iter_inside_sentence:
3454 * @iter: a #GtkTextIter
3456 * Determines whether @iter is inside a sentence (as opposed to in
3457 * between two sentences, e.g. after a period and before the first
3458 * letter of the next sentence). Sentence boundaries are determined
3459 * by Pango and should be correct for nearly any language (if not, the
3460 * correct fix would be to the Pango text boundary algorithms).
3462 * Return value: %TRUE if @iter is inside a sentence.
3465 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3467 return test_log_attrs (iter, inside_sentence_func);
3471 * gtk_text_iter_forward_sentence_end:
3472 * @iter: a #GtkTextIter
3474 * Moves forward to the next sentence end. (If @iter is at the end of
3475 * a sentence, moves to the next end of sentence.) Sentence
3476 * boundaries are determined by Pango and should be correct for nearly
3477 * any language (if not, the correct fix would be to the Pango text
3478 * boundary algorithms).
3480 * Return value: %TRUE if @iter moved and is not the end iterator
3483 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3485 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3489 * gtk_text_iter_backward_sentence_start:
3490 * @iter: a #GtkTextIter
3492 * Moves backward to the previous sentence start; if @iter is already at
3493 * the start of a sentence, moves backward to the next one. Sentence
3494 * boundaries are determined by Pango and should be correct for nearly
3495 * any language (if not, the correct fix would be to the Pango text
3496 * boundary algorithms).
3498 * Return value: %TRUE if @iter moved and is not the end iterator
3501 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3503 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3506 /* FIXME a loop around a truly slow function means
3507 * a truly spectacularly slow function.
3510 * gtk_text_iter_forward_sentence_ends:
3511 * @iter: a #GtkTextIter
3512 * @count: number of sentences to move
3514 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3515 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3516 * negative, moves backward instead of forward.
3518 * Return value: %TRUE if @iter moved and is not the end iterator
3521 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3524 return move_multiple_steps (iter, count,
3525 gtk_text_iter_forward_sentence_end,
3526 gtk_text_iter_backward_sentence_starts);
3530 * gtk_text_iter_backward_sentence_starts:
3531 * @iter: a #GtkTextIter
3532 * @count: number of sentences to move
3534 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3535 * or until it returns %FALSE. If @count is negative, moves forward
3536 * instead of backward.
3538 * Return value: %TRUE if @iter moved and is not the end iterator
3541 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3544 return move_multiple_steps (iter, count,
3545 gtk_text_iter_backward_sentence_start,
3546 gtk_text_iter_forward_sentence_ends);
3550 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3555 gboolean already_moved_initially)
3557 if (!already_moved_initially)
3560 while (offset < (min_offset + len) &&
3561 !attrs[offset].is_cursor_position)
3564 *found_offset = offset;
3566 return offset < (min_offset + len);
3570 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3575 gboolean already_moved_initially)
3577 if (!already_moved_initially)
3580 while (offset > min_offset &&
3581 !attrs[offset].is_cursor_position)
3584 *found_offset = offset;
3586 return offset >= min_offset;
3590 is_cursor_pos_func (const PangoLogAttr *attrs,
3595 return attrs[offset].is_cursor_position;
3599 * gtk_text_iter_forward_cursor_position:
3600 * @iter: a #GtkTextIter
3602 * Moves @iter forward by a single cursor position. Cursor positions
3603 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3604 * surprisingly, there may not be a cursor position between all
3605 * characters. The most common example for European languages would be
3606 * a carriage return/newline sequence. For some Unicode characters,
3607 * the equivalent of say the letter "a" with an accent mark will be
3608 * represented as two characters, first the letter then a "combining
3609 * mark" that causes the accent to be rendered; so the cursor can't go
3610 * between those two characters. See also the #PangoLogAttr structure and
3611 * pango_break() function.
3613 * Return value: %TRUE if we moved and the new position is dereferenceable
3616 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3618 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3622 * gtk_text_iter_backward_cursor_position:
3623 * @iter: a #GtkTextIter
3625 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3627 * Return value: %TRUE if we moved
3630 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3632 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3636 * gtk_text_iter_forward_cursor_positions:
3637 * @iter: a #GtkTextIter
3638 * @count: number of positions to move
3640 * Moves up to @count cursor positions. See
3641 * gtk_text_iter_forward_cursor_position() for details.
3643 * Return value: %TRUE if we moved and the new position is dereferenceable
3646 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3649 return move_multiple_steps (iter, count,
3650 gtk_text_iter_forward_cursor_position,
3651 gtk_text_iter_backward_cursor_positions);
3655 * gtk_text_iter_backward_cursor_positions:
3656 * @iter: a #GtkTextIter
3657 * @count: number of positions to move
3659 * Moves up to @count cursor positions. See
3660 * gtk_text_iter_forward_cursor_position() for details.
3662 * Return value: %TRUE if we moved and the new position is dereferenceable
3665 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3668 return move_multiple_steps (iter, count,
3669 gtk_text_iter_backward_cursor_position,
3670 gtk_text_iter_forward_cursor_positions);
3674 * gtk_text_iter_forward_visible_cursor_position:
3675 * @iter: a #GtkTextIter
3677 * Moves @iter forward to the next visible cursor position. See
3678 * gtk_text_iter_forward_cursor_position() for details.
3680 * Return value: %TRUE if we moved and the new position is dereferenceable
3685 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3687 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3691 * gtk_text_iter_backward_visible_cursor_position:
3692 * @iter: a #GtkTextIter
3694 * Moves @iter forward to the previous visible cursor position. See
3695 * gtk_text_iter_backward_cursor_position() for details.
3697 * Return value: %TRUE if we moved and the new position is dereferenceable
3702 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3704 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3708 * gtk_text_iter_forward_visible_cursor_positions:
3709 * @iter: a #GtkTextIter
3710 * @count: number of positions to move
3712 * Moves up to @count visible cursor positions. See
3713 * gtk_text_iter_forward_cursor_position() for details.
3715 * Return value: %TRUE if we moved and the new position is dereferenceable
3720 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3723 return move_multiple_steps (iter, count,
3724 gtk_text_iter_forward_visible_cursor_position,
3725 gtk_text_iter_backward_visible_cursor_positions);
3729 * gtk_text_iter_backward_visible_cursor_positions:
3730 * @iter: a #GtkTextIter
3731 * @count: number of positions to move
3733 * Moves up to @count visible cursor positions. See
3734 * gtk_text_iter_backward_cursor_position() for details.
3736 * Return value: %TRUE if we moved and the new position is dereferenceable
3741 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3744 return move_multiple_steps (iter, count,
3745 gtk_text_iter_backward_visible_cursor_position,
3746 gtk_text_iter_forward_visible_cursor_positions);
3750 * gtk_text_iter_is_cursor_position:
3751 * @iter: a #GtkTextIter
3753 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3754 * pango_break() for details on what a cursor position is.
3756 * Return value: %TRUE if the cursor can be placed at @iter
3759 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3761 return test_log_attrs (iter, is_cursor_pos_func);
3765 * gtk_text_iter_set_line_offset:
3766 * @iter: a #GtkTextIter
3767 * @char_on_line: a character offset relative to the start of @iter's current line
3769 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3770 * (not byte) offset. The given character offset must be less than or
3771 * equal to the number of characters in the line; if equal, @iter
3772 * moves to the start of the next line. See
3773 * gtk_text_iter_set_line_index() if you have a byte index rather than
3774 * a character offset.
3778 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3781 GtkTextRealIter *real;
3784 g_return_if_fail (iter != NULL);
3786 real = gtk_text_iter_make_surreal (iter);
3791 check_invariants (iter);
3793 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3795 g_return_if_fail (char_on_line <= chars_in_line);
3797 if (char_on_line < chars_in_line)
3798 iter_set_from_char_offset (real, real->line, char_on_line);
3800 gtk_text_iter_forward_line (iter); /* set to start of next line */
3802 check_invariants (iter);
3806 * gtk_text_iter_set_line_index:
3807 * @iter: a #GtkTextIter
3808 * @byte_on_line: a byte index relative to the start of @iter's current line
3810 * Same as gtk_text_iter_set_line_offset(), but works with a
3811 * <emphasis>byte</emphasis> index. The given byte index must be at
3812 * the start of a character, it can't be in the middle of a UTF-8
3813 * encoded character.
3817 gtk_text_iter_set_line_index (GtkTextIter *iter,
3820 GtkTextRealIter *real;
3823 g_return_if_fail (iter != NULL);
3825 real = gtk_text_iter_make_surreal (iter);
3830 check_invariants (iter);
3832 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3834 g_return_if_fail (byte_on_line <= bytes_in_line);
3836 if (byte_on_line < bytes_in_line)
3837 iter_set_from_byte_offset (real, real->line, byte_on_line);
3839 gtk_text_iter_forward_line (iter);
3841 if (real->segment->type == >k_text_char_type &&
3842 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3843 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3844 "character; this will crash the text buffer. "
3845 "Byte indexes must refer to the start of a character.",
3846 G_STRLOC, byte_on_line);
3848 check_invariants (iter);
3853 * gtk_text_iter_set_visible_line_offset:
3854 * @iter: a #GtkTextIter
3855 * @char_on_line: a character offset
3857 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3858 * characters, i.e. text with a tag making it invisible is not
3859 * counted in the offset.
3862 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3865 gint chars_seen = 0;
3868 g_return_if_fail (iter != NULL);
3870 gtk_text_iter_set_line_offset (iter, 0);
3874 /* For now we use a ludicrously slow implementation */
3875 while (chars_seen < char_on_line)
3877 if (!_gtk_text_btree_char_is_invisible (&pos))
3880 if (!gtk_text_iter_forward_char (&pos))
3883 if (chars_seen == char_on_line)
3887 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3890 gtk_text_iter_forward_line (iter);
3894 * gtk_text_iter_set_visible_line_index:
3895 * @iter: a #GtkTextIter
3896 * @byte_on_line: a byte index
3898 * Like gtk_text_iter_set_line_index(), but the index is in visible
3899 * bytes, i.e. text with a tag making it invisible is not counted
3903 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3906 GtkTextRealIter *real;
3907 gint bytes_in_line = 0;
3910 GtkTextLineSegment *seg;
3912 g_return_if_fail (iter != NULL);
3914 gtk_text_iter_set_line_offset (iter, 0);
3916 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3920 real = gtk_text_iter_make_real (&pos);
3925 ensure_byte_offsets (real);
3927 check_invariants (&pos);
3929 seg = _gtk_text_iter_get_indexable_segment (&pos);
3931 while (seg != NULL && byte_on_line > 0)
3933 if (!_gtk_text_btree_char_is_invisible (&pos))
3935 if (byte_on_line < seg->byte_count)
3937 iter_set_from_byte_offset (real, real->line, offset + byte_on_line);
3942 byte_on_line -= seg->byte_count;
3945 offset += seg->byte_count;
3946 _gtk_text_iter_forward_indexable_segment (&pos);
3947 seg = _gtk_text_iter_get_indexable_segment (&pos);
3950 if (byte_on_line == 0)
3953 gtk_text_iter_forward_line (iter);
3957 * gtk_text_iter_set_line:
3958 * @iter: a #GtkTextIter
3959 * @line_number: line number (counted from 0)
3961 * Moves iterator @iter to the start of the line @line_number. If
3962 * @line_number is negative or larger than the number of lines in the
3963 * buffer, moves @iter to the start of the last line in the buffer.
3967 gtk_text_iter_set_line (GtkTextIter *iter,
3972 GtkTextRealIter *real;
3974 g_return_if_fail (iter != NULL);
3976 real = gtk_text_iter_make_surreal (iter);
3981 check_invariants (iter);
3983 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3985 iter_set_from_char_offset (real, line, 0);
3987 /* We might as well cache this, since we know it. */
3988 real->cached_line_number = real_line;
3990 check_invariants (iter);
3994 * gtk_text_iter_set_offset:
3995 * @iter: a #GtkTextIter
3996 * @char_offset: a character number
3998 * Sets @iter to point to @char_offset. @char_offset counts from the start
3999 * of the entire text buffer, starting with 0.
4002 gtk_text_iter_set_offset (GtkTextIter *iter,
4006 GtkTextRealIter *real;
4008 gint real_char_index;
4010 g_return_if_fail (iter != NULL);
4012 real = gtk_text_iter_make_surreal (iter);
4017 check_invariants (iter);
4019 if (real->cached_char_index >= 0 &&
4020 real->cached_char_index == char_offset)
4023 line = _gtk_text_btree_get_line_at_char (real->tree,
4028 iter_set_from_char_offset (real, line, real_char_index - line_start);
4030 /* Go ahead and cache this since we have it. */
4031 real->cached_char_index = real_char_index;
4033 check_invariants (iter);
4037 * gtk_text_iter_forward_to_end:
4038 * @iter: a #GtkTextIter
4040 * Moves @iter forward to the "end iterator," which points one past the last
4041 * valid character in the buffer. gtk_text_iter_get_char() called on the
4042 * end iterator returns 0, which is convenient for writing loops.
4045 gtk_text_iter_forward_to_end (GtkTextIter *iter)
4047 GtkTextBuffer *buffer;
4048 GtkTextRealIter *real;
4050 g_return_if_fail (iter != NULL);
4052 real = gtk_text_iter_make_surreal (iter);
4057 buffer = _gtk_text_btree_get_buffer (real->tree);
4059 gtk_text_buffer_get_end_iter (buffer, iter);
4062 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
4063 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
4064 * If all else fails we could cache the para delimiter pos in the iter.
4065 * I think forward_to_line_end() actually gets called fairly often.
4068 find_paragraph_delimiter_for_line (GtkTextIter *iter)
4073 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
4074 _gtk_text_iter_get_btree (&end)))
4076 gtk_text_iter_forward_to_end (&end);
4080 /* if we aren't on the last line, go forward to start of next line, then scan
4081 * back for the delimiters on the previous line
4083 gtk_text_iter_forward_line (&end);
4084 gtk_text_iter_backward_char (&end);
4085 while (!gtk_text_iter_ends_line (&end))
4086 gtk_text_iter_backward_char (&end);
4089 return gtk_text_iter_get_line_offset (&end);
4093 * gtk_text_iter_forward_to_line_end:
4094 * @iter: a #GtkTextIter
4096 * Moves the iterator to point to the paragraph delimiter characters,
4097 * which will be either a newline, a carriage return, a carriage
4098 * return/newline in sequence, or the Unicode paragraph separator
4099 * character. If the iterator is already at the paragraph delimiter
4100 * characters, moves to the paragraph delimiter characters for the
4101 * next line. If @iter is on the last line in the buffer, which does
4102 * not end in paragraph delimiters, moves to the end iterator (end of
4103 * the last line), and returns %FALSE.
4105 * Return value: %TRUE if we moved and the new location is not the end iterator
4108 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
4110 gint current_offset;
4114 g_return_val_if_fail (iter != NULL, FALSE);
4116 current_offset = gtk_text_iter_get_line_offset (iter);
4117 new_offset = find_paragraph_delimiter_for_line (iter);
4119 if (current_offset < new_offset)
4121 /* Move to end of this line. */
4122 gtk_text_iter_set_line_offset (iter, new_offset);
4123 return !gtk_text_iter_is_end (iter);
4127 /* Move to end of next line. */
4128 if (gtk_text_iter_forward_line (iter))
4130 /* We don't want to move past all
4133 if (!gtk_text_iter_ends_line (iter))
4134 gtk_text_iter_forward_to_line_end (iter);
4135 return !gtk_text_iter_is_end (iter);
4143 * gtk_text_iter_forward_to_tag_toggle:
4144 * @iter: a #GtkTextIter
4145 * @tag: a #GtkTextTag, or %NULL
4147 * Moves forward to the next toggle (on or off) of the
4148 * #GtkTextTag @tag, or to the next toggle of any tag if
4149 * @tag is %NULL. If no matching tag toggles are found,
4150 * returns %FALSE, otherwise %TRUE. Does not return toggles
4151 * located at @iter, only toggles after @iter. Sets @iter to
4152 * the location of the toggle, or to the end of the buffer
4153 * if no toggle is found.
4155 * Return value: whether we found a tag toggle after @iter
4158 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4161 GtkTextLine *next_line;
4162 GtkTextLine *current_line;
4163 GtkTextRealIter *real;
4165 g_return_val_if_fail (iter != NULL, FALSE);
4167 real = gtk_text_iter_make_real (iter);
4172 check_invariants (iter);
4174 current_line = real->line;
4175 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4178 while (_gtk_text_iter_forward_indexable_segment (iter))
4180 /* If we went forward to a line that couldn't contain a toggle
4181 for the tag, then skip forward to a line that could contain
4182 it. This potentially skips huge hunks of the tree, so we
4183 aren't a purely linear search. */
4184 if (real->line != current_line)
4186 if (next_line == NULL)
4188 /* End of search. Set to end of buffer. */
4189 _gtk_text_btree_get_end_iter (real->tree, iter);
4193 if (real->line != next_line)
4194 iter_set_from_byte_offset (real, next_line, 0);
4196 current_line = real->line;
4197 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4202 if (gtk_text_iter_toggles_tag (iter, tag))
4204 /* If there's a toggle here, it isn't indexable so
4205 any_segment can't be the indexable segment. */
4206 g_assert (real->any_segment != real->segment);
4211 /* Check end iterator for tags */
4212 if (gtk_text_iter_toggles_tag (iter, tag))
4214 /* If there's a toggle here, it isn't indexable so
4215 any_segment can't be the indexable segment. */
4216 g_assert (real->any_segment != real->segment);
4220 /* Reached end of buffer */
4225 * gtk_text_iter_backward_to_tag_toggle:
4226 * @iter: a #GtkTextIter
4227 * @tag: a #GtkTextTag, or %NULL
4229 * Moves backward to the next toggle (on or off) of the
4230 * #GtkTextTag @tag, or to the next toggle of any tag if
4231 * @tag is %NULL. If no matching tag toggles are found,
4232 * returns %FALSE, otherwise %TRUE. Does not return toggles
4233 * located at @iter, only toggles before @iter. Sets @iter
4234 * to the location of the toggle, or the start of the buffer
4235 * if no toggle is found.
4237 * Return value: whether we found a tag toggle before @iter
4240 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4243 GtkTextLine *prev_line;
4244 GtkTextLine *current_line;
4245 GtkTextRealIter *real;
4247 g_return_val_if_fail (iter != NULL, FALSE);
4249 real = gtk_text_iter_make_real (iter);
4254 check_invariants (iter);
4256 current_line = real->line;
4257 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4261 /* If we're at segment start, go to the previous segment;
4262 * if mid-segment, snap to start of current segment.
4264 if (is_segment_start (real))
4266 if (!_gtk_text_iter_backward_indexable_segment (iter))
4271 ensure_char_offsets (real);
4273 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4279 /* If we went backward to a line that couldn't contain a toggle
4280 * for the tag, then skip backward further to a line that
4281 * could contain it. This potentially skips huge hunks of the
4282 * tree, so we aren't a purely linear search.
4284 if (real->line != current_line)
4286 if (prev_line == NULL)
4288 /* End of search. Set to start of buffer. */
4289 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4293 if (real->line != prev_line)
4295 /* Set to last segment in prev_line (could do this
4298 iter_set_from_byte_offset (real, prev_line, 0);
4300 while (!at_last_indexable_segment (real))
4301 _gtk_text_iter_forward_indexable_segment (iter);
4304 current_line = real->line;
4305 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4310 if (gtk_text_iter_toggles_tag (iter, tag))
4312 /* If there's a toggle here, it isn't indexable so
4313 * any_segment can't be the indexable segment.
4315 g_assert (real->any_segment != real->segment);
4319 while (_gtk_text_iter_backward_indexable_segment (iter));
4321 /* Reached front of buffer */
4326 matches_pred (GtkTextIter *iter,
4327 GtkTextCharPredicate pred,
4332 ch = gtk_text_iter_get_char (iter);
4334 return (*pred) (ch, user_data);
4338 * gtk_text_iter_forward_find_char:
4339 * @iter: a #GtkTextIter
4340 * @pred: a function to be called on each character
4341 * @user_data: user data for @pred
4342 * @limit: search limit, or %NULL for none
4344 * Advances @iter, calling @pred on each character. If
4345 * @pred returns %TRUE, returns %TRUE and stops scanning.
4346 * If @pred never returns %TRUE, @iter is set to @limit if
4347 * @limit is non-%NULL, otherwise to the end iterator.
4349 * Return value: whether a match was found
4352 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4353 GtkTextCharPredicate pred,
4355 const GtkTextIter *limit)
4357 g_return_val_if_fail (iter != NULL, FALSE);
4358 g_return_val_if_fail (pred != NULL, FALSE);
4361 gtk_text_iter_compare (iter, limit) >= 0)
4364 while ((limit == NULL ||
4365 !gtk_text_iter_equal (limit, iter)) &&
4366 gtk_text_iter_forward_char (iter))
4368 if (matches_pred (iter, pred, user_data))
4376 * gtk_text_iter_backward_find_char:
4377 * @iter: a #GtkTextIter
4378 * @pred: function to be called on each character
4379 * @user_data: user data for @pred
4380 * @limit: search limit, or %NULL for none
4382 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4384 * Return value: whether a match was found
4387 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4388 GtkTextCharPredicate pred,
4390 const GtkTextIter *limit)
4392 g_return_val_if_fail (iter != NULL, FALSE);
4393 g_return_val_if_fail (pred != NULL, FALSE);
4396 gtk_text_iter_compare (iter, limit) <= 0)
4399 while ((limit == NULL ||
4400 !gtk_text_iter_equal (limit, iter)) &&
4401 gtk_text_iter_backward_char (iter))
4403 if (matches_pred (iter, pred, user_data))
4411 forward_chars_with_skipping (GtkTextIter *iter,
4413 gboolean skip_invisible,
4414 gboolean skip_nontext)
4419 g_return_if_fail (count >= 0);
4425 gboolean ignored = FALSE;
4428 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4433 _gtk_text_btree_char_is_invisible (iter))
4436 gtk_text_iter_forward_char (iter);
4444 lines_match (const GtkTextIter *start,
4445 const gchar **lines,
4446 gboolean visible_only,
4448 GtkTextIter *match_start,
4449 GtkTextIter *match_end)
4456 if (*lines == NULL || **lines == '\0')
4459 *match_start = *start;
4462 *match_end = *start;
4467 gtk_text_iter_forward_line (&next);
4469 /* No more text in buffer, but *lines is nonempty */
4470 if (gtk_text_iter_equal (start, &next))
4478 line_text = gtk_text_iter_get_visible_slice (start, &next);
4480 line_text = gtk_text_iter_get_slice (start, &next);
4485 line_text = gtk_text_iter_get_visible_text (start, &next);
4487 line_text = gtk_text_iter_get_text (start, &next);
4490 if (match_start) /* if this is the first line we're matching */
4491 found = strstr (line_text, *lines);
4494 /* If it's not the first line, we have to match from the
4495 * start of the line.
4497 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4509 /* Get offset to start of search string */
4510 offset = g_utf8_strlen (line_text, found - line_text);
4514 /* If match start needs to be returned, set it to the
4515 * start of the search string.
4519 *match_start = next;
4521 forward_chars_with_skipping (match_start, offset,
4522 visible_only, !slice);
4525 /* Go to end of search string */
4526 offset += g_utf8_strlen (*lines, -1);
4528 forward_chars_with_skipping (&next, offset,
4529 visible_only, !slice);
4538 /* pass NULL for match_start, since we don't need to find the
4541 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4544 /* strsplit () that retains the delimiter as part of the string. */
4546 strbreakup (const char *string,
4547 const char *delimiter,
4550 GSList *string_list = NULL, *slist;
4551 gchar **str_array, *s;
4554 g_return_val_if_fail (string != NULL, NULL);
4555 g_return_val_if_fail (delimiter != NULL, NULL);
4558 max_tokens = G_MAXINT;
4560 s = strstr (string, delimiter);
4563 guint delimiter_len = strlen (delimiter);
4570 len = s - string + delimiter_len;
4571 new_string = g_new (gchar, len + 1);
4572 strncpy (new_string, string, len);
4573 new_string[len] = 0;
4574 string_list = g_slist_prepend (string_list, new_string);
4576 string = s + delimiter_len;
4577 s = strstr (string, delimiter);
4579 while (--max_tokens && s);
4584 string_list = g_slist_prepend (string_list, g_strdup (string));
4587 str_array = g_new (gchar*, n);
4591 str_array[i--] = NULL;
4592 for (slist = string_list; slist; slist = slist->next)
4593 str_array[i--] = slist->data;
4595 g_slist_free (string_list);
4601 * gtk_text_iter_forward_search:
4602 * @iter: start of search
4603 * @str: a search string
4604 * @flags: flags affecting how the search is done
4605 * @match_start: return location for start of match, or %NULL
4606 * @match_end: return location for end of match, or %NULL
4607 * @limit: bound for the search, or %NULL for the end of the buffer
4609 * Searches forward for @str. Any match is returned by setting
4610 * @match_start to the first character of the match and @match_end to the
4611 * first character after the match. The search will not continue past
4612 * @limit. Note that a search is a linear or O(n) operation, so you
4613 * may wish to use @limit to avoid locking up your UI on large
4616 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4617 * have invisible text interspersed in @str. i.e. @str will be a
4618 * possibly-noncontiguous subsequence of the matched range. similarly,
4619 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4620 * pixbufs or child widgets mixed inside the matched range. If these
4621 * flags are not given, the match must be exact; the special 0xFFFC
4622 * character in @str will match embedded pixbufs or child widgets.
4624 * Return value: whether a match was found
4627 gtk_text_iter_forward_search (const GtkTextIter *iter,
4629 GtkTextSearchFlags flags,
4630 GtkTextIter *match_start,
4631 GtkTextIter *match_end,
4632 const GtkTextIter *limit)
4634 gchar **lines = NULL;
4636 gboolean retval = FALSE;
4638 gboolean visible_only;
4641 g_return_val_if_fail (iter != NULL, FALSE);
4642 g_return_val_if_fail (str != NULL, FALSE);
4645 gtk_text_iter_compare (iter, limit) >= 0)
4650 /* If we can move one char, return the empty string there */
4653 if (gtk_text_iter_forward_char (&match))
4656 gtk_text_iter_equal (&match, limit))
4660 *match_start = match;
4669 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4670 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4672 /* locate all lines */
4674 lines = strbreakup (str, "\n", -1);
4680 /* This loop has an inefficient worst-case, where
4681 * gtk_text_iter_get_text () is called repeatedly on
4687 gtk_text_iter_compare (&search, limit) >= 0)
4690 if (lines_match (&search, (const gchar**)lines,
4691 visible_only, slice, &match, &end))
4693 if (limit == NULL ||
4695 gtk_text_iter_compare (&end, limit) <= 0))
4700 *match_start = match;
4709 while (gtk_text_iter_forward_line (&search));
4711 g_strfreev ((gchar**)lines);
4717 vectors_equal_ignoring_trailing (gchar **vec1,
4720 /* Ignores trailing chars in vec2's last line */
4729 if (strcmp (*i1, *i2) != 0)
4731 if (*(i2 + 1) == NULL) /* if this is the last line */
4733 gint len1 = strlen (*i1);
4734 gint len2 = strlen (*i2);
4737 strncmp (*i1, *i2, len1) == 0)
4739 /* We matched ignoring the trailing stuff in vec2 */
4764 typedef struct _LinesWindow LinesWindow;
4770 GtkTextIter first_line_start;
4771 GtkTextIter first_line_end;
4773 gboolean visible_only;
4777 lines_window_init (LinesWindow *win,
4778 const GtkTextIter *start)
4781 GtkTextIter line_start;
4782 GtkTextIter line_end;
4784 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4787 if (gtk_text_iter_is_start (start) ||
4788 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4790 /* Already at the end, or not enough lines to match */
4791 win->lines = g_new0 (gchar*, 1);
4796 line_start = *start;
4799 /* Move to start iter to start of line */
4800 gtk_text_iter_set_line_offset (&line_start, 0);
4802 if (gtk_text_iter_equal (&line_start, &line_end))
4804 /* we were already at the start; so go back one line */
4805 gtk_text_iter_backward_line (&line_start);
4808 win->first_line_start = line_start;
4809 win->first_line_end = line_end;
4811 win->lines = g_new0 (gchar*, win->n_lines + 1);
4813 i = win->n_lines - 1;
4820 if (win->visible_only)
4821 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4823 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4827 if (win->visible_only)
4828 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4830 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4833 win->lines[i] = line_text;
4835 line_end = line_start;
4836 gtk_text_iter_backward_line (&line_start);
4843 lines_window_back (LinesWindow *win)
4845 GtkTextIter new_start;
4848 new_start = win->first_line_start;
4850 if (!gtk_text_iter_backward_line (&new_start))
4854 win->first_line_start = new_start;
4855 win->first_line_end = new_start;
4857 gtk_text_iter_forward_line (&win->first_line_end);
4862 if (win->visible_only)
4863 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4864 &win->first_line_end);
4866 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4867 &win->first_line_end);
4871 if (win->visible_only)
4872 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4873 &win->first_line_end);
4875 line_text = gtk_text_iter_get_text (&win->first_line_start,
4876 &win->first_line_end);
4879 /* Move lines to make room for first line. */
4880 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4882 *win->lines = line_text;
4884 /* Free old last line and NULL-terminate */
4885 g_free (win->lines[win->n_lines]);
4886 win->lines[win->n_lines] = NULL;
4892 lines_window_free (LinesWindow *win)
4894 g_strfreev (win->lines);
4898 * gtk_text_iter_backward_search:
4899 * @iter: a #GtkTextIter where the search begins
4900 * @str: search string
4901 * @flags: bitmask of flags affecting the search
4902 * @match_start: return location for start of match, or %NULL
4903 * @match_end: return location for end of match, or %NULL
4904 * @limit: location of last possible @match_start, or %NULL for start of buffer
4906 * Same as gtk_text_iter_forward_search(), but moves backward.
4908 * Return value: whether a match was found
4911 gtk_text_iter_backward_search (const GtkTextIter *iter,
4913 GtkTextSearchFlags flags,
4914 GtkTextIter *match_start,
4915 GtkTextIter *match_end,
4916 const GtkTextIter *limit)
4918 gchar **lines = NULL;
4922 gboolean retval = FALSE;
4923 gboolean visible_only;
4926 g_return_val_if_fail (iter != NULL, FALSE);
4927 g_return_val_if_fail (str != NULL, FALSE);
4930 gtk_text_iter_compare (limit, iter) > 0)
4935 /* If we can move one char, return the empty string there */
4936 GtkTextIter match = *iter;
4938 if (limit && gtk_text_iter_equal (limit, &match))
4941 if (gtk_text_iter_backward_char (&match))
4944 *match_start = match;
4953 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4954 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4956 /* locate all lines */
4958 lines = strbreakup (str, "\n", -1);
4968 win.n_lines = n_lines;
4970 win.visible_only = visible_only;
4972 lines_window_init (&win, iter);
4974 if (*win.lines == NULL)
4979 gchar *first_line_match;
4982 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4984 /* We're now before the search limit, abort. */
4988 /* If there are multiple lines, the first line will
4989 * end in '\n', so this will only match at the
4990 * end of the first line, which is correct.
4992 first_line_match = g_strrstr (*win.lines, *lines);
4994 if (first_line_match &&
4995 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
5000 GtkTextIter start_tmp;
5002 /* Offset to start of search string */
5003 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
5005 next = win.first_line_start;
5007 forward_chars_with_skipping (&start_tmp, offset,
5008 visible_only, !slice);
5011 gtk_text_iter_compare (limit, &start_tmp) > 0)
5012 goto out; /* match was bogus */
5015 *match_start = start_tmp;
5017 /* Go to end of search string */
5021 offset += g_utf8_strlen (*l, -1);
5025 forward_chars_with_skipping (&next, offset,
5026 visible_only, !slice);
5035 while (lines_window_back (&win));
5038 lines_window_free (&win);
5049 * gtk_text_iter_equal:
5050 * @lhs: a #GtkTextIter
5051 * @rhs: another #GtkTextIter
5053 * Tests whether two iterators are equal, using the fastest possible
5054 * mechanism. This function is very fast; you can expect it to perform
5055 * better than e.g. getting the character offset for each iterator and
5056 * comparing the offsets yourself. Also, it's a bit faster than
5057 * gtk_text_iter_compare().
5059 * Return value: %TRUE if the iterators point to the same place in the buffer
5062 gtk_text_iter_equal (const GtkTextIter *lhs,
5063 const GtkTextIter *rhs)
5065 GtkTextRealIter *real_lhs;
5066 GtkTextRealIter *real_rhs;
5068 real_lhs = (GtkTextRealIter*)lhs;
5069 real_rhs = (GtkTextRealIter*)rhs;
5071 check_invariants (lhs);
5072 check_invariants (rhs);
5074 if (real_lhs->line != real_rhs->line)
5076 else if (real_lhs->line_byte_offset >= 0 &&
5077 real_rhs->line_byte_offset >= 0)
5078 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5081 /* the ensure_char_offsets () calls do nothing if the char offsets
5082 are already up-to-date. */
5083 ensure_char_offsets (real_lhs);
5084 ensure_char_offsets (real_rhs);
5085 return real_lhs->line_char_offset == real_rhs->line_char_offset;
5090 * gtk_text_iter_compare:
5091 * @lhs: a #GtkTextIter
5092 * @rhs: another #GtkTextIter
5094 * A qsort()-style function that returns negative if @lhs is less than
5095 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5096 * Ordering is in character offset order, i.e. the first character in the buffer
5097 * is less than the second character in the buffer.
5099 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5102 gtk_text_iter_compare (const GtkTextIter *lhs,
5103 const GtkTextIter *rhs)
5105 GtkTextRealIter *real_lhs;
5106 GtkTextRealIter *real_rhs;
5108 real_lhs = gtk_text_iter_make_surreal (lhs);
5109 real_rhs = gtk_text_iter_make_surreal (rhs);
5111 if (real_lhs == NULL ||
5113 return -1; /* why not */
5115 check_invariants (lhs);
5116 check_invariants (rhs);
5118 if (real_lhs->line == real_rhs->line)
5120 gint left_index, right_index;
5122 if (real_lhs->line_byte_offset >= 0 &&
5123 real_rhs->line_byte_offset >= 0)
5125 left_index = real_lhs->line_byte_offset;
5126 right_index = real_rhs->line_byte_offset;
5130 /* the ensure_char_offsets () calls do nothing if
5131 the offsets are already up-to-date. */
5132 ensure_char_offsets (real_lhs);
5133 ensure_char_offsets (real_rhs);
5134 left_index = real_lhs->line_char_offset;
5135 right_index = real_rhs->line_char_offset;
5138 if (left_index < right_index)
5140 else if (left_index > right_index)
5149 line1 = gtk_text_iter_get_line (lhs);
5150 line2 = gtk_text_iter_get_line (rhs);
5153 else if (line1 > line2)
5161 * gtk_text_iter_in_range:
5162 * @iter: a #GtkTextIter
5163 * @start: start of range
5164 * @end: end of range
5166 * Checks whether @iter falls in the range [@start, @end).
5167 * @start and @end must be in ascending order.
5169 * Return value: %TRUE if @iter is in the range
5172 gtk_text_iter_in_range (const GtkTextIter *iter,
5173 const GtkTextIter *start,
5174 const GtkTextIter *end)
5176 g_return_val_if_fail (iter != NULL, FALSE);
5177 g_return_val_if_fail (start != NULL, FALSE);
5178 g_return_val_if_fail (end != NULL, FALSE);
5179 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5181 return gtk_text_iter_compare (iter, start) >= 0 &&
5182 gtk_text_iter_compare (iter, end) < 0;
5186 * gtk_text_iter_order:
5187 * @first: a #GtkTextIter
5188 * @second: another #GtkTextIter
5190 * Swaps the value of @first and @second if @second comes before
5191 * @first in the buffer. That is, ensures that @first and @second are
5192 * in sequence. Most text buffer functions that take a range call this
5193 * automatically on your behalf, so there's no real reason to call it yourself
5194 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5195 * that expect a pre-sorted range.
5199 gtk_text_iter_order (GtkTextIter *first,
5200 GtkTextIter *second)
5202 g_return_if_fail (first != NULL);
5203 g_return_if_fail (second != NULL);
5205 if (gtk_text_iter_compare (first, second) > 0)
5216 * Init iterators from the BTree
5220 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5224 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5225 gint real_char_index;
5229 g_return_if_fail (iter != NULL);
5230 g_return_if_fail (tree != NULL);
5232 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5233 &line_start, &real_char_index);
5235 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5237 real->cached_char_index = real_char_index;
5239 check_invariants (iter);
5243 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5248 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5252 g_return_if_fail (iter != NULL);
5253 g_return_if_fail (tree != NULL);
5255 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5257 iter_init_from_char_offset (iter, tree, line, char_on_line);
5259 /* We might as well cache this, since we know it. */
5260 real->cached_line_number = real_line;
5262 check_invariants (iter);
5266 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5271 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5275 g_return_if_fail (iter != NULL);
5276 g_return_if_fail (tree != NULL);
5278 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5280 iter_init_from_byte_offset (iter, tree, line, byte_index);
5282 /* We might as well cache this, since we know it. */
5283 real->cached_line_number = real_line;
5285 check_invariants (iter);
5289 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5294 g_return_if_fail (iter != NULL);
5295 g_return_if_fail (tree != NULL);
5296 g_return_if_fail (line != NULL);
5298 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5300 check_invariants (iter);
5304 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5310 g_return_val_if_fail (iter != NULL, FALSE);
5311 g_return_val_if_fail (tree != NULL, FALSE);
5313 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5317 /* Set iter to last in tree */
5318 _gtk_text_btree_get_end_iter (tree, iter);
5319 check_invariants (iter);
5324 iter_init_from_byte_offset (iter, tree, line, 0);
5326 if (!gtk_text_iter_toggles_tag (iter, tag))
5327 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5329 check_invariants (iter);
5335 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5339 g_return_val_if_fail (iter != NULL, FALSE);
5340 g_return_val_if_fail (tree != NULL, FALSE);
5342 _gtk_text_btree_get_end_iter (tree, iter);
5343 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5344 check_invariants (iter);
5350 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5352 const gchar *mark_name)
5356 g_return_val_if_fail (iter != NULL, FALSE);
5357 g_return_val_if_fail (tree != NULL, FALSE);
5359 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5365 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5366 check_invariants (iter);
5372 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5376 GtkTextLineSegment *seg;
5378 g_return_if_fail (iter != NULL);
5379 g_return_if_fail (tree != NULL);
5380 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5382 seg = mark->segment;
5384 iter_init_from_segment (iter, tree,
5385 seg->body.mark.line, seg);
5386 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5387 check_invariants (iter);
5391 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5393 GtkTextChildAnchor *anchor)
5395 GtkTextLineSegment *seg;
5397 g_return_if_fail (iter != NULL);
5398 g_return_if_fail (tree != NULL);
5399 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5401 seg = anchor->segment;
5403 g_assert (seg->body.child.line != NULL);
5405 iter_init_from_segment (iter, tree,
5406 seg->body.child.line, seg);
5407 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5408 check_invariants (iter);
5412 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5415 g_return_if_fail (iter != NULL);
5416 g_return_if_fail (tree != NULL);
5418 _gtk_text_btree_get_iter_at_char (tree,
5420 _gtk_text_btree_char_count (tree));
5421 check_invariants (iter);
5425 _gtk_text_iter_check (const GtkTextIter *iter)
5427 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5428 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5429 GtkTextLineSegment *byte_segment = NULL;
5430 GtkTextLineSegment *byte_any_segment = NULL;
5431 GtkTextLineSegment *char_segment = NULL;
5432 GtkTextLineSegment *char_any_segment = NULL;
5433 gboolean segments_updated;
5435 /* This function checks our class invariants for the Iter class. */
5437 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5439 if (real->chars_changed_stamp !=
5440 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5441 g_error ("iterator check failed: invalid iterator");
5443 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5444 g_error ("iterator check failed: both char and byte offsets are invalid");
5446 segments_updated = (real->segments_changed_stamp ==
5447 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5450 printf ("checking iter, segments %s updated, byte %d char %d\n",
5451 segments_updated ? "are" : "aren't",
5452 real->line_byte_offset,
5453 real->line_char_offset);
5456 if (segments_updated)
5458 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5459 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5461 if (real->segment->char_count == 0)
5462 g_error ("iterator check failed: segment is not indexable.");
5464 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5465 g_error ("segment char offset is not properly up-to-date");
5467 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5468 g_error ("segment byte offset is not properly up-to-date");
5470 if (real->segment_byte_offset >= 0 &&
5471 real->segment_byte_offset >= real->segment->byte_count)
5472 g_error ("segment byte offset is too large.");
5474 if (real->segment_char_offset >= 0 &&
5475 real->segment_char_offset >= real->segment->char_count)
5476 g_error ("segment char offset is too large.");
5479 if (real->line_byte_offset >= 0)
5481 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5482 &byte_segment, &byte_any_segment,
5483 &seg_byte_offset, &line_byte_offset);
5485 if (line_byte_offset != real->line_byte_offset)
5486 g_error ("wrong byte offset was stored in iterator");
5488 if (segments_updated)
5490 if (real->segment != byte_segment)
5491 g_error ("wrong segment was stored in iterator");
5493 if (real->any_segment != byte_any_segment)
5494 g_error ("wrong any_segment was stored in iterator");
5496 if (seg_byte_offset != real->segment_byte_offset)
5497 g_error ("wrong segment byte offset was stored in iterator");
5499 if (byte_segment->type == >k_text_char_type)
5502 p = byte_segment->body.chars + seg_byte_offset;
5504 if (!gtk_text_byte_begins_utf8_char (p))
5505 g_error ("broken iterator byte index pointed into the middle of a character");
5510 if (real->line_char_offset >= 0)
5512 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5513 &char_segment, &char_any_segment,
5514 &seg_char_offset, &line_char_offset);
5516 if (line_char_offset != real->line_char_offset)
5517 g_error ("wrong char offset was stored in iterator");
5519 if (segments_updated)
5521 if (real->segment != char_segment)
5522 g_error ("wrong segment was stored in iterator");
5524 if (real->any_segment != char_any_segment)
5525 g_error ("wrong any_segment was stored in iterator");
5527 if (seg_char_offset != real->segment_char_offset)
5528 g_error ("wrong segment char offset was stored in iterator");
5530 if (char_segment->type == >k_text_char_type)
5533 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5536 /* hmm, not likely to happen eh */
5537 if (!gtk_text_byte_begins_utf8_char (p))
5538 g_error ("broken iterator char offset pointed into the middle of a character");
5543 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5545 if (byte_segment != char_segment)
5546 g_error ("char and byte offsets did not point to the same segment");
5548 if (byte_any_segment != char_any_segment)
5549 g_error ("char and byte offsets did not point to the same any segment");
5551 /* Make sure the segment offsets are equivalent, if it's a char
5553 if (char_segment->type == >k_text_char_type)
5555 gint byte_offset = 0;
5556 gint char_offset = 0;
5557 while (char_offset < seg_char_offset)
5559 const char * start = char_segment->body.chars + byte_offset;
5560 byte_offset += g_utf8_next_char (start) - start;
5564 if (byte_offset != seg_byte_offset)
5565 g_error ("byte offset did not correspond to char offset");
5568 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5570 if (char_offset != seg_char_offset)
5571 g_error ("char offset did not correspond to byte offset");
5573 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5574 g_error ("byte index for iterator does not index the start of a character");
5578 if (real->cached_line_number >= 0)
5582 should_be = _gtk_text_line_get_number (real->line);
5583 if (real->cached_line_number != should_be)
5584 g_error ("wrong line number was cached");
5587 if (real->cached_char_index >= 0)
5589 if (real->line_char_offset >= 0) /* only way we can check it
5590 efficiently, not a real
5595 char_index = _gtk_text_line_char_index (real->line);
5596 char_index += real->line_char_offset;
5598 if (real->cached_char_index != char_index)
5599 g_error ("wrong char index was cached");
5603 if (_gtk_text_line_is_last (real->line, real->tree))
5604 g_error ("Iterator was on last line (past the end iterator)");
5607 #define __GTK_TEXT_ITER_C__
5608 #include "gtkaliasdef.c"