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;
390 #ifdef G_ENABLE_DEBUG
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 GtkTextIter tmp = *iter;
1569 /* need to determine if a \r precedes the \n, in which case
1570 * we aren't the end of the line.
1571 * Note however that if \r and \n are on different lines, they
1572 * both are terminators. This for instance may happen after
1573 * deleting some text:
1575 1 some text\r delete 'a' 1 some text\r
1576 2 a\n ---------> 2 \n
1581 if (gtk_text_iter_get_line_offset (&tmp) == 0)
1584 if (!gtk_text_iter_backward_char (&tmp))
1587 return gtk_text_iter_get_char (&tmp) != '\r';
1594 * gtk_text_iter_is_end:
1595 * @iter: an iterator
1597 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1598 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1599 * the most efficient way to check whether an iterator is the end
1602 * Return value: whether @iter is the end iterator
1605 gtk_text_iter_is_end (const GtkTextIter *iter)
1607 GtkTextRealIter *real;
1609 g_return_val_if_fail (iter != NULL, FALSE);
1611 real = gtk_text_iter_make_surreal (iter);
1616 check_invariants (iter);
1618 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1621 /* Now we need the segments validated */
1622 real = gtk_text_iter_make_real (iter);
1627 return _gtk_text_btree_is_end (real->tree, real->line,
1629 real->segment_byte_offset,
1630 real->segment_char_offset);
1634 * gtk_text_iter_is_start:
1635 * @iter: an iterator
1637 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1638 * if @iter has a character offset of 0.
1640 * Return value: whether @iter is the first in the buffer
1643 gtk_text_iter_is_start (const GtkTextIter *iter)
1645 return gtk_text_iter_get_offset (iter) == 0;
1649 * gtk_text_iter_get_chars_in_line:
1650 * @iter: an iterator
1652 * Returns the number of characters in the line containing @iter,
1653 * including the paragraph delimiters.
1655 * Return value: number of characters in the line
1658 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1660 GtkTextRealIter *real;
1662 GtkTextLineSegment *seg;
1664 g_return_val_if_fail (iter != NULL, 0);
1666 real = gtk_text_iter_make_surreal (iter);
1671 check_invariants (iter);
1673 if (real->line_char_offset >= 0)
1675 /* We can start at the segments we've already found. */
1676 count = real->line_char_offset - real->segment_char_offset;
1677 seg = _gtk_text_iter_get_indexable_segment (iter);
1681 /* count whole line. */
1682 seg = real->line->segments;
1689 count += seg->char_count;
1694 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1695 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1701 * gtk_text_iter_get_bytes_in_line:
1702 * @iter: an iterator
1704 * Returns the number of bytes in the line containing @iter,
1705 * including the paragraph delimiters.
1707 * Return value: number of bytes in the line
1710 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1712 GtkTextRealIter *real;
1714 GtkTextLineSegment *seg;
1716 g_return_val_if_fail (iter != NULL, 0);
1718 real = gtk_text_iter_make_surreal (iter);
1723 check_invariants (iter);
1725 if (real->line_byte_offset >= 0)
1727 /* We can start at the segments we've already found. */
1728 count = real->line_byte_offset - real->segment_byte_offset;
1729 seg = _gtk_text_iter_get_indexable_segment (iter);
1733 /* count whole line. */
1734 seg = real->line->segments;
1740 count += seg->byte_count;
1745 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1746 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1752 * gtk_text_iter_get_attributes:
1753 * @iter: an iterator
1754 * @values: a #GtkTextAttributes to be filled in
1756 * Computes the effect of any tags applied to this spot in the
1757 * text. The @values parameter should be initialized to the default
1758 * settings you wish to use if no tags are in effect. You'd typically
1759 * obtain the defaults from gtk_text_view_get_default_attributes().
1761 * gtk_text_iter_get_attributes () will modify @values, applying the
1762 * effects of any tags present at @iter. If any tags affected @values,
1763 * the function returns %TRUE.
1765 * Return value: %TRUE if @values was modified
1768 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1769 GtkTextAttributes *values)
1774 /* Get the tags at this spot */
1775 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1777 /* No tags, use default style */
1778 if (tags == NULL || tag_count == 0)
1786 /* Sort tags in ascending order of priority */
1787 _gtk_text_tag_array_sort (tags, tag_count);
1789 _gtk_text_attributes_fill_from_tags (values,
1799 * Increments/decrements
1802 /* The return value of this indicates WHETHER WE MOVED.
1803 * The return value of public functions indicates
1804 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1806 * This function will not change the iterator if
1807 * it's already on the last (end iter) line, i.e. it
1808 * won't move to the end of the last line.
1811 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1813 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1815 GtkTextLine *new_line;
1817 new_line = _gtk_text_line_next (real->line);
1818 g_assert (new_line);
1819 g_assert (new_line != real->line);
1820 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1822 real->line = new_line;
1824 real->line_byte_offset = 0;
1825 real->line_char_offset = 0;
1827 real->segment_byte_offset = 0;
1828 real->segment_char_offset = 0;
1830 /* Find first segments in new line */
1831 real->any_segment = real->line->segments;
1832 real->segment = real->any_segment;
1833 while (real->segment->char_count == 0)
1834 real->segment = real->segment->next;
1840 /* There is no way to move forward a line; we were already at
1841 * the line containing the end iterator.
1842 * However we may not be at the end iterator itself.
1850 /* The return value of this indicates WHETHER WE MOVED.
1851 * The return value of public functions indicates
1852 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1854 * This function is currently unused, thus it is #if-0-ed. It is
1855 * left here, since it's non-trivial code that might be useful in
1859 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1861 GtkTextLine *new_line;
1863 new_line = _gtk_text_line_previous (real->line);
1865 g_assert (new_line != real->line);
1867 if (new_line != NULL)
1869 real->line = new_line;
1871 real->line_byte_offset = 0;
1872 real->line_char_offset = 0;
1874 real->segment_byte_offset = 0;
1875 real->segment_char_offset = 0;
1877 /* Find first segments in new line */
1878 real->any_segment = real->line->segments;
1879 real->segment = real->any_segment;
1880 while (real->segment->char_count == 0)
1881 real->segment = real->segment->next;
1887 /* There is no way to move backward; we were already
1888 at the first line. */
1890 /* We leave real->line as-is */
1892 /* Note that we didn't clamp to the start of the first line. */
1899 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1903 forward_char (GtkTextRealIter *real)
1905 GtkTextIter *iter = (GtkTextIter*)real;
1907 check_invariants ((GtkTextIter*)real);
1909 ensure_char_offsets (real);
1911 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1913 /* Need to move to the next segment; if no next segment,
1914 need to move to next line. */
1915 return _gtk_text_iter_forward_indexable_segment (iter);
1919 /* Just moving within a segment. Keep byte count
1920 up-to-date, if it was already up-to-date. */
1922 g_assert (real->segment->type == >k_text_char_type);
1924 if (real->line_byte_offset >= 0)
1927 const char * start =
1928 real->segment->body.chars + real->segment_byte_offset;
1930 bytes = g_utf8_next_char (start) - start;
1932 real->line_byte_offset += bytes;
1933 real->segment_byte_offset += bytes;
1935 g_assert (real->segment_byte_offset < real->segment->byte_count);
1938 real->line_char_offset += 1;
1939 real->segment_char_offset += 1;
1941 adjust_char_index (real, 1);
1943 g_assert (real->segment_char_offset < real->segment->char_count);
1945 /* We moved into the middle of a segment, so the any_segment
1946 must now be the segment we're in the middle of. */
1947 real->any_segment = real->segment;
1949 check_invariants ((GtkTextIter*)real);
1951 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1959 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1961 /* Need to move to the next segment; if no next segment,
1962 need to move to next line. */
1963 GtkTextLineSegment *seg;
1964 GtkTextLineSegment *any_seg;
1965 GtkTextRealIter *real;
1969 g_return_val_if_fail (iter != NULL, FALSE);
1971 real = gtk_text_iter_make_real (iter);
1976 check_invariants (iter);
1978 if (real->line_char_offset >= 0)
1980 chars_skipped = real->segment->char_count - real->segment_char_offset;
1981 g_assert (chars_skipped > 0);
1986 if (real->line_byte_offset >= 0)
1988 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1989 g_assert (bytes_skipped > 0);
1994 /* Get first segment of any kind */
1995 any_seg = real->segment->next;
1996 /* skip non-indexable segments, if any */
1998 while (seg != NULL && seg->char_count == 0)
2003 real->any_segment = any_seg;
2004 real->segment = seg;
2006 if (real->line_byte_offset >= 0)
2008 g_assert (bytes_skipped > 0);
2009 real->segment_byte_offset = 0;
2010 real->line_byte_offset += bytes_skipped;
2013 if (real->line_char_offset >= 0)
2015 g_assert (chars_skipped > 0);
2016 real->segment_char_offset = 0;
2017 real->line_char_offset += chars_skipped;
2018 adjust_char_index (real, chars_skipped);
2021 check_invariants (iter);
2023 return !gtk_text_iter_is_end (iter);
2027 /* End of the line */
2028 if (forward_line_leaving_caches_unmodified (real))
2030 adjust_line_number (real, 1);
2031 if (real->line_char_offset >= 0)
2032 adjust_char_index (real, chars_skipped);
2034 g_assert (real->line_byte_offset == 0);
2035 g_assert (real->line_char_offset == 0);
2036 g_assert (real->segment_byte_offset == 0);
2037 g_assert (real->segment_char_offset == 0);
2038 g_assert (gtk_text_iter_starts_line (iter));
2040 check_invariants (iter);
2042 return !gtk_text_iter_is_end (iter);
2046 /* End of buffer, but iter is still at start of last segment,
2047 * not at the end iterator. We put it on the end iterator.
2050 check_invariants (iter);
2052 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2053 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2055 gtk_text_iter_forward_to_line_end (iter);
2057 g_assert (gtk_text_iter_is_end (iter));
2065 at_last_indexable_segment (GtkTextRealIter *real)
2067 GtkTextLineSegment *seg;
2069 /* Return TRUE if there are no indexable segments after
2073 seg = real->segment->next;
2076 if (seg->char_count > 0)
2083 /* Goes back to the start of the next segment, even if
2084 * we're not at the start of the current segment (always
2085 * ends up on a different segment if it returns TRUE)
2088 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2090 /* Move to the start of the previous segment; if no previous
2091 * segment, to the last segment in the previous line. This is
2092 * inherently a bit inefficient due to the singly-linked list and
2093 * tree nodes, but we can't afford the RAM for doubly-linked.
2095 GtkTextRealIter *real;
2096 GtkTextLineSegment *seg;
2097 GtkTextLineSegment *any_seg;
2098 GtkTextLineSegment *prev_seg;
2099 GtkTextLineSegment *prev_any_seg;
2103 g_return_val_if_fail (iter != NULL, FALSE);
2105 real = gtk_text_iter_make_real (iter);
2110 check_invariants (iter);
2112 /* Find first segments in line */
2113 any_seg = real->line->segments;
2115 while (seg->char_count == 0)
2118 if (seg == real->segment)
2120 /* Could probably do this case faster by hand-coding the
2124 /* We were already at the start of a line;
2125 * go back to the previous line.
2127 if (gtk_text_iter_backward_line (iter))
2129 /* Go forward to last indexable segment in line. */
2130 while (!at_last_indexable_segment (real))
2131 _gtk_text_iter_forward_indexable_segment (iter);
2133 check_invariants (iter);
2138 return FALSE; /* We were at the start of the first line. */
2141 /* We must be in the middle of a line; so find the indexable
2142 * segment just before our current segment.
2144 g_assert (seg != real->segment);
2148 prev_any_seg = any_seg;
2150 any_seg = seg->next;
2152 while (seg->char_count == 0)
2155 while (seg != real->segment);
2157 g_assert (prev_seg != NULL);
2158 g_assert (prev_any_seg != NULL);
2159 g_assert (prev_seg->char_count > 0);
2161 /* We skipped the entire previous segment, plus any
2162 * chars we were into the current segment.
2164 if (real->segment_byte_offset >= 0)
2165 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2169 if (real->segment_char_offset >= 0)
2170 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2174 real->segment = prev_seg;
2175 real->any_segment = prev_any_seg;
2176 real->segment_byte_offset = 0;
2177 real->segment_char_offset = 0;
2179 if (bytes_skipped >= 0)
2181 if (real->line_byte_offset >= 0)
2183 real->line_byte_offset -= bytes_skipped;
2184 g_assert (real->line_byte_offset >= 0);
2188 real->line_byte_offset = -1;
2190 if (chars_skipped >= 0)
2192 if (real->line_char_offset >= 0)
2194 real->line_char_offset -= chars_skipped;
2195 g_assert (real->line_char_offset >= 0);
2198 if (real->cached_char_index >= 0)
2200 real->cached_char_index -= chars_skipped;
2201 g_assert (real->cached_char_index >= 0);
2206 real->line_char_offset = -1;
2207 real->cached_char_index = -1;
2210 /* line number is unchanged. */
2212 check_invariants (iter);
2218 * gtk_text_iter_forward_char:
2219 * @iter: an iterator
2221 * Moves @iter forward by one character offset. Note that images
2222 * embedded in the buffer occupy 1 character slot, so
2223 * gtk_text_iter_forward_char () may actually move onto an image instead
2224 * of a character, if you have images in your buffer. If @iter is the
2225 * end iterator or one character before it, @iter will now point at
2226 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2227 * convenience when writing loops.
2229 * Return value: whether @iter moved and is dereferenceable
2232 gtk_text_iter_forward_char (GtkTextIter *iter)
2234 GtkTextRealIter *real;
2236 g_return_val_if_fail (iter != NULL, FALSE);
2238 real = gtk_text_iter_make_real (iter);
2244 check_invariants (iter);
2245 return forward_char (real);
2250 * gtk_text_iter_backward_char:
2251 * @iter: an iterator
2253 * Moves backward by one character offset. Returns %TRUE if movement
2254 * was possible; if @iter was the first in the buffer (character
2255 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2258 * Return value: whether movement was possible
2261 gtk_text_iter_backward_char (GtkTextIter *iter)
2263 g_return_val_if_fail (iter != NULL, FALSE);
2265 check_invariants (iter);
2267 return gtk_text_iter_backward_chars (iter, 1);
2271 Definitely we should try to linear scan as often as possible for
2272 movement within a single line, because we can't use the BTree to
2273 speed within-line searches up; for movement between lines, we would
2274 like to avoid the linear scan probably.
2276 Instead of using this constant, it might be nice to cache the line
2277 length in the iterator and linear scan if motion is within a single
2280 I guess you'd have to profile the various approaches.
2282 #define MAX_LINEAR_SCAN 150
2286 * gtk_text_iter_forward_chars:
2287 * @iter: an iterator
2288 * @count: number of characters to move, may be negative
2290 * Moves @count characters if possible (if @count would move past the
2291 * start or end of the buffer, moves to the start or end of the
2292 * buffer). The return value indicates whether the new position of
2293 * @iter is different from its original position, and dereferenceable
2294 * (the last iterator in the buffer is not dereferenceable). If @count
2295 * is 0, the function does nothing and returns %FALSE.
2297 * Return value: whether @iter moved and is dereferenceable
2300 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2302 GtkTextRealIter *real;
2304 g_return_val_if_fail (iter != NULL, FALSE);
2306 FIX_OVERFLOWS (count);
2308 real = gtk_text_iter_make_real (iter);
2312 else if (count == 0)
2315 return gtk_text_iter_backward_chars (iter, 0 - count);
2316 else if (count < MAX_LINEAR_SCAN)
2318 check_invariants (iter);
2322 if (!forward_char (real))
2327 return forward_char (real);
2331 gint current_char_index;
2332 gint new_char_index;
2334 check_invariants (iter);
2336 current_char_index = gtk_text_iter_get_offset (iter);
2338 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2339 return FALSE; /* can't move forward */
2341 new_char_index = current_char_index + count;
2342 gtk_text_iter_set_offset (iter, new_char_index);
2344 check_invariants (iter);
2346 /* Return FALSE if we're on the non-dereferenceable end
2349 if (gtk_text_iter_is_end (iter))
2357 * gtk_text_iter_backward_chars:
2358 * @iter: an iterator
2359 * @count: number of characters to move
2361 * Moves @count characters backward, if possible (if @count would move
2362 * past the start or end of the buffer, moves to the start or end of
2363 * the buffer). The return value indicates whether the iterator moved
2364 * onto a dereferenceable position; if the iterator didn't move, or
2365 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2366 * the function does nothing and returns %FALSE.
2368 * Return value: whether @iter moved and is dereferenceable
2372 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2374 GtkTextRealIter *real;
2376 g_return_val_if_fail (iter != NULL, FALSE);
2378 FIX_OVERFLOWS (count);
2380 real = gtk_text_iter_make_real (iter);
2384 else if (count == 0)
2387 return gtk_text_iter_forward_chars (iter, 0 - count);
2389 ensure_char_offsets (real);
2390 check_invariants (iter);
2392 /* <, not <=, because if count == segment_char_offset
2393 * we're going to the front of the segment and the any_segment
2396 if (count < real->segment_char_offset)
2398 /* Optimize the within-segment case */
2399 g_assert (real->segment->char_count > 0);
2400 g_assert (real->segment->type == >k_text_char_type);
2402 if (real->line_byte_offset >= 0)
2405 gint new_byte_offset;
2407 /* if in the last fourth of the segment walk backwards */
2408 if (count < real->segment_char_offset / 4)
2409 p = g_utf8_offset_to_pointer (real->segment->body.chars + real->segment_byte_offset,
2412 p = g_utf8_offset_to_pointer (real->segment->body.chars,
2413 real->segment_char_offset - count);
2415 new_byte_offset = p - real->segment->body.chars;
2416 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2417 real->segment_byte_offset = new_byte_offset;
2420 real->segment_char_offset -= count;
2421 real->line_char_offset -= count;
2423 adjust_char_index (real, 0 - count);
2425 check_invariants (iter);
2431 /* We need to go back into previous segments. For now,
2432 * just keep this really simple. FIXME
2433 * use backward_indexable_segment.
2435 if (TRUE || count > MAX_LINEAR_SCAN)
2437 gint current_char_index;
2438 gint new_char_index;
2440 current_char_index = gtk_text_iter_get_offset (iter);
2442 if (current_char_index == 0)
2443 return FALSE; /* can't move backward */
2445 new_char_index = current_char_index - count;
2446 if (new_char_index < 0)
2449 gtk_text_iter_set_offset (iter, new_char_index);
2451 check_invariants (iter);
2457 /* FIXME backward_indexable_segment here */
2466 /* These two can't be implemented efficiently (always have to use
2467 * a linear scan, since that's the only way to find all the non-text
2472 * gtk_text_iter_forward_text_chars:
2473 * @iter: a #GtkTextIter
2474 * @count: number of chars to move
2476 * Moves forward by @count text characters (pixbufs, widgets,
2477 * etc. do not count as characters for this). Equivalent to moving
2478 * through the results of gtk_text_iter_get_text (), rather than
2479 * gtk_text_iter_get_slice ().
2481 * Return value: whether @iter moved and is dereferenceable
2484 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2493 * gtk_text_iter_forward_text_chars:
2494 * @iter: a #GtkTextIter
2495 * @count: number of chars to move
2497 * Moves backward by @count text characters (pixbufs, widgets,
2498 * etc. do not count as characters for this). Equivalent to moving
2499 * through the results of gtk_text_iter_get_text (), rather than
2500 * gtk_text_iter_get_slice ().
2502 * Return value: whether @iter moved and is dereferenceable
2505 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2514 * gtk_text_iter_forward_line:
2515 * @iter: an iterator
2517 * Moves @iter to the start of the next line. Returns %TRUE if there
2518 * was a next line to move to, and %FALSE if @iter was simply moved to
2519 * the end of the buffer and is now not dereferenceable, or if @iter was
2520 * already at the end of the buffer.
2522 * Return value: whether @iter can be dereferenced
2525 gtk_text_iter_forward_line (GtkTextIter *iter)
2527 GtkTextRealIter *real;
2529 g_return_val_if_fail (iter != NULL, FALSE);
2531 real = gtk_text_iter_make_real (iter);
2536 check_invariants (iter);
2538 if (forward_line_leaving_caches_unmodified (real))
2540 invalidate_char_index (real);
2541 adjust_line_number (real, 1);
2543 check_invariants (iter);
2545 if (gtk_text_iter_is_end (iter))
2552 /* On the last line, move to end of it */
2554 if (!gtk_text_iter_is_end (iter))
2555 gtk_text_iter_forward_to_end (iter);
2557 check_invariants (iter);
2563 * gtk_text_iter_backward_line:
2564 * @iter: an iterator
2566 * Moves @iter to the start of the previous line. Returns %TRUE if
2567 * @iter could be moved; i.e. if @iter was at character offset 0, this
2568 * function returns %FALSE. Therefore if @iter was already on line 0,
2569 * but not at the start of the line, @iter is snapped to the start of
2570 * the line and the function returns %TRUE. (Note that this implies that
2571 * in a loop calling this function, the line number may not change on
2572 * every iteration, if your first iteration is on line 0.)
2574 * Return value: whether @iter moved
2577 gtk_text_iter_backward_line (GtkTextIter *iter)
2579 GtkTextLine *new_line;
2580 GtkTextRealIter *real;
2581 gboolean offset_will_change;
2584 g_return_val_if_fail (iter != NULL, FALSE);
2586 real = gtk_text_iter_make_real (iter);
2591 check_invariants (iter);
2593 new_line = _gtk_text_line_previous (real->line);
2595 offset_will_change = FALSE;
2596 if (real->line_char_offset > 0)
2597 offset_will_change = TRUE;
2599 if (new_line != NULL)
2601 real->line = new_line;
2603 adjust_line_number (real, -1);
2607 if (!offset_will_change)
2611 invalidate_char_index (real);
2613 real->line_byte_offset = 0;
2614 real->line_char_offset = 0;
2616 real->segment_byte_offset = 0;
2617 real->segment_char_offset = 0;
2619 /* Find first segment in line */
2620 real->any_segment = real->line->segments;
2621 real->segment = _gtk_text_line_byte_to_segment (real->line,
2624 g_assert (offset == 0);
2626 /* Note that if we are on the first line, we snap to the start of
2627 * the first line and return TRUE, so TRUE means the iterator
2628 * changed, not that the line changed; this is maybe a bit
2629 * weird. I'm not sure there's an obvious right thing to do though.
2632 check_invariants (iter);
2639 * gtk_text_iter_forward_lines:
2640 * @iter: a #GtkTextIter
2641 * @count: number of lines to move forward
2643 * Moves @count lines forward, if possible (if @count would move
2644 * past the start or end of the buffer, moves to the start or end of
2645 * the buffer). The return value indicates whether the iterator moved
2646 * onto a dereferenceable position; if the iterator didn't move, or
2647 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2648 * the function does nothing and returns %FALSE. If @count is negative,
2649 * moves backward by 0 - @count lines.
2651 * Return value: whether @iter moved and is dereferenceable
2654 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2656 FIX_OVERFLOWS (count);
2659 return gtk_text_iter_backward_lines (iter, 0 - count);
2660 else if (count == 0)
2662 else if (count == 1)
2664 check_invariants (iter);
2665 return gtk_text_iter_forward_line (iter);
2671 if (gtk_text_iter_is_end (iter))
2674 old_line = gtk_text_iter_get_line (iter);
2676 gtk_text_iter_set_line (iter, old_line + count);
2678 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2680 /* count went past the last line, so move to end of last line */
2681 if (!gtk_text_iter_is_end (iter))
2682 gtk_text_iter_forward_to_end (iter);
2685 return !gtk_text_iter_is_end (iter);
2690 * gtk_text_iter_backward_lines:
2691 * @iter: a #GtkTextIter
2692 * @count: number of lines to move backward
2694 * Moves @count lines backward, if possible (if @count would move
2695 * past the start or end of the buffer, moves to the start or end of
2696 * the buffer). The return value indicates whether the iterator moved
2697 * onto a dereferenceable position; if the iterator didn't move, or
2698 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2699 * the function does nothing and returns %FALSE. If @count is negative,
2700 * moves forward by 0 - @count lines.
2702 * Return value: whether @iter moved and is dereferenceable
2705 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2707 FIX_OVERFLOWS (count);
2710 return gtk_text_iter_forward_lines (iter, 0 - count);
2711 else if (count == 0)
2713 else if (count == 1)
2715 return gtk_text_iter_backward_line (iter);
2721 old_line = gtk_text_iter_get_line (iter);
2723 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2725 return (gtk_text_iter_get_line (iter) != old_line);
2730 * gtk_text_iter_forward_visible_line:
2731 * @iter: an iterator
2733 * Moves @iter to the start of the next visible line. Returns %TRUE if there
2734 * was a next line to move to, and %FALSE if @iter was simply moved to
2735 * the end of the buffer and is now not dereferenceable, or if @iter was
2736 * already at the end of the buffer.
2738 * Return value: whether @iter can be dereferenced
2743 gtk_text_iter_forward_visible_line (GtkTextIter *iter)
2745 while (gtk_text_iter_forward_line (iter))
2747 if (!_gtk_text_btree_char_is_invisible (iter))
2753 if (!gtk_text_iter_forward_char (iter))
2756 if (!_gtk_text_btree_char_is_invisible (iter))
2759 while (!gtk_text_iter_ends_line (iter));
2767 * gtk_text_iter_backward_visible_line:
2768 * @iter: an iterator
2770 * Moves @iter to the start of the previous visible line. Returns %TRUE if
2771 * @iter could be moved; i.e. if @iter was at character offset 0, this
2772 * function returns %FALSE. Therefore if @iter was already on line 0,
2773 * but not at the start of the line, @iter is snapped to the start of
2774 * the line and the function returns %TRUE. (Note that this implies that
2775 * in a loop calling this function, the line number may not change on
2776 * every iteration, if your first iteration is on line 0.)
2778 * Return value: whether @iter moved
2783 gtk_text_iter_backward_visible_line (GtkTextIter *iter)
2785 while (gtk_text_iter_backward_line (iter))
2787 if (!_gtk_text_btree_char_is_invisible (iter))
2793 if (!gtk_text_iter_backward_char (iter))
2796 if (!_gtk_text_btree_char_is_invisible (iter))
2799 while (!gtk_text_iter_starts_line (iter));
2807 * gtk_text_iter_forward_visible_lines:
2808 * @iter: a #GtkTextIter
2809 * @count: number of lines to move forward
2811 * Moves @count visible lines forward, if possible (if @count would move
2812 * past the start or end of the buffer, moves to the start or end of
2813 * the buffer). The return value indicates whether the iterator moved
2814 * onto a dereferenceable position; if the iterator didn't move, or
2815 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2816 * the function does nothing and returns %FALSE. If @count is negative,
2817 * moves backward by 0 - @count lines.
2819 * Return value: whether @iter moved and is dereferenceable
2824 gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
2827 FIX_OVERFLOWS (count);
2830 return gtk_text_iter_backward_visible_lines (iter, 0 - count);
2831 else if (count == 0)
2833 else if (count == 1)
2835 check_invariants (iter);
2836 return gtk_text_iter_forward_visible_line (iter);
2840 while (gtk_text_iter_forward_visible_line (iter) && count > 0)
2847 * gtk_text_iter_backward_visible_lines:
2848 * @iter: a #GtkTextIter
2849 * @count: number of lines to move backward
2851 * Moves @count visible lines backward, if possible (if @count would move
2852 * past the start or end of the buffer, moves to the start or end of
2853 * the buffer). The return value indicates whether the iterator moved
2854 * onto a dereferenceable position; if the iterator didn't move, or
2855 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2856 * the function does nothing and returns %FALSE. If @count is negative,
2857 * moves forward by 0 - @count lines.
2859 * Return value: whether @iter moved and is dereferenceable
2864 gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
2867 FIX_OVERFLOWS (count);
2870 return gtk_text_iter_forward_visible_lines (iter, 0 - count);
2871 else if (count == 0)
2873 else if (count == 1)
2875 return gtk_text_iter_backward_visible_line (iter);
2879 while (gtk_text_iter_backward_visible_line (iter) && count > 0)
2885 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2890 gboolean already_moved_initially);
2892 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2900 find_word_end_func (const PangoLogAttr *attrs,
2905 gboolean already_moved_initially)
2907 if (!already_moved_initially)
2910 /* Find end of next word */
2911 while (offset < min_offset + len &&
2912 !attrs[offset].is_word_end)
2915 *found_offset = offset;
2917 return offset < min_offset + len;
2921 is_word_end_func (const PangoLogAttr *attrs,
2926 return attrs[offset].is_word_end;
2930 find_word_start_func (const PangoLogAttr *attrs,
2935 gboolean already_moved_initially)
2937 if (!already_moved_initially)
2940 /* Find start of prev word */
2941 while (offset >= min_offset &&
2942 !attrs[offset].is_word_start)
2945 *found_offset = offset;
2947 return offset >= min_offset;
2951 is_word_start_func (const PangoLogAttr *attrs,
2956 return attrs[offset].is_word_start;
2960 inside_word_func (const PangoLogAttr *attrs,
2965 /* Find next word start or end */
2966 while (offset >= min_offset &&
2967 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2971 return attrs[offset].is_word_start;
2976 /* Sentence funcs */
2979 find_sentence_end_func (const PangoLogAttr *attrs,
2984 gboolean already_moved_initially)
2986 if (!already_moved_initially)
2989 /* Find end of next sentence */
2990 while (offset < min_offset + len &&
2991 !attrs[offset].is_sentence_end)
2994 *found_offset = offset;
2996 return offset < min_offset + len;
3000 is_sentence_end_func (const PangoLogAttr *attrs,
3005 return attrs[offset].is_sentence_end;
3009 find_sentence_start_func (const PangoLogAttr *attrs,
3014 gboolean already_moved_initially)
3016 if (!already_moved_initially)
3019 /* Find start of prev sentence */
3020 while (offset >= min_offset &&
3021 !attrs[offset].is_sentence_start)
3024 *found_offset = offset;
3026 return offset >= min_offset;
3030 is_sentence_start_func (const PangoLogAttr *attrs,
3035 return attrs[offset].is_sentence_start;
3039 inside_sentence_func (const PangoLogAttr *attrs,
3044 /* Find next sentence start or end */
3045 while (offset >= min_offset &&
3046 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
3049 return attrs[offset].is_sentence_start;
3053 test_log_attrs (const GtkTextIter *iter,
3054 TestLogAttrFunc func)
3057 const PangoLogAttr *attrs;
3059 gboolean result = FALSE;
3061 g_return_val_if_fail (iter != NULL, FALSE);
3063 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3066 offset = gtk_text_iter_get_line_offset (iter);
3068 /* char_len may be 0 and attrs will be NULL if so, if
3069 * iter is the end iter and the last line is empty.
3071 * offset may be equal to char_len, since attrs contains an entry
3072 * for one past the end
3075 if (attrs && offset <= char_len)
3076 result = (* func) (attrs, offset, 0, char_len);
3082 find_line_log_attrs (const GtkTextIter *iter,
3083 FindLogAttrFunc func,
3085 gboolean already_moved_initially)
3088 const PangoLogAttr *attrs;
3090 gboolean result = FALSE;
3092 g_return_val_if_fail (iter != NULL, FALSE);
3094 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3097 offset = gtk_text_iter_get_line_offset (iter);
3099 /* char_len may be 0 and attrs will be NULL if so, if
3100 * iter is the end iter and the last line is empty
3104 result = (* func) (attrs, offset, 0, char_len, found_offset,
3105 already_moved_initially);
3110 /* FIXME this function is very, very gratuitously slow */
3112 find_by_log_attrs (GtkTextIter *iter,
3113 FindLogAttrFunc func,
3115 gboolean already_moved_initially)
3119 gboolean found = FALSE;
3121 g_return_val_if_fail (iter != NULL, FALSE);
3125 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
3131 if (gtk_text_iter_forward_line (iter))
3132 return find_by_log_attrs (iter, func, forward,
3139 /* go to end of previous line. need to check that
3140 * line is > 0 because backward_line snaps to start of
3141 * line 0 if it's on line 0
3143 if (gtk_text_iter_get_line (iter) > 0 &&
3144 gtk_text_iter_backward_line (iter))
3146 if (!gtk_text_iter_ends_line (iter))
3147 gtk_text_iter_forward_to_line_end (iter);
3149 return find_by_log_attrs (iter, func, forward,
3158 gtk_text_iter_set_line_offset (iter, offset);
3161 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
3162 !gtk_text_iter_is_end (iter);
3167 find_visible_by_log_attrs (GtkTextIter *iter,
3168 FindLogAttrFunc func,
3170 gboolean already_moved_initially)
3174 g_return_val_if_fail (iter != NULL, FALSE);
3178 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3180 if (!_gtk_text_btree_char_is_invisible (&pos))
3190 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3191 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3194 move_multiple_steps (GtkTextIter *iter,
3196 OneStepFunc step_forward,
3197 MultipleStepFunc n_steps_backward)
3199 g_return_val_if_fail (iter != NULL, FALSE);
3201 FIX_OVERFLOWS (count);
3207 return n_steps_backward (iter, -count);
3209 if (!step_forward (iter))
3215 if (!step_forward (iter))
3220 return !gtk_text_iter_is_end (iter);
3225 * gtk_text_iter_forward_word_end:
3226 * @iter: a #GtkTextIter
3228 * Moves forward to the next word end. (If @iter is currently on a
3229 * word end, moves forward to the next one after that.) Word breaks
3230 * are determined by Pango and should be correct for nearly any
3231 * language (if not, the correct fix would be to the Pango word break
3234 * Return value: %TRUE if @iter moved and is not the end iterator
3237 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3239 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3243 * gtk_text_iter_backward_word_start:
3244 * @iter: a #GtkTextIter
3246 * Moves backward to the previous word start. (If @iter is currently on a
3247 * word start, moves backward to the next one after that.) Word breaks
3248 * are determined by Pango and should be correct for nearly any
3249 * language (if not, the correct fix would be to the Pango word break
3252 * Return value: %TRUE if @iter moved and is not the end iterator
3255 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3257 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3260 /* FIXME a loop around a truly slow function means
3261 * a truly spectacularly slow function.
3265 * gtk_text_iter_forward_word_ends:
3266 * @iter: a #GtkTextIter
3267 * @count: number of times to move
3269 * Calls gtk_text_iter_forward_word_end() up to @count times.
3271 * Return value: %TRUE if @iter moved and is not the end iterator
3274 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3277 return move_multiple_steps (iter, count,
3278 gtk_text_iter_forward_word_end,
3279 gtk_text_iter_backward_word_starts);
3283 * gtk_text_iter_backward_word_starts
3284 * @iter: a #GtkTextIter
3285 * @count: number of times to move
3287 * Calls gtk_text_iter_backward_word_start() up to @count times.
3289 * Return value: %TRUE if @iter moved and is not the end iterator
3292 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3295 return move_multiple_steps (iter, count,
3296 gtk_text_iter_backward_word_start,
3297 gtk_text_iter_forward_word_ends);
3301 * gtk_text_iter_forward_visible_word_end:
3302 * @iter: a #GtkTextIter
3304 * Moves forward to the next visible word end. (If @iter is currently on a
3305 * word end, moves forward to the next one after that.) Word breaks
3306 * are determined by Pango and should be correct for nearly any
3307 * language (if not, the correct fix would be to the Pango word break
3310 * Return value: %TRUE if @iter moved and is not the end iterator
3315 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3317 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3321 * gtk_text_iter_backward_visible_word_start:
3322 * @iter: a #GtkTextIter
3324 * Moves backward to the previous visible word start. (If @iter is currently
3325 * on a word start, moves backward to the next one after that.) Word breaks
3326 * are determined by Pango and should be correct for nearly any
3327 * language (if not, the correct fix would be to the Pango word break
3330 * Return value: %TRUE if @iter moved and is not the end iterator
3335 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3337 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3341 * gtk_text_iter_forward_visible_word_ends:
3342 * @iter: a #GtkTextIter
3343 * @count: number of times to move
3345 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3347 * Return value: %TRUE if @iter moved and is not the end iterator
3352 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3355 return move_multiple_steps (iter, count,
3356 gtk_text_iter_forward_visible_word_end,
3357 gtk_text_iter_backward_visible_word_starts);
3361 * gtk_text_iter_backward_visible_word_starts
3362 * @iter: a #GtkTextIter
3363 * @count: number of times to move
3365 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3367 * Return value: %TRUE if @iter moved and is not the end iterator
3372 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3375 return move_multiple_steps (iter, count,
3376 gtk_text_iter_backward_visible_word_start,
3377 gtk_text_iter_forward_visible_word_ends);
3381 * gtk_text_iter_starts_word:
3382 * @iter: a #GtkTextIter
3384 * Determines whether @iter begins a natural-language word. Word
3385 * breaks are determined by Pango and should be correct for nearly any
3386 * language (if not, the correct fix would be to the Pango word break
3389 * Return value: %TRUE if @iter is at the start of a word
3392 gtk_text_iter_starts_word (const GtkTextIter *iter)
3394 return test_log_attrs (iter, is_word_start_func);
3398 * gtk_text_iter_ends_word:
3399 * @iter: a #GtkTextIter
3401 * Determines whether @iter ends a natural-language word. Word breaks
3402 * are determined by Pango and should be correct for nearly any
3403 * language (if not, the correct fix would be to the Pango word break
3406 * Return value: %TRUE if @iter is at the end of a word
3409 gtk_text_iter_ends_word (const GtkTextIter *iter)
3411 return test_log_attrs (iter, is_word_end_func);
3415 * gtk_text_iter_inside_word:
3416 * @iter: a #GtkTextIter
3418 * Determines whether @iter is inside a natural-language word (as
3419 * opposed to say inside some whitespace). Word breaks are determined
3420 * by Pango and should be correct for nearly any language (if not, the
3421 * correct fix would be to the Pango word break algorithms).
3423 * Return value: %TRUE if @iter is inside a word
3426 gtk_text_iter_inside_word (const GtkTextIter *iter)
3428 return test_log_attrs (iter, inside_word_func);
3432 * gtk_text_iter_starts_sentence:
3433 * @iter: a #GtkTextIter
3435 * Determines whether @iter begins a sentence. Sentence boundaries are
3436 * determined by Pango and should be correct for nearly any language
3437 * (if not, the correct fix would be to the Pango text boundary
3440 * Return value: %TRUE if @iter is at the start of a sentence.
3443 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3445 return test_log_attrs (iter, is_sentence_start_func);
3449 * gtk_text_iter_ends_sentence:
3450 * @iter: a #GtkTextIter
3452 * Determines whether @iter ends a sentence. Sentence boundaries are
3453 * determined by Pango and should be correct for nearly any language
3454 * (if not, the correct fix would be to the Pango text boundary
3457 * Return value: %TRUE if @iter is at the end of a sentence.
3460 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3462 return test_log_attrs (iter, is_sentence_end_func);
3466 * gtk_text_iter_inside_sentence:
3467 * @iter: a #GtkTextIter
3469 * Determines whether @iter is inside a sentence (as opposed to in
3470 * between two sentences, e.g. after a period and before the first
3471 * letter of the next sentence). Sentence boundaries are determined
3472 * by Pango and should be correct for nearly any language (if not, the
3473 * correct fix would be to the Pango text boundary algorithms).
3475 * Return value: %TRUE if @iter is inside a sentence.
3478 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3480 return test_log_attrs (iter, inside_sentence_func);
3484 * gtk_text_iter_forward_sentence_end:
3485 * @iter: a #GtkTextIter
3487 * Moves forward to the next sentence end. (If @iter is at the end of
3488 * a sentence, moves to the next end of sentence.) Sentence
3489 * boundaries are determined by Pango and should be correct for nearly
3490 * any language (if not, the correct fix would be to the Pango text
3491 * boundary algorithms).
3493 * Return value: %TRUE if @iter moved and is not the end iterator
3496 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3498 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3502 * gtk_text_iter_backward_sentence_start:
3503 * @iter: a #GtkTextIter
3505 * Moves backward to the previous sentence start; if @iter is already at
3506 * the start of a sentence, moves backward to the next one. Sentence
3507 * boundaries are determined by Pango and should be correct for nearly
3508 * any language (if not, the correct fix would be to the Pango text
3509 * boundary algorithms).
3511 * Return value: %TRUE if @iter moved and is not the end iterator
3514 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3516 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3519 /* FIXME a loop around a truly slow function means
3520 * a truly spectacularly slow function.
3523 * gtk_text_iter_forward_sentence_ends:
3524 * @iter: a #GtkTextIter
3525 * @count: number of sentences to move
3527 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3528 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3529 * negative, moves backward instead of forward.
3531 * Return value: %TRUE if @iter moved and is not the end iterator
3534 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3537 return move_multiple_steps (iter, count,
3538 gtk_text_iter_forward_sentence_end,
3539 gtk_text_iter_backward_sentence_starts);
3543 * gtk_text_iter_backward_sentence_starts:
3544 * @iter: a #GtkTextIter
3545 * @count: number of sentences to move
3547 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3548 * or until it returns %FALSE. If @count is negative, moves forward
3549 * instead of backward.
3551 * Return value: %TRUE if @iter moved and is not the end iterator
3554 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3557 return move_multiple_steps (iter, count,
3558 gtk_text_iter_backward_sentence_start,
3559 gtk_text_iter_forward_sentence_ends);
3563 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3568 gboolean already_moved_initially)
3570 if (!already_moved_initially)
3573 while (offset < (min_offset + len) &&
3574 !attrs[offset].is_cursor_position)
3577 *found_offset = offset;
3579 return offset < (min_offset + len);
3583 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3588 gboolean already_moved_initially)
3590 if (!already_moved_initially)
3593 while (offset > min_offset &&
3594 !attrs[offset].is_cursor_position)
3597 *found_offset = offset;
3599 return offset >= min_offset;
3603 is_cursor_pos_func (const PangoLogAttr *attrs,
3608 return attrs[offset].is_cursor_position;
3612 * gtk_text_iter_forward_cursor_position:
3613 * @iter: a #GtkTextIter
3615 * Moves @iter forward by a single cursor position. Cursor positions
3616 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3617 * surprisingly, there may not be a cursor position between all
3618 * characters. The most common example for European languages would be
3619 * a carriage return/newline sequence. For some Unicode characters,
3620 * the equivalent of say the letter "a" with an accent mark will be
3621 * represented as two characters, first the letter then a "combining
3622 * mark" that causes the accent to be rendered; so the cursor can't go
3623 * between those two characters. See also the #PangoLogAttr structure and
3624 * pango_break() function.
3626 * Return value: %TRUE if we moved and the new position is dereferenceable
3629 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3631 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3635 * gtk_text_iter_backward_cursor_position:
3636 * @iter: a #GtkTextIter
3638 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3640 * Return value: %TRUE if we moved
3643 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3645 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3649 * gtk_text_iter_forward_cursor_positions:
3650 * @iter: a #GtkTextIter
3651 * @count: number of positions to move
3653 * Moves up to @count cursor positions. See
3654 * gtk_text_iter_forward_cursor_position() for details.
3656 * Return value: %TRUE if we moved and the new position is dereferenceable
3659 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3662 return move_multiple_steps (iter, count,
3663 gtk_text_iter_forward_cursor_position,
3664 gtk_text_iter_backward_cursor_positions);
3668 * gtk_text_iter_backward_cursor_positions:
3669 * @iter: a #GtkTextIter
3670 * @count: number of positions to move
3672 * Moves up to @count cursor positions. See
3673 * gtk_text_iter_forward_cursor_position() for details.
3675 * Return value: %TRUE if we moved and the new position is dereferenceable
3678 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3681 return move_multiple_steps (iter, count,
3682 gtk_text_iter_backward_cursor_position,
3683 gtk_text_iter_forward_cursor_positions);
3687 * gtk_text_iter_forward_visible_cursor_position:
3688 * @iter: a #GtkTextIter
3690 * Moves @iter forward to the next visible cursor position. See
3691 * gtk_text_iter_forward_cursor_position() for details.
3693 * Return value: %TRUE if we moved and the new position is dereferenceable
3698 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3700 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3704 * gtk_text_iter_backward_visible_cursor_position:
3705 * @iter: a #GtkTextIter
3707 * Moves @iter forward to the previous visible cursor position. See
3708 * gtk_text_iter_backward_cursor_position() for details.
3710 * Return value: %TRUE if we moved and the new position is dereferenceable
3715 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3717 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3721 * gtk_text_iter_forward_visible_cursor_positions:
3722 * @iter: a #GtkTextIter
3723 * @count: number of positions to move
3725 * Moves up to @count visible cursor positions. See
3726 * gtk_text_iter_forward_cursor_position() for details.
3728 * Return value: %TRUE if we moved and the new position is dereferenceable
3733 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3736 return move_multiple_steps (iter, count,
3737 gtk_text_iter_forward_visible_cursor_position,
3738 gtk_text_iter_backward_visible_cursor_positions);
3742 * gtk_text_iter_backward_visible_cursor_positions:
3743 * @iter: a #GtkTextIter
3744 * @count: number of positions to move
3746 * Moves up to @count visible cursor positions. See
3747 * gtk_text_iter_backward_cursor_position() for details.
3749 * Return value: %TRUE if we moved and the new position is dereferenceable
3754 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3757 return move_multiple_steps (iter, count,
3758 gtk_text_iter_backward_visible_cursor_position,
3759 gtk_text_iter_forward_visible_cursor_positions);
3763 * gtk_text_iter_is_cursor_position:
3764 * @iter: a #GtkTextIter
3766 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3767 * pango_break() for details on what a cursor position is.
3769 * Return value: %TRUE if the cursor can be placed at @iter
3772 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3774 return test_log_attrs (iter, is_cursor_pos_func);
3778 * gtk_text_iter_set_line_offset:
3779 * @iter: a #GtkTextIter
3780 * @char_on_line: a character offset relative to the start of @iter's current line
3782 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3783 * (not byte) offset. The given character offset must be less than or
3784 * equal to the number of characters in the line; if equal, @iter
3785 * moves to the start of the next line. See
3786 * gtk_text_iter_set_line_index() if you have a byte index rather than
3787 * a character offset.
3791 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3794 GtkTextRealIter *real;
3797 g_return_if_fail (iter != NULL);
3799 real = gtk_text_iter_make_surreal (iter);
3804 check_invariants (iter);
3806 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3808 g_return_if_fail (char_on_line <= chars_in_line);
3810 if (char_on_line < chars_in_line)
3811 iter_set_from_char_offset (real, real->line, char_on_line);
3813 gtk_text_iter_forward_line (iter); /* set to start of next line */
3815 check_invariants (iter);
3819 * gtk_text_iter_set_line_index:
3820 * @iter: a #GtkTextIter
3821 * @byte_on_line: a byte index relative to the start of @iter's current line
3823 * Same as gtk_text_iter_set_line_offset(), but works with a
3824 * <emphasis>byte</emphasis> index. The given byte index must be at
3825 * the start of a character, it can't be in the middle of a UTF-8
3826 * encoded character.
3830 gtk_text_iter_set_line_index (GtkTextIter *iter,
3833 GtkTextRealIter *real;
3836 g_return_if_fail (iter != NULL);
3838 real = gtk_text_iter_make_surreal (iter);
3843 check_invariants (iter);
3845 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3847 g_return_if_fail (byte_on_line <= bytes_in_line);
3849 if (byte_on_line < bytes_in_line)
3850 iter_set_from_byte_offset (real, real->line, byte_on_line);
3852 gtk_text_iter_forward_line (iter);
3854 if (real->segment->type == >k_text_char_type &&
3855 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3856 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3857 "character; this will crash the text buffer. "
3858 "Byte indexes must refer to the start of a character.",
3859 G_STRLOC, byte_on_line);
3861 check_invariants (iter);
3866 * gtk_text_iter_set_visible_line_offset:
3867 * @iter: a #GtkTextIter
3868 * @char_on_line: a character offset
3870 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3871 * characters, i.e. text with a tag making it invisible is not
3872 * counted in the offset.
3875 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3878 gint chars_seen = 0;
3881 g_return_if_fail (iter != NULL);
3883 gtk_text_iter_set_line_offset (iter, 0);
3887 /* For now we use a ludicrously slow implementation */
3888 while (chars_seen < char_on_line)
3890 if (!_gtk_text_btree_char_is_invisible (&pos))
3893 if (!gtk_text_iter_forward_char (&pos))
3896 if (chars_seen == char_on_line)
3900 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3903 gtk_text_iter_forward_line (iter);
3907 * gtk_text_iter_set_visible_line_index:
3908 * @iter: a #GtkTextIter
3909 * @byte_on_line: a byte index
3911 * Like gtk_text_iter_set_line_index(), but the index is in visible
3912 * bytes, i.e. text with a tag making it invisible is not counted
3916 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3919 GtkTextRealIter *real;
3920 gint bytes_in_line = 0;
3923 GtkTextLineSegment *seg;
3925 g_return_if_fail (iter != NULL);
3927 gtk_text_iter_set_line_offset (iter, 0);
3929 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3933 real = gtk_text_iter_make_real (&pos);
3938 ensure_byte_offsets (real);
3940 check_invariants (&pos);
3942 seg = _gtk_text_iter_get_indexable_segment (&pos);
3944 while (seg != NULL && byte_on_line > 0)
3946 if (!_gtk_text_btree_char_is_invisible (&pos))
3948 if (byte_on_line < seg->byte_count)
3950 iter_set_from_byte_offset (real, real->line, offset + byte_on_line);
3955 byte_on_line -= seg->byte_count;
3958 offset += seg->byte_count;
3959 _gtk_text_iter_forward_indexable_segment (&pos);
3960 seg = _gtk_text_iter_get_indexable_segment (&pos);
3963 if (byte_on_line == 0)
3966 gtk_text_iter_forward_line (iter);
3970 * gtk_text_iter_set_line:
3971 * @iter: a #GtkTextIter
3972 * @line_number: line number (counted from 0)
3974 * Moves iterator @iter to the start of the line @line_number. If
3975 * @line_number is negative or larger than the number of lines in the
3976 * buffer, moves @iter to the start of the last line in the buffer.
3980 gtk_text_iter_set_line (GtkTextIter *iter,
3985 GtkTextRealIter *real;
3987 g_return_if_fail (iter != NULL);
3989 real = gtk_text_iter_make_surreal (iter);
3994 check_invariants (iter);
3996 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3998 iter_set_from_char_offset (real, line, 0);
4000 /* We might as well cache this, since we know it. */
4001 real->cached_line_number = real_line;
4003 check_invariants (iter);
4007 * gtk_text_iter_set_offset:
4008 * @iter: a #GtkTextIter
4009 * @char_offset: a character number
4011 * Sets @iter to point to @char_offset. @char_offset counts from the start
4012 * of the entire text buffer, starting with 0.
4015 gtk_text_iter_set_offset (GtkTextIter *iter,
4019 GtkTextRealIter *real;
4021 gint real_char_index;
4023 g_return_if_fail (iter != NULL);
4025 real = gtk_text_iter_make_surreal (iter);
4030 check_invariants (iter);
4032 if (real->cached_char_index >= 0 &&
4033 real->cached_char_index == char_offset)
4036 line = _gtk_text_btree_get_line_at_char (real->tree,
4041 iter_set_from_char_offset (real, line, real_char_index - line_start);
4043 /* Go ahead and cache this since we have it. */
4044 real->cached_char_index = real_char_index;
4046 check_invariants (iter);
4050 * gtk_text_iter_forward_to_end:
4051 * @iter: a #GtkTextIter
4053 * Moves @iter forward to the "end iterator," which points one past the last
4054 * valid character in the buffer. gtk_text_iter_get_char() called on the
4055 * end iterator returns 0, which is convenient for writing loops.
4058 gtk_text_iter_forward_to_end (GtkTextIter *iter)
4060 GtkTextBuffer *buffer;
4061 GtkTextRealIter *real;
4063 g_return_if_fail (iter != NULL);
4065 real = gtk_text_iter_make_surreal (iter);
4070 buffer = _gtk_text_btree_get_buffer (real->tree);
4072 gtk_text_buffer_get_end_iter (buffer, iter);
4075 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
4076 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
4077 * If all else fails we could cache the para delimiter pos in the iter.
4078 * I think forward_to_line_end() actually gets called fairly often.
4081 find_paragraph_delimiter_for_line (GtkTextIter *iter)
4086 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
4087 _gtk_text_iter_get_btree (&end)))
4089 gtk_text_iter_forward_to_end (&end);
4093 /* if we aren't on the last line, go forward to start of next line, then scan
4094 * back for the delimiters on the previous line
4096 gtk_text_iter_forward_line (&end);
4097 gtk_text_iter_backward_char (&end);
4098 while (!gtk_text_iter_ends_line (&end))
4099 gtk_text_iter_backward_char (&end);
4102 return gtk_text_iter_get_line_offset (&end);
4106 * gtk_text_iter_forward_to_line_end:
4107 * @iter: a #GtkTextIter
4109 * Moves the iterator to point to the paragraph delimiter characters,
4110 * which will be either a newline, a carriage return, a carriage
4111 * return/newline in sequence, or the Unicode paragraph separator
4112 * character. If the iterator is already at the paragraph delimiter
4113 * characters, moves to the paragraph delimiter characters for the
4114 * next line. If @iter is on the last line in the buffer, which does
4115 * not end in paragraph delimiters, moves to the end iterator (end of
4116 * the last line), and returns %FALSE.
4118 * Return value: %TRUE if we moved and the new location is not the end iterator
4121 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
4123 gint current_offset;
4127 g_return_val_if_fail (iter != NULL, FALSE);
4129 current_offset = gtk_text_iter_get_line_offset (iter);
4130 new_offset = find_paragraph_delimiter_for_line (iter);
4132 if (current_offset < new_offset)
4134 /* Move to end of this line. */
4135 gtk_text_iter_set_line_offset (iter, new_offset);
4136 return !gtk_text_iter_is_end (iter);
4140 /* Move to end of next line. */
4141 if (gtk_text_iter_forward_line (iter))
4143 /* We don't want to move past all
4146 if (!gtk_text_iter_ends_line (iter))
4147 gtk_text_iter_forward_to_line_end (iter);
4148 return !gtk_text_iter_is_end (iter);
4156 * gtk_text_iter_forward_to_tag_toggle:
4157 * @iter: a #GtkTextIter
4158 * @tag: a #GtkTextTag, or %NULL
4160 * Moves forward to the next toggle (on or off) of the
4161 * #GtkTextTag @tag, or to the next toggle of any tag if
4162 * @tag is %NULL. If no matching tag toggles are found,
4163 * returns %FALSE, otherwise %TRUE. Does not return toggles
4164 * located at @iter, only toggles after @iter. Sets @iter to
4165 * the location of the toggle, or to the end of the buffer
4166 * if no toggle is found.
4168 * Return value: whether we found a tag toggle after @iter
4171 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4174 GtkTextLine *next_line;
4175 GtkTextLine *current_line;
4176 GtkTextRealIter *real;
4178 g_return_val_if_fail (iter != NULL, FALSE);
4180 real = gtk_text_iter_make_real (iter);
4185 check_invariants (iter);
4187 current_line = real->line;
4188 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4191 while (_gtk_text_iter_forward_indexable_segment (iter))
4193 /* If we went forward to a line that couldn't contain a toggle
4194 for the tag, then skip forward to a line that could contain
4195 it. This potentially skips huge hunks of the tree, so we
4196 aren't a purely linear search. */
4197 if (real->line != current_line)
4199 if (next_line == NULL)
4201 /* End of search. Set to end of buffer. */
4202 _gtk_text_btree_get_end_iter (real->tree, iter);
4206 if (real->line != next_line)
4207 iter_set_from_byte_offset (real, next_line, 0);
4209 current_line = real->line;
4210 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4215 if (gtk_text_iter_toggles_tag (iter, tag))
4217 /* If there's a toggle here, it isn't indexable so
4218 any_segment can't be the indexable segment. */
4219 g_assert (real->any_segment != real->segment);
4224 /* Check end iterator for tags */
4225 if (gtk_text_iter_toggles_tag (iter, tag))
4227 /* If there's a toggle here, it isn't indexable so
4228 any_segment can't be the indexable segment. */
4229 g_assert (real->any_segment != real->segment);
4233 /* Reached end of buffer */
4238 * gtk_text_iter_backward_to_tag_toggle:
4239 * @iter: a #GtkTextIter
4240 * @tag: a #GtkTextTag, or %NULL
4242 * Moves backward to the next toggle (on or off) of the
4243 * #GtkTextTag @tag, or to the next toggle of any tag if
4244 * @tag is %NULL. If no matching tag toggles are found,
4245 * returns %FALSE, otherwise %TRUE. Does not return toggles
4246 * located at @iter, only toggles before @iter. Sets @iter
4247 * to the location of the toggle, or the start of the buffer
4248 * if no toggle is found.
4250 * Return value: whether we found a tag toggle before @iter
4253 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4256 GtkTextLine *prev_line;
4257 GtkTextLine *current_line;
4258 GtkTextRealIter *real;
4260 g_return_val_if_fail (iter != NULL, FALSE);
4262 real = gtk_text_iter_make_real (iter);
4267 check_invariants (iter);
4269 current_line = real->line;
4270 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4274 /* If we're at segment start, go to the previous segment;
4275 * if mid-segment, snap to start of current segment.
4277 if (is_segment_start (real))
4279 if (!_gtk_text_iter_backward_indexable_segment (iter))
4284 ensure_char_offsets (real);
4286 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4292 /* If we went backward to a line that couldn't contain a toggle
4293 * for the tag, then skip backward further to a line that
4294 * could contain it. This potentially skips huge hunks of the
4295 * tree, so we aren't a purely linear search.
4297 if (real->line != current_line)
4299 if (prev_line == NULL)
4301 /* End of search. Set to start of buffer. */
4302 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4306 if (real->line != prev_line)
4308 /* Set to last segment in prev_line (could do this
4311 iter_set_from_byte_offset (real, prev_line, 0);
4313 while (!at_last_indexable_segment (real))
4314 _gtk_text_iter_forward_indexable_segment (iter);
4317 current_line = real->line;
4318 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4323 if (gtk_text_iter_toggles_tag (iter, tag))
4325 /* If there's a toggle here, it isn't indexable so
4326 * any_segment can't be the indexable segment.
4328 g_assert (real->any_segment != real->segment);
4332 while (_gtk_text_iter_backward_indexable_segment (iter));
4334 /* Reached front of buffer */
4339 matches_pred (GtkTextIter *iter,
4340 GtkTextCharPredicate pred,
4345 ch = gtk_text_iter_get_char (iter);
4347 return (*pred) (ch, user_data);
4351 * gtk_text_iter_forward_find_char:
4352 * @iter: a #GtkTextIter
4353 * @pred: a function to be called on each character
4354 * @user_data: user data for @pred
4355 * @limit: search limit, or %NULL for none
4357 * Advances @iter, calling @pred on each character. If
4358 * @pred returns %TRUE, returns %TRUE and stops scanning.
4359 * If @pred never returns %TRUE, @iter is set to @limit if
4360 * @limit is non-%NULL, otherwise to the end iterator.
4362 * Return value: whether a match was found
4365 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4366 GtkTextCharPredicate pred,
4368 const GtkTextIter *limit)
4370 g_return_val_if_fail (iter != NULL, FALSE);
4371 g_return_val_if_fail (pred != NULL, FALSE);
4374 gtk_text_iter_compare (iter, limit) >= 0)
4377 while ((limit == NULL ||
4378 !gtk_text_iter_equal (limit, iter)) &&
4379 gtk_text_iter_forward_char (iter))
4381 if (matches_pred (iter, pred, user_data))
4389 * gtk_text_iter_backward_find_char:
4390 * @iter: a #GtkTextIter
4391 * @pred: function to be called on each character
4392 * @user_data: user data for @pred
4393 * @limit: search limit, or %NULL for none
4395 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4397 * Return value: whether a match was found
4400 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4401 GtkTextCharPredicate pred,
4403 const GtkTextIter *limit)
4405 g_return_val_if_fail (iter != NULL, FALSE);
4406 g_return_val_if_fail (pred != NULL, FALSE);
4409 gtk_text_iter_compare (iter, limit) <= 0)
4412 while ((limit == NULL ||
4413 !gtk_text_iter_equal (limit, iter)) &&
4414 gtk_text_iter_backward_char (iter))
4416 if (matches_pred (iter, pred, user_data))
4424 forward_chars_with_skipping (GtkTextIter *iter,
4426 gboolean skip_invisible,
4427 gboolean skip_nontext)
4432 g_return_if_fail (count >= 0);
4438 gboolean ignored = FALSE;
4441 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4446 _gtk_text_btree_char_is_invisible (iter))
4449 gtk_text_iter_forward_char (iter);
4457 lines_match (const GtkTextIter *start,
4458 const gchar **lines,
4459 gboolean visible_only,
4461 GtkTextIter *match_start,
4462 GtkTextIter *match_end)
4469 if (*lines == NULL || **lines == '\0')
4472 *match_start = *start;
4475 *match_end = *start;
4480 gtk_text_iter_forward_line (&next);
4482 /* No more text in buffer, but *lines is nonempty */
4483 if (gtk_text_iter_equal (start, &next))
4491 line_text = gtk_text_iter_get_visible_slice (start, &next);
4493 line_text = gtk_text_iter_get_slice (start, &next);
4498 line_text = gtk_text_iter_get_visible_text (start, &next);
4500 line_text = gtk_text_iter_get_text (start, &next);
4503 if (match_start) /* if this is the first line we're matching */
4504 found = strstr (line_text, *lines);
4507 /* If it's not the first line, we have to match from the
4508 * start of the line.
4510 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4522 /* Get offset to start of search string */
4523 offset = g_utf8_strlen (line_text, found - line_text);
4527 /* If match start needs to be returned, set it to the
4528 * start of the search string.
4532 *match_start = next;
4534 forward_chars_with_skipping (match_start, offset,
4535 visible_only, !slice);
4538 /* Go to end of search string */
4539 offset += g_utf8_strlen (*lines, -1);
4541 forward_chars_with_skipping (&next, offset,
4542 visible_only, !slice);
4551 /* pass NULL for match_start, since we don't need to find the
4554 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4557 /* strsplit () that retains the delimiter as part of the string. */
4559 strbreakup (const char *string,
4560 const char *delimiter,
4563 GSList *string_list = NULL, *slist;
4564 gchar **str_array, *s;
4567 g_return_val_if_fail (string != NULL, NULL);
4568 g_return_val_if_fail (delimiter != NULL, NULL);
4571 max_tokens = G_MAXINT;
4573 s = strstr (string, delimiter);
4576 guint delimiter_len = strlen (delimiter);
4583 len = s - string + delimiter_len;
4584 new_string = g_new (gchar, len + 1);
4585 strncpy (new_string, string, len);
4586 new_string[len] = 0;
4587 string_list = g_slist_prepend (string_list, new_string);
4589 string = s + delimiter_len;
4590 s = strstr (string, delimiter);
4592 while (--max_tokens && s);
4597 string_list = g_slist_prepend (string_list, g_strdup (string));
4600 str_array = g_new (gchar*, n);
4604 str_array[i--] = NULL;
4605 for (slist = string_list; slist; slist = slist->next)
4606 str_array[i--] = slist->data;
4608 g_slist_free (string_list);
4614 * gtk_text_iter_forward_search:
4615 * @iter: start of search
4616 * @str: a search string
4617 * @flags: flags affecting how the search is done
4618 * @match_start: return location for start of match, or %NULL
4619 * @match_end: return location for end of match, or %NULL
4620 * @limit: bound for the search, or %NULL for the end of the buffer
4622 * Searches forward for @str. Any match is returned by setting
4623 * @match_start to the first character of the match and @match_end to the
4624 * first character after the match. The search will not continue past
4625 * @limit. Note that a search is a linear or O(n) operation, so you
4626 * may wish to use @limit to avoid locking up your UI on large
4629 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4630 * have invisible text interspersed in @str. i.e. @str will be a
4631 * possibly-noncontiguous subsequence of the matched range. similarly,
4632 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4633 * pixbufs or child widgets mixed inside the matched range. If these
4634 * flags are not given, the match must be exact; the special 0xFFFC
4635 * character in @str will match embedded pixbufs or child widgets.
4637 * Return value: whether a match was found
4640 gtk_text_iter_forward_search (const GtkTextIter *iter,
4642 GtkTextSearchFlags flags,
4643 GtkTextIter *match_start,
4644 GtkTextIter *match_end,
4645 const GtkTextIter *limit)
4647 gchar **lines = NULL;
4649 gboolean retval = FALSE;
4651 gboolean visible_only;
4654 g_return_val_if_fail (iter != NULL, FALSE);
4655 g_return_val_if_fail (str != NULL, FALSE);
4658 gtk_text_iter_compare (iter, limit) >= 0)
4663 /* If we can move one char, return the empty string there */
4666 if (gtk_text_iter_forward_char (&match))
4669 gtk_text_iter_equal (&match, limit))
4673 *match_start = match;
4682 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4683 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4685 /* locate all lines */
4687 lines = strbreakup (str, "\n", -1);
4693 /* This loop has an inefficient worst-case, where
4694 * gtk_text_iter_get_text () is called repeatedly on
4700 gtk_text_iter_compare (&search, limit) >= 0)
4703 if (lines_match (&search, (const gchar**)lines,
4704 visible_only, slice, &match, &end))
4706 if (limit == NULL ||
4708 gtk_text_iter_compare (&end, limit) <= 0))
4713 *match_start = match;
4722 while (gtk_text_iter_forward_line (&search));
4724 g_strfreev ((gchar**)lines);
4730 vectors_equal_ignoring_trailing (gchar **vec1,
4733 /* Ignores trailing chars in vec2's last line */
4742 if (strcmp (*i1, *i2) != 0)
4744 if (*(i2 + 1) == NULL) /* if this is the last line */
4746 gint len1 = strlen (*i1);
4747 gint len2 = strlen (*i2);
4750 strncmp (*i1, *i2, len1) == 0)
4752 /* We matched ignoring the trailing stuff in vec2 */
4777 typedef struct _LinesWindow LinesWindow;
4783 GtkTextIter first_line_start;
4784 GtkTextIter first_line_end;
4786 gboolean visible_only;
4790 lines_window_init (LinesWindow *win,
4791 const GtkTextIter *start)
4794 GtkTextIter line_start;
4795 GtkTextIter line_end;
4797 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4800 if (gtk_text_iter_is_start (start) ||
4801 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4803 /* Already at the end, or not enough lines to match */
4804 win->lines = g_new0 (gchar*, 1);
4809 line_start = *start;
4812 /* Move to start iter to start of line */
4813 gtk_text_iter_set_line_offset (&line_start, 0);
4815 if (gtk_text_iter_equal (&line_start, &line_end))
4817 /* we were already at the start; so go back one line */
4818 gtk_text_iter_backward_line (&line_start);
4821 win->first_line_start = line_start;
4822 win->first_line_end = line_end;
4824 win->lines = g_new0 (gchar*, win->n_lines + 1);
4826 i = win->n_lines - 1;
4833 if (win->visible_only)
4834 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4836 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4840 if (win->visible_only)
4841 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4843 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4846 win->lines[i] = line_text;
4848 line_end = line_start;
4849 gtk_text_iter_backward_line (&line_start);
4856 lines_window_back (LinesWindow *win)
4858 GtkTextIter new_start;
4861 new_start = win->first_line_start;
4863 if (!gtk_text_iter_backward_line (&new_start))
4867 win->first_line_start = new_start;
4868 win->first_line_end = new_start;
4870 gtk_text_iter_forward_line (&win->first_line_end);
4875 if (win->visible_only)
4876 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4877 &win->first_line_end);
4879 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4880 &win->first_line_end);
4884 if (win->visible_only)
4885 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4886 &win->first_line_end);
4888 line_text = gtk_text_iter_get_text (&win->first_line_start,
4889 &win->first_line_end);
4892 /* Move lines to make room for first line. */
4893 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4895 *win->lines = line_text;
4897 /* Free old last line and NULL-terminate */
4898 g_free (win->lines[win->n_lines]);
4899 win->lines[win->n_lines] = NULL;
4905 lines_window_free (LinesWindow *win)
4907 g_strfreev (win->lines);
4911 * gtk_text_iter_backward_search:
4912 * @iter: a #GtkTextIter where the search begins
4913 * @str: search string
4914 * @flags: bitmask of flags affecting the search
4915 * @match_start: return location for start of match, or %NULL
4916 * @match_end: return location for end of match, or %NULL
4917 * @limit: location of last possible @match_start, or %NULL for start of buffer
4919 * Same as gtk_text_iter_forward_search(), but moves backward.
4921 * Return value: whether a match was found
4924 gtk_text_iter_backward_search (const GtkTextIter *iter,
4926 GtkTextSearchFlags flags,
4927 GtkTextIter *match_start,
4928 GtkTextIter *match_end,
4929 const GtkTextIter *limit)
4931 gchar **lines = NULL;
4935 gboolean retval = FALSE;
4936 gboolean visible_only;
4939 g_return_val_if_fail (iter != NULL, FALSE);
4940 g_return_val_if_fail (str != NULL, FALSE);
4943 gtk_text_iter_compare (limit, iter) > 0)
4948 /* If we can move one char, return the empty string there */
4949 GtkTextIter match = *iter;
4951 if (limit && gtk_text_iter_equal (limit, &match))
4954 if (gtk_text_iter_backward_char (&match))
4957 *match_start = match;
4966 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4967 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4969 /* locate all lines */
4971 lines = strbreakup (str, "\n", -1);
4981 win.n_lines = n_lines;
4983 win.visible_only = visible_only;
4985 lines_window_init (&win, iter);
4987 if (*win.lines == NULL)
4992 gchar *first_line_match;
4995 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4997 /* We're now before the search limit, abort. */
5001 /* If there are multiple lines, the first line will
5002 * end in '\n', so this will only match at the
5003 * end of the first line, which is correct.
5005 first_line_match = g_strrstr (*win.lines, *lines);
5007 if (first_line_match &&
5008 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
5013 GtkTextIter start_tmp;
5015 /* Offset to start of search string */
5016 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
5018 next = win.first_line_start;
5020 forward_chars_with_skipping (&start_tmp, offset,
5021 visible_only, !slice);
5024 gtk_text_iter_compare (limit, &start_tmp) > 0)
5025 goto out; /* match was bogus */
5028 *match_start = start_tmp;
5030 /* Go to end of search string */
5034 offset += g_utf8_strlen (*l, -1);
5038 forward_chars_with_skipping (&next, offset,
5039 visible_only, !slice);
5048 while (lines_window_back (&win));
5051 lines_window_free (&win);
5062 * gtk_text_iter_equal:
5063 * @lhs: a #GtkTextIter
5064 * @rhs: another #GtkTextIter
5066 * Tests whether two iterators are equal, using the fastest possible
5067 * mechanism. This function is very fast; you can expect it to perform
5068 * better than e.g. getting the character offset for each iterator and
5069 * comparing the offsets yourself. Also, it's a bit faster than
5070 * gtk_text_iter_compare().
5072 * Return value: %TRUE if the iterators point to the same place in the buffer
5075 gtk_text_iter_equal (const GtkTextIter *lhs,
5076 const GtkTextIter *rhs)
5078 GtkTextRealIter *real_lhs;
5079 GtkTextRealIter *real_rhs;
5081 real_lhs = (GtkTextRealIter*)lhs;
5082 real_rhs = (GtkTextRealIter*)rhs;
5084 check_invariants (lhs);
5085 check_invariants (rhs);
5087 if (real_lhs->line != real_rhs->line)
5089 else if (real_lhs->line_byte_offset >= 0 &&
5090 real_rhs->line_byte_offset >= 0)
5091 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5094 /* the ensure_char_offsets () calls do nothing if the char offsets
5095 are already up-to-date. */
5096 ensure_char_offsets (real_lhs);
5097 ensure_char_offsets (real_rhs);
5098 return real_lhs->line_char_offset == real_rhs->line_char_offset;
5103 * gtk_text_iter_compare:
5104 * @lhs: a #GtkTextIter
5105 * @rhs: another #GtkTextIter
5107 * A qsort()-style function that returns negative if @lhs is less than
5108 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5109 * Ordering is in character offset order, i.e. the first character in the buffer
5110 * is less than the second character in the buffer.
5112 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5115 gtk_text_iter_compare (const GtkTextIter *lhs,
5116 const GtkTextIter *rhs)
5118 GtkTextRealIter *real_lhs;
5119 GtkTextRealIter *real_rhs;
5121 real_lhs = gtk_text_iter_make_surreal (lhs);
5122 real_rhs = gtk_text_iter_make_surreal (rhs);
5124 if (real_lhs == NULL ||
5126 return -1; /* why not */
5128 check_invariants (lhs);
5129 check_invariants (rhs);
5131 if (real_lhs->line == real_rhs->line)
5133 gint left_index, right_index;
5135 if (real_lhs->line_byte_offset >= 0 &&
5136 real_rhs->line_byte_offset >= 0)
5138 left_index = real_lhs->line_byte_offset;
5139 right_index = real_rhs->line_byte_offset;
5143 /* the ensure_char_offsets () calls do nothing if
5144 the offsets are already up-to-date. */
5145 ensure_char_offsets (real_lhs);
5146 ensure_char_offsets (real_rhs);
5147 left_index = real_lhs->line_char_offset;
5148 right_index = real_rhs->line_char_offset;
5151 if (left_index < right_index)
5153 else if (left_index > right_index)
5162 line1 = gtk_text_iter_get_line (lhs);
5163 line2 = gtk_text_iter_get_line (rhs);
5166 else if (line1 > line2)
5174 * gtk_text_iter_in_range:
5175 * @iter: a #GtkTextIter
5176 * @start: start of range
5177 * @end: end of range
5179 * Checks whether @iter falls in the range [@start, @end).
5180 * @start and @end must be in ascending order.
5182 * Return value: %TRUE if @iter is in the range
5185 gtk_text_iter_in_range (const GtkTextIter *iter,
5186 const GtkTextIter *start,
5187 const GtkTextIter *end)
5189 g_return_val_if_fail (iter != NULL, FALSE);
5190 g_return_val_if_fail (start != NULL, FALSE);
5191 g_return_val_if_fail (end != NULL, FALSE);
5192 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5194 return gtk_text_iter_compare (iter, start) >= 0 &&
5195 gtk_text_iter_compare (iter, end) < 0;
5199 * gtk_text_iter_order:
5200 * @first: a #GtkTextIter
5201 * @second: another #GtkTextIter
5203 * Swaps the value of @first and @second if @second comes before
5204 * @first in the buffer. That is, ensures that @first and @second are
5205 * in sequence. Most text buffer functions that take a range call this
5206 * automatically on your behalf, so there's no real reason to call it yourself
5207 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5208 * that expect a pre-sorted range.
5212 gtk_text_iter_order (GtkTextIter *first,
5213 GtkTextIter *second)
5215 g_return_if_fail (first != NULL);
5216 g_return_if_fail (second != NULL);
5218 if (gtk_text_iter_compare (first, second) > 0)
5229 * Init iterators from the BTree
5233 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5237 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5238 gint real_char_index;
5242 g_return_if_fail (iter != NULL);
5243 g_return_if_fail (tree != NULL);
5245 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5246 &line_start, &real_char_index);
5248 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5250 real->cached_char_index = real_char_index;
5252 check_invariants (iter);
5256 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5261 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5265 g_return_if_fail (iter != NULL);
5266 g_return_if_fail (tree != NULL);
5268 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5270 iter_init_from_char_offset (iter, tree, line, char_on_line);
5272 /* We might as well cache this, since we know it. */
5273 real->cached_line_number = real_line;
5275 check_invariants (iter);
5279 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5284 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5288 g_return_if_fail (iter != NULL);
5289 g_return_if_fail (tree != NULL);
5291 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5293 iter_init_from_byte_offset (iter, tree, line, byte_index);
5295 /* We might as well cache this, since we know it. */
5296 real->cached_line_number = real_line;
5298 check_invariants (iter);
5302 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5307 g_return_if_fail (iter != NULL);
5308 g_return_if_fail (tree != NULL);
5309 g_return_if_fail (line != NULL);
5311 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5313 check_invariants (iter);
5317 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5323 g_return_val_if_fail (iter != NULL, FALSE);
5324 g_return_val_if_fail (tree != NULL, FALSE);
5326 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5330 /* Set iter to last in tree */
5331 _gtk_text_btree_get_end_iter (tree, iter);
5332 check_invariants (iter);
5337 iter_init_from_byte_offset (iter, tree, line, 0);
5339 if (!gtk_text_iter_toggles_tag (iter, tag))
5340 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5342 check_invariants (iter);
5348 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5352 g_return_val_if_fail (iter != NULL, FALSE);
5353 g_return_val_if_fail (tree != NULL, FALSE);
5355 _gtk_text_btree_get_end_iter (tree, iter);
5356 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5357 check_invariants (iter);
5363 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5365 const gchar *mark_name)
5369 g_return_val_if_fail (iter != NULL, FALSE);
5370 g_return_val_if_fail (tree != NULL, FALSE);
5372 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5378 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5379 check_invariants (iter);
5385 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5389 GtkTextLineSegment *seg;
5391 g_return_if_fail (iter != NULL);
5392 g_return_if_fail (tree != NULL);
5393 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5395 seg = mark->segment;
5397 iter_init_from_segment (iter, tree,
5398 seg->body.mark.line, seg);
5399 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5400 check_invariants (iter);
5404 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5406 GtkTextChildAnchor *anchor)
5408 GtkTextLineSegment *seg;
5410 g_return_if_fail (iter != NULL);
5411 g_return_if_fail (tree != NULL);
5412 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5414 seg = anchor->segment;
5416 g_assert (seg->body.child.line != NULL);
5418 iter_init_from_segment (iter, tree,
5419 seg->body.child.line, seg);
5420 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5421 check_invariants (iter);
5425 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5428 g_return_if_fail (iter != NULL);
5429 g_return_if_fail (tree != NULL);
5431 _gtk_text_btree_get_iter_at_char (tree,
5433 _gtk_text_btree_char_count (tree));
5434 check_invariants (iter);
5438 _gtk_text_iter_check (const GtkTextIter *iter)
5440 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5441 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5442 GtkTextLineSegment *byte_segment = NULL;
5443 GtkTextLineSegment *byte_any_segment = NULL;
5444 GtkTextLineSegment *char_segment = NULL;
5445 GtkTextLineSegment *char_any_segment = NULL;
5446 gboolean segments_updated;
5448 /* This function checks our class invariants for the Iter class. */
5450 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5452 if (real->chars_changed_stamp !=
5453 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5454 g_error ("iterator check failed: invalid iterator");
5456 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5457 g_error ("iterator check failed: both char and byte offsets are invalid");
5459 segments_updated = (real->segments_changed_stamp ==
5460 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5463 printf ("checking iter, segments %s updated, byte %d char %d\n",
5464 segments_updated ? "are" : "aren't",
5465 real->line_byte_offset,
5466 real->line_char_offset);
5469 if (segments_updated)
5471 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5472 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5474 if (real->segment->char_count == 0)
5475 g_error ("iterator check failed: segment is not indexable.");
5477 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5478 g_error ("segment char offset is not properly up-to-date");
5480 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5481 g_error ("segment byte offset is not properly up-to-date");
5483 if (real->segment_byte_offset >= 0 &&
5484 real->segment_byte_offset >= real->segment->byte_count)
5485 g_error ("segment byte offset is too large.");
5487 if (real->segment_char_offset >= 0 &&
5488 real->segment_char_offset >= real->segment->char_count)
5489 g_error ("segment char offset is too large.");
5492 if (real->line_byte_offset >= 0)
5494 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5495 &byte_segment, &byte_any_segment,
5496 &seg_byte_offset, &line_byte_offset);
5498 if (line_byte_offset != real->line_byte_offset)
5499 g_error ("wrong byte offset was stored in iterator");
5501 if (segments_updated)
5503 if (real->segment != byte_segment)
5504 g_error ("wrong segment was stored in iterator");
5506 if (real->any_segment != byte_any_segment)
5507 g_error ("wrong any_segment was stored in iterator");
5509 if (seg_byte_offset != real->segment_byte_offset)
5510 g_error ("wrong segment byte offset was stored in iterator");
5512 if (byte_segment->type == >k_text_char_type)
5515 p = byte_segment->body.chars + seg_byte_offset;
5517 if (!gtk_text_byte_begins_utf8_char (p))
5518 g_error ("broken iterator byte index pointed into the middle of a character");
5523 if (real->line_char_offset >= 0)
5525 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5526 &char_segment, &char_any_segment,
5527 &seg_char_offset, &line_char_offset);
5529 if (line_char_offset != real->line_char_offset)
5530 g_error ("wrong char offset was stored in iterator");
5532 if (segments_updated)
5534 if (real->segment != char_segment)
5535 g_error ("wrong segment was stored in iterator");
5537 if (real->any_segment != char_any_segment)
5538 g_error ("wrong any_segment was stored in iterator");
5540 if (seg_char_offset != real->segment_char_offset)
5541 g_error ("wrong segment char offset was stored in iterator");
5543 if (char_segment->type == >k_text_char_type)
5546 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5549 /* hmm, not likely to happen eh */
5550 if (!gtk_text_byte_begins_utf8_char (p))
5551 g_error ("broken iterator char offset pointed into the middle of a character");
5556 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5558 if (byte_segment != char_segment)
5559 g_error ("char and byte offsets did not point to the same segment");
5561 if (byte_any_segment != char_any_segment)
5562 g_error ("char and byte offsets did not point to the same any segment");
5564 /* Make sure the segment offsets are equivalent, if it's a char
5566 if (char_segment->type == >k_text_char_type)
5568 gint byte_offset = 0;
5569 gint char_offset = 0;
5570 while (char_offset < seg_char_offset)
5572 const char * start = char_segment->body.chars + byte_offset;
5573 byte_offset += g_utf8_next_char (start) - start;
5577 if (byte_offset != seg_byte_offset)
5578 g_error ("byte offset did not correspond to char offset");
5581 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5583 if (char_offset != seg_char_offset)
5584 g_error ("char offset did not correspond to byte offset");
5586 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5587 g_error ("byte index for iterator does not index the start of a character");
5591 if (real->cached_line_number >= 0)
5595 should_be = _gtk_text_line_get_number (real->line);
5596 if (real->cached_line_number != should_be)
5597 g_error ("wrong line number was cached");
5600 if (real->cached_char_index >= 0)
5602 if (real->line_char_offset >= 0) /* only way we can check it
5603 efficiently, not a real
5608 char_index = _gtk_text_line_char_index (real->line);
5609 char_index += real->line_char_offset;
5611 if (real->cached_char_index != char_index)
5612 g_error ("wrong char index was cached");
5616 if (_gtk_text_line_is_last (real->line, real->tree))
5617 g_error ("Iterator was on last line (past the end iterator)");
5620 #define __GTK_TEXT_ITER_C__
5621 #include "gtkaliasdef.c"