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"
35 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
37 typedef struct _GtkTextRealIter GtkTextRealIter;
39 struct _GtkTextRealIter
41 /* Always-valid information */
44 /* At least one of these is always valid;
45 if invalid, they are -1.
47 If the line byte offset is valid, so is the segment byte offset;
48 and ditto for char offsets. */
49 gint line_byte_offset;
50 gint line_char_offset;
51 /* These two are valid if >= 0 */
52 gint cached_char_index;
53 gint cached_line_number;
54 /* Stamps to detect the buffer changing under us */
55 gint chars_changed_stamp;
56 gint segments_changed_stamp;
57 /* Valid if the segments_changed_stamp is up-to-date */
58 GtkTextLineSegment *segment; /* indexable segment we index */
59 GtkTextLineSegment *any_segment; /* first segment in our location,
60 maybe same as "segment" */
61 /* One of these will always be valid if segments_changed_stamp is
62 up-to-date. If invalid, they are -1.
64 If the line byte offset is valid, so is the segment byte offset;
65 and ditto for char offsets. */
66 gint segment_byte_offset;
67 gint segment_char_offset;
74 /* These "set" functions should not assume any fields
75 other than the char stamp and the tree are valid.
78 iter_set_common (GtkTextRealIter *iter,
81 /* Update segments stamp */
82 iter->segments_changed_stamp =
83 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
87 iter->line_byte_offset = -1;
88 iter->line_char_offset = -1;
89 iter->segment_byte_offset = -1;
90 iter->segment_char_offset = -1;
91 iter->cached_char_index = -1;
92 iter->cached_line_number = -1;
96 iter_set_from_byte_offset (GtkTextRealIter *iter,
100 iter_set_common (iter, line);
102 if (!_gtk_text_line_byte_locate (iter->line,
106 &iter->segment_byte_offset,
107 &iter->line_byte_offset))
108 g_error ("Byte index %d is off the end of the line",
113 iter_set_from_char_offset (GtkTextRealIter *iter,
117 iter_set_common (iter, line);
119 if (!_gtk_text_line_char_locate (iter->line,
123 &iter->segment_char_offset,
124 &iter->line_char_offset))
125 g_error ("Char offset %d is off the end of the line",
130 iter_set_from_segment (GtkTextRealIter *iter,
132 GtkTextLineSegment *segment)
134 GtkTextLineSegment *seg;
137 /* This could theoretically be optimized by computing all the iter
138 fields in this same loop, but I'm skipping it for now. */
140 seg = line->segments;
141 while (seg != segment)
143 byte_offset += seg->byte_count;
147 iter_set_from_byte_offset (iter, line, byte_offset);
150 /* This function ensures that the segment-dependent information is
151 truly computed lazily; often we don't need to do the full make_real
152 work. This ensures the btree and line are valid, but doesn't
153 update the segments. */
154 static GtkTextRealIter*
155 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
157 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
159 if (iter->chars_changed_stamp !=
160 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
162 g_warning ("Invalid text buffer iterator: either the iterator "
163 "is uninitialized, or the characters/pixbufs/widgets "
164 "in the buffer have been modified since the iterator "
165 "was created.\nYou must use marks, character numbers, "
166 "or line numbers to preserve a position across buffer "
167 "modifications.\nYou can apply tags and insert marks "
168 "without invalidating your iterators,\n"
169 "but any mutation that affects 'indexable' buffer contents "
170 "(contents that can be referred to by character offset)\n"
171 "will invalidate all outstanding iterators");
175 /* We don't update the segments information since we are becoming
176 only surreal. However we do invalidate the segments information
177 if appropriate, to be sure we segfault if we try to use it and we
178 should have used make_real. */
180 if (iter->segments_changed_stamp !=
181 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
183 iter->segment = NULL;
184 iter->any_segment = NULL;
185 /* set to segfault-causing values. */
186 iter->segment_byte_offset = -10000;
187 iter->segment_char_offset = -10000;
193 static GtkTextRealIter*
194 gtk_text_iter_make_real (const GtkTextIter *_iter)
196 GtkTextRealIter *iter;
198 iter = gtk_text_iter_make_surreal (_iter);
200 if (iter->segments_changed_stamp !=
201 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
203 if (iter->line_byte_offset >= 0)
205 iter_set_from_byte_offset (iter,
207 iter->line_byte_offset);
211 g_assert (iter->line_char_offset >= 0);
213 iter_set_from_char_offset (iter,
215 iter->line_char_offset);
219 g_assert (iter->segment != NULL);
220 g_assert (iter->any_segment != NULL);
221 g_assert (iter->segment->char_count > 0);
226 static GtkTextRealIter*
227 iter_init_common (GtkTextIter *_iter,
230 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
232 g_return_val_if_fail (iter != NULL, NULL);
233 g_return_val_if_fail (tree != NULL, NULL);
237 iter->chars_changed_stamp =
238 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
243 static GtkTextRealIter*
244 iter_init_from_segment (GtkTextIter *iter,
247 GtkTextLineSegment *segment)
249 GtkTextRealIter *real;
251 g_return_val_if_fail (line != NULL, NULL);
253 real = iter_init_common (iter, tree);
255 iter_set_from_segment (real, line, segment);
260 static GtkTextRealIter*
261 iter_init_from_byte_offset (GtkTextIter *iter,
264 gint line_byte_offset)
266 GtkTextRealIter *real;
268 g_return_val_if_fail (line != NULL, NULL);
270 real = iter_init_common (iter, tree);
272 iter_set_from_byte_offset (real, line, line_byte_offset);
274 if (real->segment->type == >k_text_char_type &&
275 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
276 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
277 "character; this will crash the text buffer. "
278 "Byte indexes must refer to the start of a character.",
284 static GtkTextRealIter*
285 iter_init_from_char_offset (GtkTextIter *iter,
288 gint line_char_offset)
290 GtkTextRealIter *real;
292 g_return_val_if_fail (line != NULL, NULL);
294 real = iter_init_common (iter, tree);
296 iter_set_from_char_offset (real, line, line_char_offset);
302 invalidate_segment (GtkTextRealIter *iter)
304 iter->segments_changed_stamp -= 1;
308 invalidate_char_index (GtkTextRealIter *iter)
310 iter->cached_char_index = -1;
314 invalidate_line_number (GtkTextRealIter *iter)
316 iter->cached_line_number = -1;
320 adjust_char_index (GtkTextRealIter *iter, gint count)
322 if (iter->cached_char_index >= 0)
323 iter->cached_char_index += count;
327 adjust_line_number (GtkTextRealIter *iter, gint count)
329 if (iter->cached_line_number >= 0)
330 iter->cached_line_number += count;
334 adjust_char_offsets (GtkTextRealIter *iter, gint count)
336 if (iter->line_char_offset >= 0)
338 iter->line_char_offset += count;
339 g_assert (iter->segment_char_offset >= 0);
340 iter->segment_char_offset += count;
345 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
347 if (iter->line_byte_offset >= 0)
349 iter->line_byte_offset += count;
350 g_assert (iter->segment_byte_offset >= 0);
351 iter->segment_byte_offset += count;
356 ensure_char_offsets (GtkTextRealIter *iter)
358 if (iter->line_char_offset < 0)
360 g_assert (iter->line_byte_offset >= 0);
362 _gtk_text_line_byte_to_char_offsets (iter->line,
363 iter->line_byte_offset,
364 &iter->line_char_offset,
365 &iter->segment_char_offset);
370 ensure_byte_offsets (GtkTextRealIter *iter)
372 if (iter->line_byte_offset < 0)
374 g_assert (iter->line_char_offset >= 0);
376 _gtk_text_line_char_to_byte_offsets (iter->line,
377 iter->line_char_offset,
378 &iter->line_byte_offset,
379 &iter->segment_byte_offset);
383 static inline gboolean
384 is_segment_start (GtkTextRealIter *real)
386 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
391 check_invariants (const GtkTextIter *iter)
393 if (gtk_debug_flags & GTK_DEBUG_TEXT)
394 _gtk_text_iter_check (iter);
397 #define check_invariants (x)
401 * gtk_text_iter_get_buffer:
404 * Returns the #GtkTextBuffer this iterator is associated with.
406 * Return value: the buffer
409 gtk_text_iter_get_buffer (const GtkTextIter *iter)
411 GtkTextRealIter *real;
413 g_return_val_if_fail (iter != NULL, NULL);
415 real = gtk_text_iter_make_surreal (iter);
420 check_invariants (iter);
422 return _gtk_text_btree_get_buffer (real->tree);
426 * gtk_text_iter_copy:
429 * Creates a dynamically-allocated copy of an iterator. This function
430 * is not useful in applications, because iterators can be copied with a
431 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
432 * function is used by language bindings.
434 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
437 gtk_text_iter_copy (const GtkTextIter *iter)
439 GtkTextIter *new_iter;
441 g_return_val_if_fail (iter != NULL, NULL);
443 new_iter = g_new (GtkTextIter, 1);
451 * gtk_text_iter_free:
452 * @iter: a dynamically-allocated iterator
454 * Free an iterator allocated on the heap. This function
455 * is intended for use in language bindings, and is not
456 * especially useful for applications, because iterators can
457 * simply be allocated on the stack.
460 gtk_text_iter_free (GtkTextIter *iter)
462 g_return_if_fail (iter != NULL);
468 gtk_text_iter_get_type (void)
470 static GType our_type = 0;
473 our_type = g_boxed_type_register_static ("GtkTextIter",
474 (GBoxedCopyFunc) gtk_text_iter_copy,
475 (GBoxedFreeFunc) gtk_text_iter_free);
481 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
483 GtkTextRealIter *real;
485 g_return_val_if_fail (iter != NULL, NULL);
487 real = gtk_text_iter_make_real (iter);
492 check_invariants (iter);
494 g_assert (real->segment != NULL);
496 return real->segment;
500 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
502 GtkTextRealIter *real;
504 g_return_val_if_fail (iter != NULL, NULL);
506 real = gtk_text_iter_make_real (iter);
511 check_invariants (iter);
513 g_assert (real->any_segment != NULL);
515 return real->any_segment;
519 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
521 GtkTextRealIter *real;
523 g_return_val_if_fail (iter != NULL, 0);
525 real = gtk_text_iter_make_real (iter);
530 ensure_byte_offsets (real);
532 check_invariants (iter);
534 return real->segment_byte_offset;
538 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
540 GtkTextRealIter *real;
542 g_return_val_if_fail (iter != NULL, 0);
544 real = gtk_text_iter_make_real (iter);
549 ensure_char_offsets (real);
551 check_invariants (iter);
553 return real->segment_char_offset;
556 /* This function does not require a still-valid
559 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
561 const GtkTextRealIter *real;
563 g_return_val_if_fail (iter != NULL, NULL);
565 real = (const GtkTextRealIter*)iter;
570 /* This function does not require a still-valid
573 _gtk_text_iter_get_btree (const GtkTextIter *iter)
575 const GtkTextRealIter *real;
577 g_return_val_if_fail (iter != NULL, NULL);
579 real = (const GtkTextRealIter*)iter;
589 * gtk_text_iter_get_offset:
592 * Returns the character offset of an iterator.
593 * Each character in a #GtkTextBuffer has an offset,
594 * starting with 0 for the first character in the buffer.
595 * Use gtk_text_buffer_get_iter_at_offset () to convert an
596 * offset back into an iterator.
598 * Return value: a character offset
601 gtk_text_iter_get_offset (const GtkTextIter *iter)
603 GtkTextRealIter *real;
605 g_return_val_if_fail (iter != NULL, 0);
607 real = gtk_text_iter_make_surreal (iter);
612 check_invariants (iter);
614 if (real->cached_char_index < 0)
616 ensure_char_offsets (real);
618 real->cached_char_index =
619 _gtk_text_line_char_index (real->line);
620 real->cached_char_index += real->line_char_offset;
623 check_invariants (iter);
625 return real->cached_char_index;
629 * gtk_text_iter_get_line:
632 * Returns the line number containing the iterator. Lines in
633 * a #GtkTextBuffer are numbered beginning with 0 for the first
634 * line in the buffer.
636 * Return value: a line number
639 gtk_text_iter_get_line (const GtkTextIter *iter)
641 GtkTextRealIter *real;
643 g_return_val_if_fail (iter != NULL, 0);
645 real = gtk_text_iter_make_surreal (iter);
650 if (real->cached_line_number < 0)
651 real->cached_line_number =
652 _gtk_text_line_get_number (real->line);
654 check_invariants (iter);
656 return real->cached_line_number;
660 * gtk_text_iter_get_line_offset:
663 * Returns the character offset of the iterator,
664 * counting from the start of a newline-terminated line.
665 * The first character on the line has offset 0.
667 * Return value: offset from start of line
670 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
672 GtkTextRealIter *real;
674 g_return_val_if_fail (iter != NULL, 0);
676 real = gtk_text_iter_make_surreal (iter);
681 ensure_char_offsets (real);
683 check_invariants (iter);
685 return real->line_char_offset;
689 * gtk_text_iter_get_line_index:
692 * Returns the byte index of the iterator, counting
693 * from the start of a newline-terminated line.
694 * Remember that #GtkTextBuffer encodes text in
695 * UTF-8, and that characters can require a variable
696 * number of bytes to represent.
698 * Return value: distance from start of line, in bytes
701 gtk_text_iter_get_line_index (const GtkTextIter *iter)
703 GtkTextRealIter *real;
705 g_return_val_if_fail (iter != NULL, 0);
707 real = gtk_text_iter_make_surreal (iter);
712 ensure_byte_offsets (real);
714 check_invariants (iter);
716 return real->line_byte_offset;
720 * gtk_text_iter_get_visible_line_offset:
721 * @iter: a #GtkTextIter
723 * Returns the offset in characters from the start of the
724 * line to the given @iter, not counting characters that
725 * are invisible due to tags with the "invisible" flag
728 * Return value: offset in visible characters from the start of the line
731 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
733 GtkTextRealIter *real;
735 GtkTextLineSegment *seg;
738 g_return_val_if_fail (iter != NULL, 0);
740 real = gtk_text_iter_make_real (iter);
745 ensure_char_offsets (real);
747 check_invariants (iter);
749 vis_offset = real->line_char_offset;
751 g_assert (vis_offset >= 0);
753 _gtk_text_btree_get_iter_at_line (real->tree,
758 seg = _gtk_text_iter_get_indexable_segment (&pos);
760 while (seg != real->segment)
762 /* This is a pretty expensive call, making the
763 * whole function pretty lame; we could keep track
764 * of current invisibility state by looking at toggle
765 * segments as we loop, and then call this function
766 * only once per line, in order to speed up the loop
769 if (_gtk_text_btree_char_is_invisible (&pos))
770 vis_offset -= seg->char_count;
772 _gtk_text_iter_forward_indexable_segment (&pos);
774 seg = _gtk_text_iter_get_indexable_segment (&pos);
777 if (_gtk_text_btree_char_is_invisible (&pos))
778 vis_offset -= real->segment_char_offset;
785 * gtk_text_iter_get_visible_line_index:
786 * @iter: a #GtkTextIter
788 * Returns the number of bytes from the start of the
789 * line to the given @iter, not counting bytes that
790 * are invisible due to tags with the "invisible" flag
793 * Return value: byte index of @iter with respect to the start of the line
796 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
798 GtkTextRealIter *real;
800 GtkTextLineSegment *seg;
803 g_return_val_if_fail (iter != NULL, 0);
805 real = gtk_text_iter_make_real (iter);
810 ensure_byte_offsets (real);
812 check_invariants (iter);
814 vis_offset = real->line_byte_offset;
816 g_assert (vis_offset >= 0);
818 _gtk_text_btree_get_iter_at_line (real->tree,
823 seg = _gtk_text_iter_get_indexable_segment (&pos);
825 while (seg != real->segment)
827 /* This is a pretty expensive call, making the
828 * whole function pretty lame; we could keep track
829 * of current invisibility state by looking at toggle
830 * segments as we loop, and then call this function
831 * only once per line, in order to speed up the loop
834 if (_gtk_text_btree_char_is_invisible (&pos))
835 vis_offset -= seg->byte_count;
837 _gtk_text_iter_forward_indexable_segment (&pos);
839 seg = _gtk_text_iter_get_indexable_segment (&pos);
842 if (_gtk_text_btree_char_is_invisible (&pos))
843 vis_offset -= real->segment_byte_offset;
853 * gtk_text_iter_get_char:
856 * Returns the Unicode character at this iterator. (Equivalent to
857 * operator* on a C++ iterator.) If the element at this iterator is a
858 * non-character element, such as an image embedded in the buffer, the
859 * Unicode "unknown" character 0xFFFC is returned. If invoked on
860 * the end iterator, zero is returned; zero is not a valid Unicode character.
861 * So you can write a loop which ends when gtk_text_iter_get_char ()
864 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
867 gtk_text_iter_get_char (const GtkTextIter *iter)
869 GtkTextRealIter *real;
871 g_return_val_if_fail (iter != NULL, 0);
873 real = gtk_text_iter_make_real (iter);
878 check_invariants (iter);
880 if (gtk_text_iter_is_end (iter))
882 else if (real->segment->type == >k_text_char_type)
884 ensure_byte_offsets (real);
886 return g_utf8_get_char (real->segment->body.chars +
887 real->segment_byte_offset);
891 /* Unicode "unknown character" 0xFFFC */
892 return GTK_TEXT_UNKNOWN_CHAR;
897 * gtk_text_iter_get_slice:
898 * @start: iterator at start of a range
899 * @end: iterator at end of a range
901 * Returns the text in the given range. A "slice" is an array of
902 * characters encoded in UTF-8 format, including the Unicode "unknown"
903 * character 0xFFFC for iterable non-character elements in the buffer,
904 * such as images. Because images are encoded in the slice, byte and
905 * character offsets in the returned array will correspond to byte
906 * offsets in the text buffer. Note that 0xFFFC can occur in normal
907 * text as well, so it is not a reliable indicator that a pixbuf or
908 * widget is in the buffer.
910 * Return value: slice of text from the buffer
913 gtk_text_iter_get_slice (const GtkTextIter *start,
914 const GtkTextIter *end)
916 g_return_val_if_fail (start != NULL, NULL);
917 g_return_val_if_fail (end != NULL, NULL);
919 check_invariants (start);
920 check_invariants (end);
922 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
926 * gtk_text_iter_get_text:
927 * @start: iterator at start of a range
928 * @end: iterator at end of a range
930 * Returns <emphasis>text</emphasis> in the given range. If the range
931 * contains non-text elements such as images, the character and byte
932 * offsets in the returned string will not correspond to character and
933 * byte offsets in the buffer. If you want offsets to correspond, see
934 * gtk_text_iter_get_slice ().
936 * Return value: array of characters from the buffer
939 gtk_text_iter_get_text (const GtkTextIter *start,
940 const GtkTextIter *end)
942 g_return_val_if_fail (start != NULL, NULL);
943 g_return_val_if_fail (end != NULL, NULL);
945 check_invariants (start);
946 check_invariants (end);
948 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
952 * gtk_text_iter_get_visible_slice:
953 * @start: iterator at start of range
954 * @end: iterator at end of range
956 * Like gtk_text_iter_get_slice (), but invisible text is not included.
957 * Invisible text is usually invisible because a #GtkTextTag with the
958 * "invisible" attribute turned on has been applied to it.
960 * Return value: slice of text from the buffer
963 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
964 const GtkTextIter *end)
966 g_return_val_if_fail (start != NULL, NULL);
967 g_return_val_if_fail (end != NULL, NULL);
969 check_invariants (start);
970 check_invariants (end);
972 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
976 * gtk_text_iter_get_visible_text:
977 * @start: iterator at start of range
978 * @end: iterator at end of range
980 * Like gtk_text_iter_get_text (), but invisible text is not included.
981 * Invisible text is usually invisible because a #GtkTextTag with the
982 * "invisible" attribute turned on has been applied to it.
984 * Return value: string containing visible text in the range
987 gtk_text_iter_get_visible_text (const GtkTextIter *start,
988 const GtkTextIter *end)
990 g_return_val_if_fail (start != NULL, NULL);
991 g_return_val_if_fail (end != NULL, NULL);
993 check_invariants (start);
994 check_invariants (end);
996 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
1000 * gtk_text_iter_get_pixbuf:
1001 * @iter: an iterator
1003 * If the element at @iter is a pixbuf, the pixbuf is returned
1004 * (with no new reference count added). Otherwise,
1005 * %NULL is returned.
1007 * Return value: the pixbuf at @iter
1010 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1012 GtkTextRealIter *real;
1014 g_return_val_if_fail (iter != NULL, NULL);
1016 real = gtk_text_iter_make_real (iter);
1021 check_invariants (iter);
1023 if (real->segment->type != >k_text_pixbuf_type)
1026 return real->segment->body.pixbuf.pixbuf;
1030 * gtk_text_iter_get_child_anchor:
1031 * @iter: an iterator
1033 * If the location at @iter contains a child anchor, the
1034 * anchor is returned (with no new reference count added). Otherwise,
1035 * %NULL is returned.
1037 * Return value: the anchor at @iter
1040 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1042 GtkTextRealIter *real;
1044 g_return_val_if_fail (iter != NULL, NULL);
1046 real = gtk_text_iter_make_real (iter);
1051 check_invariants (iter);
1053 if (real->segment->type != >k_text_child_type)
1056 return real->segment->body.child.obj;
1060 * gtk_text_iter_get_marks:
1061 * @iter: an iterator
1063 * Returns a list of all #GtkTextMark at this location. Because marks
1064 * are not iterable (they don't take up any "space" in the buffer,
1065 * they are just marks in between iterable locations), multiple marks
1066 * can exist in the same place. The returned list is not in any
1069 * Return value: list of #GtkTextMark
1072 gtk_text_iter_get_marks (const GtkTextIter *iter)
1074 GtkTextRealIter *real;
1075 GtkTextLineSegment *seg;
1078 g_return_val_if_fail (iter != NULL, NULL);
1080 real = gtk_text_iter_make_real (iter);
1085 check_invariants (iter);
1088 seg = real->any_segment;
1089 while (seg != real->segment)
1091 if (seg->type == >k_text_left_mark_type ||
1092 seg->type == >k_text_right_mark_type)
1093 retval = g_slist_prepend (retval, seg->body.mark.obj);
1098 /* The returned list isn't guaranteed to be in any special order,
1104 * gtk_text_iter_get_toggled_tags:
1105 * @iter: an iterator
1106 * @toggled_on: %TRUE to get toggled-on tags
1108 * Returns a list of #GtkTextTag that are toggled on or off at this
1109 * point. (If @toggled_on is %TRUE, the list contains tags that are
1110 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1111 * range of characters following @iter has that tag applied to it. If
1112 * a tag is toggled off, then some non-empty range following @iter
1113 * does <emphasis>not</emphasis> have the tag applied to it.
1115 * Return value: tags toggled at this point
1118 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1119 gboolean toggled_on)
1121 GtkTextRealIter *real;
1122 GtkTextLineSegment *seg;
1125 g_return_val_if_fail (iter != NULL, NULL);
1127 real = gtk_text_iter_make_real (iter);
1132 check_invariants (iter);
1135 seg = real->any_segment;
1136 while (seg != real->segment)
1140 if (seg->type == >k_text_toggle_on_type)
1142 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1147 if (seg->type == >k_text_toggle_off_type)
1149 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1156 /* The returned list isn't guaranteed to be in any special order,
1162 * gtk_text_iter_begins_tag:
1163 * @iter: an iterator
1164 * @tag: a #GtkTextTag, or %NULL
1166 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1167 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1168 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1169 * <emphasis>start</emphasis> of the tagged range;
1170 * gtk_text_iter_has_tag () tells you whether an iterator is
1171 * <emphasis>within</emphasis> a tagged range.
1173 * Return value: whether @iter is the start of a range tagged with @tag
1176 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1179 GtkTextRealIter *real;
1180 GtkTextLineSegment *seg;
1182 g_return_val_if_fail (iter != NULL, FALSE);
1184 real = gtk_text_iter_make_real (iter);
1189 check_invariants (iter);
1191 seg = real->any_segment;
1192 while (seg != real->segment)
1194 if (seg->type == >k_text_toggle_on_type)
1197 seg->body.toggle.info->tag == tag)
1208 * gtk_text_iter_ends_tag:
1209 * @iter: an iterator
1210 * @tag: a #GtkTextTag, or %NULL
1212 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1213 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1214 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1215 * <emphasis>end</emphasis> of the tagged range;
1216 * gtk_text_iter_has_tag () tells you whether an iterator is
1217 * <emphasis>within</emphasis> a tagged range.
1219 * Return value: whether @iter is the end of a range tagged with @tag
1223 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1226 GtkTextRealIter *real;
1227 GtkTextLineSegment *seg;
1229 g_return_val_if_fail (iter != NULL, FALSE);
1231 real = gtk_text_iter_make_real (iter);
1236 check_invariants (iter);
1238 seg = real->any_segment;
1239 while (seg != real->segment)
1241 if (seg->type == >k_text_toggle_off_type)
1244 seg->body.toggle.info->tag == tag)
1255 * gtk_text_iter_toggles_tag:
1256 * @iter: an iterator
1257 * @tag: a #GtkTextTag, or %NULL
1259 * This is equivalent to (gtk_text_iter_begins_tag () ||
1260 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1261 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1263 * Return value: whether @tag is toggled on or off at @iter
1266 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1269 GtkTextRealIter *real;
1270 GtkTextLineSegment *seg;
1272 g_return_val_if_fail (iter != NULL, FALSE);
1274 real = gtk_text_iter_make_real (iter);
1279 check_invariants (iter);
1281 seg = real->any_segment;
1282 while (seg != real->segment)
1284 if ( (seg->type == >k_text_toggle_off_type ||
1285 seg->type == >k_text_toggle_on_type) &&
1287 seg->body.toggle.info->tag == tag) )
1297 * gtk_text_iter_has_tag:
1298 * @iter: an iterator
1299 * @tag: a #GtkTextTag
1301 * Returns %TRUE if @iter is within a range tagged with @tag.
1303 * Return value: whether @iter is tagged with @tag
1306 gtk_text_iter_has_tag (const GtkTextIter *iter,
1309 GtkTextRealIter *real;
1311 g_return_val_if_fail (iter != NULL, FALSE);
1312 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1314 real = gtk_text_iter_make_surreal (iter);
1319 check_invariants (iter);
1321 if (real->line_byte_offset >= 0)
1323 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1324 real->line_byte_offset, tag);
1328 g_assert (real->line_char_offset >= 0);
1329 return _gtk_text_line_char_has_tag (real->line, real->tree,
1330 real->line_char_offset, tag);
1335 * gtk_text_iter_get_tags:
1336 * @iter: a #GtkTextIter
1338 * Returns a list of tags that apply to @iter, in ascending order of
1339 * priority (highest-priority tags are last). The #GtkTextTag in the
1340 * list don't have a reference added, but you have to free the list
1343 * Return value: list of #GtkTextTag
1346 gtk_text_iter_get_tags (const GtkTextIter *iter)
1353 g_return_val_if_fail (iter != NULL, NULL);
1355 /* Get the tags at this spot */
1356 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1358 /* No tags, use default style */
1359 if (tags == NULL || tag_count == 0)
1367 /* Sort tags in ascending order of priority */
1368 _gtk_text_tag_array_sort (tags, tag_count);
1372 while (i < tag_count)
1374 retval = g_slist_prepend (retval, tags[i]);
1380 /* Return tags in ascending order of priority */
1381 return g_slist_reverse (retval);
1385 * gtk_text_iter_editable:
1386 * @iter: an iterator
1387 * @default_setting: %TRUE if text is editable by default
1389 * Returns whether the character at @iter is within an editable region
1390 * of text. Non-editable text is "locked" and can't be changed by the
1391 * user via #GtkTextView. This function is simply a convenience
1392 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1393 * to this text affect editability, @default_setting will be returned.
1395 * You don't want to use this function to decide whether text can be
1396 * inserted at @iter, because for insertion you don't want to know
1397 * whether the char at @iter is inside an editable range, you want to
1398 * know whether a new character inserted at @iter would be inside an
1399 * editable range. Use gtk_text_iter_can_insert() to handle this
1402 * Return value: whether @iter is inside an editable range
1405 gtk_text_iter_editable (const GtkTextIter *iter,
1406 gboolean default_setting)
1408 GtkTextAttributes *values;
1411 g_return_val_if_fail (iter != NULL, FALSE);
1413 values = gtk_text_attributes_new ();
1415 values->editable = default_setting;
1417 gtk_text_iter_get_attributes (iter, values);
1419 retval = values->editable;
1421 gtk_text_attributes_unref (values);
1427 * gtk_text_iter_can_insert:
1428 * @iter: an iterator
1429 * @default_editability: %TRUE if text is editable by default
1431 * Considering the default editability of the buffer, and tags that
1432 * affect editability, determines whether text inserted at @iter would
1433 * be editable. If text inserted at @iter would be editable then the
1434 * user should be allowed to insert text at @iter.
1435 * gtk_text_buffer_insert_interactive() uses this function to decide
1436 * whether insertions are allowed at a given position.
1438 * Return value: whether text inserted at @iter would be editable
1441 gtk_text_iter_can_insert (const GtkTextIter *iter,
1442 gboolean default_editability)
1444 g_return_val_if_fail (iter != NULL, FALSE);
1446 if (gtk_text_iter_editable (iter, default_editability))
1448 /* If at start/end of buffer, default editability is used */
1449 else if ((gtk_text_iter_is_start (iter) ||
1450 gtk_text_iter_is_end (iter)) &&
1451 default_editability)
1455 /* if iter isn't editable, and the char before iter is,
1456 * then iter is the first char in an editable region
1457 * and thus insertion at iter results in editable text.
1459 GtkTextIter prev = *iter;
1460 gtk_text_iter_backward_char (&prev);
1461 return gtk_text_iter_editable (&prev, default_editability);
1467 * gtk_text_iter_get_language:
1468 * @iter: an iterator
1470 * A convenience wrapper around gtk_text_iter_get_attributes (),
1471 * which returns the language in effect at @iter. If no tags affecting
1472 * language apply to @iter, the return value is identical to that of
1473 * gtk_get_default_language ().
1475 * Return value: language in effect at @iter
1478 gtk_text_iter_get_language (const GtkTextIter *iter)
1480 GtkTextAttributes *values;
1481 PangoLanguage *retval;
1483 values = gtk_text_attributes_new ();
1485 gtk_text_iter_get_attributes (iter, values);
1487 retval = values->language;
1489 gtk_text_attributes_unref (values);
1495 * gtk_text_iter_starts_line:
1496 * @iter: an iterator
1498 * Returns %TRUE if @iter begins a paragraph,
1499 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1500 * However this function is potentially more efficient than
1501 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1502 * the offset, it just has to see whether it's 0.
1504 * Return value: whether @iter begins a line
1507 gtk_text_iter_starts_line (const GtkTextIter *iter)
1509 GtkTextRealIter *real;
1511 g_return_val_if_fail (iter != NULL, FALSE);
1513 real = gtk_text_iter_make_surreal (iter);
1518 check_invariants (iter);
1520 if (real->line_byte_offset >= 0)
1522 return (real->line_byte_offset == 0);
1526 g_assert (real->line_char_offset >= 0);
1527 return (real->line_char_offset == 0);
1532 * gtk_text_iter_ends_line:
1533 * @iter: an iterator
1535 * Returns %TRUE if @iter points to the start of the paragraph
1536 * delimiter characters for a line (delimiters will be either a
1537 * newline, a carriage return, a carriage return followed by a
1538 * newline, or a Unicode paragraph separator character). Note that an
1539 * iterator pointing to the \n of a \r\n pair will not be counted as
1540 * the end of a line, the line ends before the \r. The end iterator is
1541 * considered to be at the end of a line, even though there are no
1542 * paragraph delimiter chars there.
1544 * Return value: whether @iter is at the end of a line
1547 gtk_text_iter_ends_line (const GtkTextIter *iter)
1549 GtkTextRealIter *real;
1552 g_return_val_if_fail (iter != NULL, FALSE);
1554 real = gtk_text_iter_make_real (iter);
1556 check_invariants (iter);
1558 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1559 * Unicode 3.0; update this if that changes.
1561 #define PARAGRAPH_SEPARATOR 0x2029
1563 wc = gtk_text_iter_get_char (iter);
1565 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1567 else if (wc == '\n')
1569 /* need to determine if a \r precedes the \n, in which case
1570 * we aren't the end of the line
1572 GtkTextIter tmp = *iter;
1573 if (!gtk_text_iter_backward_char (&tmp))
1576 return gtk_text_iter_get_char (&tmp) != '\r';
1583 * gtk_text_iter_is_end:
1584 * @iter: an iterator
1586 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1587 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1588 * the most efficient way to check whether an iterator is the end
1591 * Return value: whether @iter is the end iterator
1594 gtk_text_iter_is_end (const GtkTextIter *iter)
1596 GtkTextRealIter *real;
1598 g_return_val_if_fail (iter != NULL, FALSE);
1600 real = gtk_text_iter_make_surreal (iter);
1605 check_invariants (iter);
1607 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1610 /* Now we need the segments validated */
1611 real = gtk_text_iter_make_real (iter);
1616 return _gtk_text_btree_is_end (real->tree, real->line,
1618 real->segment_byte_offset,
1619 real->segment_char_offset);
1623 * gtk_text_iter_is_start:
1624 * @iter: an iterator
1626 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1627 * if @iter has a character offset of 0.
1629 * Return value: whether @iter is the first in the buffer
1632 gtk_text_iter_is_start (const GtkTextIter *iter)
1634 return gtk_text_iter_get_offset (iter) == 0;
1638 * gtk_text_iter_get_chars_in_line:
1639 * @iter: an iterator
1641 * Returns the number of characters in the line containing @iter,
1642 * including the paragraph delimiters.
1644 * Return value: number of characters in the line
1647 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1649 GtkTextRealIter *real;
1651 GtkTextLineSegment *seg;
1653 g_return_val_if_fail (iter != NULL, 0);
1655 real = gtk_text_iter_make_surreal (iter);
1660 check_invariants (iter);
1662 if (real->line_char_offset >= 0)
1664 /* We can start at the segments we've already found. */
1665 count = real->line_char_offset - real->segment_char_offset;
1666 seg = _gtk_text_iter_get_indexable_segment (iter);
1670 /* count whole line. */
1671 seg = real->line->segments;
1678 count += seg->char_count;
1683 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1684 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1690 * gtk_text_iter_get_bytes_in_line:
1691 * @iter: an iterator
1693 * Returns the number of bytes in the line containing @iter,
1694 * including the paragraph delimiters.
1696 * Return value: number of bytes in the line
1699 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1701 GtkTextRealIter *real;
1703 GtkTextLineSegment *seg;
1705 g_return_val_if_fail (iter != NULL, 0);
1707 real = gtk_text_iter_make_surreal (iter);
1712 check_invariants (iter);
1714 if (real->line_byte_offset >= 0)
1716 /* We can start at the segments we've already found. */
1717 count = real->line_byte_offset - real->segment_byte_offset;
1718 seg = _gtk_text_iter_get_indexable_segment (iter);
1722 /* count whole line. */
1723 seg = real->line->segments;
1729 count += seg->byte_count;
1734 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1735 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1741 * gtk_text_iter_get_attributes:
1742 * @iter: an iterator
1743 * @values: a #GtkTextAttributes to be filled in
1745 * Computes the effect of any tags applied to this spot in the
1746 * text. The @values parameter should be initialized to the default
1747 * settings you wish to use if no tags are in effect. You'd typically
1748 * obtain the defaults from gtk_text_view_get_default_attributes().
1750 * gtk_text_iter_get_attributes () will modify @values, applying the
1751 * effects of any tags present at @iter. If any tags affected @values,
1752 * the function returns %TRUE.
1754 * Return value: %TRUE if @values was modified
1757 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1758 GtkTextAttributes *values)
1763 /* Get the tags at this spot */
1764 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1766 /* No tags, use default style */
1767 if (tags == NULL || tag_count == 0)
1775 /* Sort tags in ascending order of priority */
1776 _gtk_text_tag_array_sort (tags, tag_count);
1778 _gtk_text_attributes_fill_from_tags (values,
1788 * Increments/decrements
1791 /* The return value of this indicates WHETHER WE MOVED.
1792 * The return value of public functions indicates
1793 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1795 * This function will not change the iterator if
1796 * it's already on the last (end iter) line, i.e. it
1797 * won't move to the end of the last line.
1800 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1802 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1804 GtkTextLine *new_line;
1806 new_line = _gtk_text_line_next (real->line);
1807 g_assert (new_line);
1808 g_assert (new_line != real->line);
1809 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1811 real->line = new_line;
1813 real->line_byte_offset = 0;
1814 real->line_char_offset = 0;
1816 real->segment_byte_offset = 0;
1817 real->segment_char_offset = 0;
1819 /* Find first segments in new line */
1820 real->any_segment = real->line->segments;
1821 real->segment = real->any_segment;
1822 while (real->segment->char_count == 0)
1823 real->segment = real->segment->next;
1829 /* There is no way to move forward a line; we were already at
1830 * the line containing the end iterator.
1831 * However we may not be at the end iterator itself.
1839 /* The return value of this indicates WHETHER WE MOVED.
1840 * The return value of public functions indicates
1841 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1843 * This function is currently unused, thus it is #if-0-ed. It is
1844 * left here, since it's non-trivial code that might be useful in
1848 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1850 GtkTextLine *new_line;
1852 new_line = _gtk_text_line_previous (real->line);
1854 g_assert (new_line != real->line);
1856 if (new_line != NULL)
1858 real->line = new_line;
1860 real->line_byte_offset = 0;
1861 real->line_char_offset = 0;
1863 real->segment_byte_offset = 0;
1864 real->segment_char_offset = 0;
1866 /* Find first segments in new line */
1867 real->any_segment = real->line->segments;
1868 real->segment = real->any_segment;
1869 while (real->segment->char_count == 0)
1870 real->segment = real->segment->next;
1876 /* There is no way to move backward; we were already
1877 at the first line. */
1879 /* We leave real->line as-is */
1881 /* Note that we didn't clamp to the start of the first line. */
1888 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1892 forward_char (GtkTextRealIter *real)
1894 GtkTextIter *iter = (GtkTextIter*)real;
1896 check_invariants ((GtkTextIter*)real);
1898 ensure_char_offsets (real);
1900 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1902 /* Need to move to the next segment; if no next segment,
1903 need to move to next line. */
1904 return _gtk_text_iter_forward_indexable_segment (iter);
1908 /* Just moving within a segment. Keep byte count
1909 up-to-date, if it was already up-to-date. */
1911 g_assert (real->segment->type == >k_text_char_type);
1913 if (real->line_byte_offset >= 0)
1916 const char * start =
1917 real->segment->body.chars + real->segment_byte_offset;
1919 bytes = g_utf8_next_char (start) - start;
1921 real->line_byte_offset += bytes;
1922 real->segment_byte_offset += bytes;
1924 g_assert (real->segment_byte_offset < real->segment->byte_count);
1927 real->line_char_offset += 1;
1928 real->segment_char_offset += 1;
1930 adjust_char_index (real, 1);
1932 g_assert (real->segment_char_offset < real->segment->char_count);
1934 /* We moved into the middle of a segment, so the any_segment
1935 must now be the segment we're in the middle of. */
1936 real->any_segment = real->segment;
1938 check_invariants ((GtkTextIter*)real);
1940 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1948 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1950 /* Need to move to the next segment; if no next segment,
1951 need to move to next line. */
1952 GtkTextLineSegment *seg;
1953 GtkTextLineSegment *any_seg;
1954 GtkTextRealIter *real;
1958 g_return_val_if_fail (iter != NULL, FALSE);
1960 real = gtk_text_iter_make_real (iter);
1965 check_invariants (iter);
1967 if (real->line_char_offset >= 0)
1969 chars_skipped = real->segment->char_count - real->segment_char_offset;
1970 g_assert (chars_skipped > 0);
1975 if (real->line_byte_offset >= 0)
1977 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1978 g_assert (bytes_skipped > 0);
1983 /* Get first segment of any kind */
1984 any_seg = real->segment->next;
1985 /* skip non-indexable segments, if any */
1987 while (seg != NULL && seg->char_count == 0)
1992 real->any_segment = any_seg;
1993 real->segment = seg;
1995 if (real->line_byte_offset >= 0)
1997 g_assert (bytes_skipped > 0);
1998 real->segment_byte_offset = 0;
1999 real->line_byte_offset += bytes_skipped;
2002 if (real->line_char_offset >= 0)
2004 g_assert (chars_skipped > 0);
2005 real->segment_char_offset = 0;
2006 real->line_char_offset += chars_skipped;
2007 adjust_char_index (real, chars_skipped);
2010 check_invariants (iter);
2012 return !gtk_text_iter_is_end (iter);
2016 /* End of the line */
2017 if (forward_line_leaving_caches_unmodified (real))
2019 adjust_line_number (real, 1);
2020 if (real->line_char_offset >= 0)
2021 adjust_char_index (real, chars_skipped);
2023 g_assert (real->line_byte_offset == 0);
2024 g_assert (real->line_char_offset == 0);
2025 g_assert (real->segment_byte_offset == 0);
2026 g_assert (real->segment_char_offset == 0);
2027 g_assert (gtk_text_iter_starts_line (iter));
2029 check_invariants (iter);
2031 return !gtk_text_iter_is_end (iter);
2035 /* End of buffer, but iter is still at start of last segment,
2036 * not at the end iterator. We put it on the end iterator.
2039 check_invariants (iter);
2041 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2042 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2044 gtk_text_iter_forward_to_line_end (iter);
2046 g_assert (gtk_text_iter_is_end (iter));
2054 at_last_indexable_segment (GtkTextRealIter *real)
2056 GtkTextLineSegment *seg;
2058 /* Return TRUE if there are no indexable segments after
2062 seg = real->segment->next;
2065 if (seg->char_count > 0)
2072 /* Goes back to the start of the next segment, even if
2073 * we're not at the start of the current segment (always
2074 * ends up on a different segment if it returns TRUE)
2077 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2079 /* Move to the start of the previous segment; if no previous
2080 * segment, to the last segment in the previous line. This is
2081 * inherently a bit inefficient due to the singly-linked list and
2082 * tree nodes, but we can't afford the RAM for doubly-linked.
2084 GtkTextRealIter *real;
2085 GtkTextLineSegment *seg;
2086 GtkTextLineSegment *any_seg;
2087 GtkTextLineSegment *prev_seg;
2088 GtkTextLineSegment *prev_any_seg;
2092 g_return_val_if_fail (iter != NULL, FALSE);
2094 real = gtk_text_iter_make_real (iter);
2099 check_invariants (iter);
2101 /* Find first segments in line */
2102 any_seg = real->line->segments;
2104 while (seg->char_count == 0)
2107 if (seg == real->segment)
2109 /* Could probably do this case faster by hand-coding the
2113 /* We were already at the start of a line;
2114 * go back to the previous line.
2116 if (gtk_text_iter_backward_line (iter))
2118 /* Go forward to last indexable segment in line. */
2119 while (!at_last_indexable_segment (real))
2120 _gtk_text_iter_forward_indexable_segment (iter);
2122 check_invariants (iter);
2127 return FALSE; /* We were at the start of the first line. */
2130 /* We must be in the middle of a line; so find the indexable
2131 * segment just before our current segment.
2133 g_assert (seg != real->segment);
2137 prev_any_seg = any_seg;
2139 any_seg = seg->next;
2141 while (seg->char_count == 0)
2144 while (seg != real->segment);
2146 g_assert (prev_seg != NULL);
2147 g_assert (prev_any_seg != NULL);
2148 g_assert (prev_seg->char_count > 0);
2150 /* We skipped the entire previous segment, plus any
2151 * chars we were into the current segment.
2153 if (real->segment_byte_offset >= 0)
2154 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2158 if (real->segment_char_offset >= 0)
2159 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2163 real->segment = prev_seg;
2164 real->any_segment = prev_any_seg;
2165 real->segment_byte_offset = 0;
2166 real->segment_char_offset = 0;
2168 if (bytes_skipped >= 0)
2170 if (real->line_byte_offset >= 0)
2172 real->line_byte_offset -= bytes_skipped;
2173 g_assert (real->line_byte_offset >= 0);
2177 real->line_byte_offset = -1;
2179 if (chars_skipped >= 0)
2181 if (real->line_char_offset >= 0)
2183 real->line_char_offset -= chars_skipped;
2184 g_assert (real->line_char_offset >= 0);
2187 if (real->cached_char_index >= 0)
2189 real->cached_char_index -= chars_skipped;
2190 g_assert (real->cached_char_index >= 0);
2195 real->line_char_offset = -1;
2196 real->cached_char_index = -1;
2199 /* line number is unchanged. */
2201 check_invariants (iter);
2207 * gtk_text_iter_forward_char:
2208 * @iter: an iterator
2210 * Moves @iter forward by one character offset. Note that images
2211 * embedded in the buffer occupy 1 character slot, so
2212 * gtk_text_iter_forward_char () may actually move onto an image instead
2213 * of a character, if you have images in your buffer. If @iter is the
2214 * end iterator or one character before it, @iter will now point at
2215 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2216 * convenience when writing loops.
2218 * Return value: whether @iter moved and is dereferenceable
2221 gtk_text_iter_forward_char (GtkTextIter *iter)
2223 GtkTextRealIter *real;
2225 g_return_val_if_fail (iter != NULL, FALSE);
2227 real = gtk_text_iter_make_real (iter);
2233 check_invariants (iter);
2234 return forward_char (real);
2239 * gtk_text_iter_backward_char:
2240 * @iter: an iterator
2242 * Moves backward by one character offset. Returns %TRUE if movement
2243 * was possible; if @iter was the first in the buffer (character
2244 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2247 * Return value: whether movement was possible
2250 gtk_text_iter_backward_char (GtkTextIter *iter)
2252 g_return_val_if_fail (iter != NULL, FALSE);
2254 check_invariants (iter);
2256 return gtk_text_iter_backward_chars (iter, 1);
2260 Definitely we should try to linear scan as often as possible for
2261 movement within a single line, because we can't use the BTree to
2262 speed within-line searches up; for movement between lines, we would
2263 like to avoid the linear scan probably.
2265 Instead of using this constant, it might be nice to cache the line
2266 length in the iterator and linear scan if motion is within a single
2269 I guess you'd have to profile the various approaches.
2271 #define MAX_LINEAR_SCAN 150
2275 * gtk_text_iter_forward_chars:
2276 * @iter: an iterator
2277 * @count: number of characters to move, may be negative
2279 * Moves @count characters if possible (if @count would move past the
2280 * start or end of the buffer, moves to the start or end of the
2281 * buffer). The return value indicates whether the new position of
2282 * @iter is different from its original position, and dereferenceable
2283 * (the last iterator in the buffer is not dereferenceable). If @count
2284 * is 0, the function does nothing and returns %FALSE.
2286 * Return value: whether @iter moved and is dereferenceable
2289 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2291 GtkTextRealIter *real;
2293 g_return_val_if_fail (iter != NULL, FALSE);
2295 FIX_OVERFLOWS (count);
2297 real = gtk_text_iter_make_real (iter);
2301 else if (count == 0)
2304 return gtk_text_iter_backward_chars (iter, 0 - count);
2305 else if (count < MAX_LINEAR_SCAN)
2307 check_invariants (iter);
2311 if (!forward_char (real))
2316 return forward_char (real);
2320 gint current_char_index;
2321 gint new_char_index;
2323 check_invariants (iter);
2325 current_char_index = gtk_text_iter_get_offset (iter);
2327 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2328 return FALSE; /* can't move forward */
2330 new_char_index = current_char_index + count;
2331 gtk_text_iter_set_offset (iter, new_char_index);
2333 check_invariants (iter);
2335 /* Return FALSE if we're on the non-dereferenceable end
2338 if (gtk_text_iter_is_end (iter))
2346 * gtk_text_iter_backward_chars:
2347 * @iter: an iterator
2348 * @count: number of characters to move
2350 * Moves @count characters backward, if possible (if @count would move
2351 * past the start or end of the buffer, moves to the start or end of
2352 * the buffer). The return value indicates whether the iterator moved
2353 * onto a dereferenceable position; if the iterator didn't move, or
2354 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2355 * the function does nothing and returns %FALSE.
2357 * Return value: whether @iter moved and is dereferenceable
2361 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2363 GtkTextRealIter *real;
2365 g_return_val_if_fail (iter != NULL, FALSE);
2367 FIX_OVERFLOWS (count);
2369 real = gtk_text_iter_make_real (iter);
2373 else if (count == 0)
2376 return gtk_text_iter_forward_chars (iter, 0 - count);
2378 ensure_char_offsets (real);
2379 check_invariants (iter);
2381 /* <, not <=, because if count == segment_char_offset
2382 * we're going to the front of the segment and the any_segment
2385 if (count < real->segment_char_offset)
2387 /* Optimize the within-segment case */
2388 g_assert (real->segment->char_count > 0);
2389 g_assert (real->segment->type == >k_text_char_type);
2391 real->segment_char_offset -= count;
2392 g_assert (real->segment_char_offset >= 0);
2394 if (real->line_byte_offset >= 0)
2396 gint new_byte_offset;
2399 new_byte_offset = 0;
2401 while (i < real->segment_char_offset)
2403 const char * start = real->segment->body.chars + new_byte_offset;
2404 new_byte_offset += g_utf8_next_char (start) - start;
2409 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2410 real->segment_byte_offset = new_byte_offset;
2413 real->line_char_offset -= count;
2415 adjust_char_index (real, 0 - count);
2417 check_invariants (iter);
2423 /* We need to go back into previous segments. For now,
2424 * just keep this really simple. FIXME
2425 * use backward_indexable_segment.
2427 if (TRUE || count > MAX_LINEAR_SCAN)
2429 gint current_char_index;
2430 gint new_char_index;
2432 current_char_index = gtk_text_iter_get_offset (iter);
2434 if (current_char_index == 0)
2435 return FALSE; /* can't move backward */
2437 new_char_index = current_char_index - count;
2438 if (new_char_index < 0)
2441 gtk_text_iter_set_offset (iter, new_char_index);
2443 check_invariants (iter);
2449 /* FIXME backward_indexable_segment here */
2458 /* These two can't be implemented efficiently (always have to use
2459 * a linear scan, since that's the only way to find all the non-text
2464 * gtk_text_iter_forward_text_chars:
2465 * @iter: a #GtkTextIter
2466 * @count: number of chars to move
2468 * Moves forward by @count text characters (pixbufs, widgets,
2469 * etc. do not count as characters for this). Equivalent to moving
2470 * through the results of gtk_text_iter_get_text (), rather than
2471 * gtk_text_iter_get_slice ().
2473 * Return value: whether @iter moved and is dereferenceable
2476 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2485 * gtk_text_iter_forward_text_chars:
2486 * @iter: a #GtkTextIter
2487 * @count: number of chars to move
2489 * Moves backward by @count text characters (pixbufs, widgets,
2490 * etc. do not count as characters for this). Equivalent to moving
2491 * through the results of gtk_text_iter_get_text (), rather than
2492 * gtk_text_iter_get_slice ().
2494 * Return value: whether @iter moved and is dereferenceable
2497 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2506 * gtk_text_iter_forward_line:
2507 * @iter: an iterator
2509 * Moves @iter to the start of the next line. Returns %TRUE if there
2510 * was a next line to move to, and %FALSE if @iter was simply moved to
2511 * the end of the buffer and is now not dereferenceable, or if @iter was
2512 * already at the end of the buffer.
2514 * Return value: whether @iter can be dereferenced
2517 gtk_text_iter_forward_line (GtkTextIter *iter)
2519 GtkTextRealIter *real;
2521 g_return_val_if_fail (iter != NULL, FALSE);
2523 real = gtk_text_iter_make_real (iter);
2528 check_invariants (iter);
2530 if (forward_line_leaving_caches_unmodified (real))
2532 invalidate_char_index (real);
2533 adjust_line_number (real, 1);
2535 check_invariants (iter);
2537 if (gtk_text_iter_is_end (iter))
2544 /* On the last line, move to end of it */
2546 if (!gtk_text_iter_is_end (iter))
2547 gtk_text_iter_forward_to_end (iter);
2549 check_invariants (iter);
2555 * gtk_text_iter_backward_line:
2556 * @iter: an iterator
2558 * Moves @iter to the start of the previous line. Returns %TRUE if
2559 * @iter could be moved; i.e. if @iter was at character offset 0, this
2560 * function returns %FALSE. Therefore if @iter was already on line 0,
2561 * but not at the start of the line, @iter is snapped to the start of
2562 * the line and the function returns %TRUE. (Note that this implies that
2563 * in a loop calling this function, the line number may not change on
2564 * every iteration, if your first iteration is on line 0.)
2566 * Return value: whether @iter moved
2569 gtk_text_iter_backward_line (GtkTextIter *iter)
2571 GtkTextLine *new_line;
2572 GtkTextRealIter *real;
2573 gboolean offset_will_change;
2576 g_return_val_if_fail (iter != NULL, FALSE);
2578 real = gtk_text_iter_make_real (iter);
2583 check_invariants (iter);
2585 new_line = _gtk_text_line_previous (real->line);
2587 offset_will_change = FALSE;
2588 if (real->line_char_offset > 0)
2589 offset_will_change = TRUE;
2591 if (new_line != NULL)
2593 real->line = new_line;
2595 adjust_line_number (real, -1);
2599 if (!offset_will_change)
2603 invalidate_char_index (real);
2605 real->line_byte_offset = 0;
2606 real->line_char_offset = 0;
2608 real->segment_byte_offset = 0;
2609 real->segment_char_offset = 0;
2611 /* Find first segment in line */
2612 real->any_segment = real->line->segments;
2613 real->segment = _gtk_text_line_byte_to_segment (real->line,
2616 g_assert (offset == 0);
2618 /* Note that if we are on the first line, we snap to the start of
2619 * the first line and return TRUE, so TRUE means the iterator
2620 * changed, not that the line changed; this is maybe a bit
2621 * weird. I'm not sure there's an obvious right thing to do though.
2624 check_invariants (iter);
2631 * gtk_text_iter_forward_lines:
2632 * @iter: a #GtkTextIter
2633 * @count: number of lines to move forward
2635 * Moves @count lines forward, if possible (if @count would move
2636 * past the start or end of the buffer, moves to the start or end of
2637 * the buffer). The return value indicates whether the iterator moved
2638 * onto a dereferenceable position; if the iterator didn't move, or
2639 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2640 * the function does nothing and returns %FALSE. If @count is negative,
2641 * moves backward by 0 - @count lines.
2643 * Return value: whether @iter moved and is dereferenceable
2646 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2648 FIX_OVERFLOWS (count);
2651 return gtk_text_iter_backward_lines (iter, 0 - count);
2652 else if (count == 0)
2654 else if (count == 1)
2656 check_invariants (iter);
2657 return gtk_text_iter_forward_line (iter);
2663 if (gtk_text_iter_is_end (iter))
2666 old_line = gtk_text_iter_get_line (iter);
2668 gtk_text_iter_set_line (iter, old_line + count);
2670 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2672 /* count went past the last line, so move to end of last line */
2673 if (!gtk_text_iter_is_end (iter))
2674 gtk_text_iter_forward_to_end (iter);
2677 return !gtk_text_iter_is_end (iter);
2682 * gtk_text_iter_backward_lines:
2683 * @iter: a #GtkTextIter
2684 * @count: number of lines to move backward
2686 * Moves @count lines backward, if possible (if @count would move
2687 * past the start or end of the buffer, moves to the start or end of
2688 * the buffer). The return value indicates whether the iterator moved
2689 * onto a dereferenceable position; if the iterator didn't move, or
2690 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2691 * the function does nothing and returns %FALSE. If @count is negative,
2692 * moves forward by 0 - @count lines.
2694 * Return value: whether @iter moved and is dereferenceable
2697 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2699 FIX_OVERFLOWS (count);
2702 return gtk_text_iter_forward_lines (iter, 0 - count);
2703 else if (count == 0)
2705 else if (count == 1)
2707 return gtk_text_iter_backward_line (iter);
2713 old_line = gtk_text_iter_get_line (iter);
2715 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2717 return (gtk_text_iter_get_line (iter) != old_line);
2721 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2726 gboolean already_moved_initially);
2728 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2736 find_word_end_func (const PangoLogAttr *attrs,
2741 gboolean already_moved_initially)
2743 if (!already_moved_initially)
2746 /* Find end of next word */
2747 while (offset < min_offset + len &&
2748 !attrs[offset].is_word_end)
2751 *found_offset = offset;
2753 return offset < min_offset + len;
2757 is_word_end_func (const PangoLogAttr *attrs,
2762 return attrs[offset].is_word_end;
2766 find_word_start_func (const PangoLogAttr *attrs,
2771 gboolean already_moved_initially)
2773 if (!already_moved_initially)
2776 /* Find start of prev word */
2777 while (offset >= min_offset &&
2778 !attrs[offset].is_word_start)
2781 *found_offset = offset;
2783 return offset >= min_offset;
2787 is_word_start_func (const PangoLogAttr *attrs,
2792 return attrs[offset].is_word_start;
2796 inside_word_func (const PangoLogAttr *attrs,
2801 /* Find next word start or end */
2802 while (offset >= min_offset &&
2803 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2806 return attrs[offset].is_word_start;
2809 /* Sentence funcs */
2812 find_sentence_end_func (const PangoLogAttr *attrs,
2817 gboolean already_moved_initially)
2819 if (!already_moved_initially)
2822 /* Find end of next sentence */
2823 while (offset < min_offset + len &&
2824 !attrs[offset].is_sentence_end)
2827 *found_offset = offset;
2829 return offset < min_offset + len;
2833 is_sentence_end_func (const PangoLogAttr *attrs,
2838 return attrs[offset].is_sentence_end;
2842 find_sentence_start_func (const PangoLogAttr *attrs,
2847 gboolean already_moved_initially)
2849 if (!already_moved_initially)
2852 /* Find start of prev sentence */
2853 while (offset >= min_offset &&
2854 !attrs[offset].is_sentence_start)
2857 *found_offset = offset;
2859 return offset >= min_offset;
2863 is_sentence_start_func (const PangoLogAttr *attrs,
2868 return attrs[offset].is_sentence_start;
2872 inside_sentence_func (const PangoLogAttr *attrs,
2877 /* Find next sentence start or end */
2878 while (offset >= min_offset &&
2879 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2882 return attrs[offset].is_sentence_start;
2886 test_log_attrs (const GtkTextIter *iter,
2887 TestLogAttrFunc func)
2890 const PangoLogAttr *attrs;
2892 gboolean result = FALSE;
2894 g_return_val_if_fail (iter != NULL, FALSE);
2896 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2899 offset = gtk_text_iter_get_line_offset (iter);
2901 /* char_len may be 0 and attrs will be NULL if so, if
2902 * iter is the end iter and the last line is empty.
2904 * offset may be equal to char_len, since attrs contains an entry
2905 * for one past the end
2908 if (attrs && offset <= char_len)
2909 result = (* func) (attrs, offset, 0, char_len);
2915 find_line_log_attrs (const GtkTextIter *iter,
2916 FindLogAttrFunc func,
2918 gboolean already_moved_initially)
2921 const PangoLogAttr *attrs;
2923 gboolean result = FALSE;
2925 g_return_val_if_fail (iter != NULL, FALSE);
2927 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2930 offset = gtk_text_iter_get_line_offset (iter);
2932 /* char_len may be 0 and attrs will be NULL if so, if
2933 * iter is the end iter and the last line is empty
2937 result = (* func) (attrs, offset, 0, char_len, found_offset,
2938 already_moved_initially);
2943 /* FIXME this function is very, very gratuitously slow */
2945 find_by_log_attrs (GtkTextIter *iter,
2946 FindLogAttrFunc func,
2948 gboolean already_moved_initially)
2952 gboolean found = FALSE;
2954 g_return_val_if_fail (iter != NULL, FALSE);
2958 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2964 if (gtk_text_iter_forward_line (iter))
2965 return find_by_log_attrs (iter, func, forward,
2972 /* go to end of previous line. need to check that
2973 * line is > 0 because backward_line snaps to start of
2974 * line 0 if it's on line 0
2976 if (gtk_text_iter_get_line (iter) > 0 &&
2977 gtk_text_iter_backward_line (iter))
2979 if (!gtk_text_iter_ends_line (iter))
2980 gtk_text_iter_forward_to_line_end (iter);
2982 return find_by_log_attrs (iter, func, forward,
2991 gtk_text_iter_set_line_offset (iter, offset);
2994 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2995 !gtk_text_iter_is_end (iter);
3000 find_visible_by_log_attrs (GtkTextIter *iter,
3001 FindLogAttrFunc func,
3003 gboolean already_moved_initially)
3007 g_return_val_if_fail (iter != NULL, FALSE);
3011 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3013 if (!_gtk_text_btree_char_is_invisible (&pos))
3023 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3024 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3027 move_multiple_steps (GtkTextIter *iter,
3029 OneStepFunc step_forward,
3030 MultipleStepFunc n_steps_backward)
3032 g_return_val_if_fail (iter != NULL, FALSE);
3034 FIX_OVERFLOWS (count);
3040 return n_steps_backward (iter, -count);
3042 if (!step_forward (iter))
3048 if (!step_forward (iter))
3053 return !gtk_text_iter_is_end (iter);
3058 * gtk_text_iter_forward_word_end:
3059 * @iter: a #GtkTextIter
3061 * Moves forward to the next word end. (If @iter is currently on a
3062 * word end, moves forward to the next one after that.) Word breaks
3063 * are determined by Pango and should be correct for nearly any
3064 * language (if not, the correct fix would be to the Pango word break
3067 * Return value: %TRUE if @iter moved and is not the end iterator
3070 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3072 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3076 * gtk_text_iter_backward_word_start:
3077 * @iter: a #GtkTextIter
3079 * Moves backward to the previous word start. (If @iter is currently on a
3080 * word start, moves backward to the next one after that.) Word breaks
3081 * are determined by Pango and should be correct for nearly any
3082 * language (if not, the correct fix would be to the Pango word break
3085 * Return value: %TRUE if @iter moved and is not the end iterator
3088 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3090 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3093 /* FIXME a loop around a truly slow function means
3094 * a truly spectacularly slow function.
3098 * gtk_text_iter_forward_word_ends:
3099 * @iter: a #GtkTextIter
3100 * @count: number of times to move
3102 * Calls gtk_text_iter_forward_word_end() up to @count times.
3104 * Return value: %TRUE if @iter moved and is not the end iterator
3107 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3110 return move_multiple_steps (iter, count,
3111 gtk_text_iter_forward_word_end,
3112 gtk_text_iter_backward_word_starts);
3116 * gtk_text_iter_backward_word_starts
3117 * @iter: a #GtkTextIter
3118 * @count: number of times to move
3120 * Calls gtk_text_iter_backward_word_start() up to @count times.
3122 * Return value: %TRUE if @iter moved and is not the end iterator
3125 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3128 return move_multiple_steps (iter, count,
3129 gtk_text_iter_backward_word_start,
3130 gtk_text_iter_forward_word_ends);
3134 * gtk_text_iter_forward_visible_word_end:
3135 * @iter: a #GtkTextIter
3137 * Moves forward to the next visible word end. (If @iter is currently on a
3138 * word end, moves forward to the next one after that.) Word breaks
3139 * are determined by Pango and should be correct for nearly any
3140 * language (if not, the correct fix would be to the Pango word break
3143 * Return value: %TRUE if @iter moved and is not the end iterator
3148 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3150 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3154 * gtk_text_iter_backward_visible_word_start:
3155 * @iter: a #GtkTextIter
3157 * Moves backward to the previous visible word start. (If @iter is currently
3158 * on a word start, moves backward to the next one after that.) Word breaks
3159 * are determined by Pango and should be correct for nearly any
3160 * language (if not, the correct fix would be to the Pango word break
3163 * Return value: %TRUE if @iter moved and is not the end iterator
3168 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3170 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3174 * gtk_text_iter_forward_visible_word_ends:
3175 * @iter: a #GtkTextIter
3176 * @count: number of times to move
3178 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3180 * Return value: %TRUE if @iter moved and is not the end iterator
3185 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3188 return move_multiple_steps (iter, count,
3189 gtk_text_iter_forward_visible_word_end,
3190 gtk_text_iter_backward_visible_word_starts);
3194 * gtk_text_iter_backward_visible_word_starts
3195 * @iter: a #GtkTextIter
3196 * @count: number of times to move
3198 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3200 * Return value: %TRUE if @iter moved and is not the end iterator
3205 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3208 return move_multiple_steps (iter, count,
3209 gtk_text_iter_backward_visible_word_start,
3210 gtk_text_iter_forward_visible_word_ends);
3214 * gtk_text_iter_starts_word:
3215 * @iter: a #GtkTextIter
3217 * Determines whether @iter begins a natural-language word. Word
3218 * breaks are determined by Pango and should be correct for nearly any
3219 * language (if not, the correct fix would be to the Pango word break
3222 * Return value: %TRUE if @iter is at the start of a word
3225 gtk_text_iter_starts_word (const GtkTextIter *iter)
3227 return test_log_attrs (iter, is_word_start_func);
3231 * gtk_text_iter_ends_word:
3232 * @iter: a #GtkTextIter
3234 * Determines whether @iter ends a natural-language word. Word breaks
3235 * are determined by Pango and should be correct for nearly any
3236 * language (if not, the correct fix would be to the Pango word break
3239 * Return value: %TRUE if @iter is at the end of a word
3242 gtk_text_iter_ends_word (const GtkTextIter *iter)
3244 return test_log_attrs (iter, is_word_end_func);
3248 * gtk_text_iter_inside_word:
3249 * @iter: a #GtkTextIter
3251 * Determines whether @iter is inside a natural-language word (as
3252 * opposed to say inside some whitespace). Word breaks are determined
3253 * by Pango and should be correct for nearly any language (if not, the
3254 * correct fix would be to the Pango word break algorithms).
3256 * Return value: %TRUE if @iter is inside a word
3259 gtk_text_iter_inside_word (const GtkTextIter *iter)
3261 return test_log_attrs (iter, inside_word_func);
3265 * gtk_text_iter_starts_sentence:
3266 * @iter: a #GtkTextIter
3268 * Determines whether @iter begins a sentence. Sentence boundaries are
3269 * determined by Pango and should be correct for nearly any language
3270 * (if not, the correct fix would be to the Pango text boundary
3273 * Return value: %TRUE if @iter is at the start of a sentence.
3276 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3278 return test_log_attrs (iter, is_sentence_start_func);
3282 * gtk_text_iter_ends_sentence:
3283 * @iter: a #GtkTextIter
3285 * Determines whether @iter ends a sentence. Sentence boundaries are
3286 * determined by Pango and should be correct for nearly any language
3287 * (if not, the correct fix would be to the Pango text boundary
3290 * Return value: %TRUE if @iter is at the end of a sentence.
3293 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3295 return test_log_attrs (iter, is_sentence_end_func);
3299 * gtk_text_iter_inside_sentence:
3300 * @iter: a #GtkTextIter
3302 * Determines whether @iter is inside a sentence (as opposed to in
3303 * between two sentences, e.g. after a period and before the first
3304 * letter of the next sentence). Sentence boundaries are determined
3305 * by Pango and should be correct for nearly any language (if not, the
3306 * correct fix would be to the Pango text boundary algorithms).
3308 * Return value: %TRUE if @iter is inside a sentence.
3311 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3313 return test_log_attrs (iter, inside_sentence_func);
3317 * gtk_text_iter_forward_sentence_end:
3318 * @iter: a #GtkTextIter
3320 * Moves forward to the next sentence end. (If @iter is at the end of
3321 * a sentence, moves to the next end of sentence.) Sentence
3322 * boundaries are determined by Pango and should be correct for nearly
3323 * any language (if not, the correct fix would be to the Pango text
3324 * boundary algorithms).
3326 * Return value: %TRUE if @iter moved and is not the end iterator
3329 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3331 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3335 * gtk_text_iter_backward_sentence_start:
3336 * @iter: a #GtkTextIter
3338 * Moves backward to the previous sentence start; if @iter is already at
3339 * the start of a sentence, moves backward to the next one. Sentence
3340 * boundaries are determined by Pango and should be correct for nearly
3341 * any language (if not, the correct fix would be to the Pango text
3342 * boundary algorithms).
3344 * Return value: %TRUE if @iter moved and is not the end iterator
3347 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3349 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3352 /* FIXME a loop around a truly slow function means
3353 * a truly spectacularly slow function.
3356 * gtk_text_iter_forward_sentence_ends:
3357 * @iter: a #GtkTextIter
3358 * @count: number of sentences to move
3360 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3361 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3362 * negative, moves backward instead of forward.
3364 * Return value: %TRUE if @iter moved and is not the end iterator
3367 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3370 return move_multiple_steps (iter, count,
3371 gtk_text_iter_forward_sentence_end,
3372 gtk_text_iter_backward_sentence_starts);
3376 * gtk_text_iter_backward_sentence_starts:
3377 * @iter: a #GtkTextIter
3378 * @count: number of sentences to move
3380 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3381 * or until it returns %FALSE. If @count is negative, moves forward
3382 * instead of backward.
3384 * Return value: %TRUE if @iter moved and is not the end iterator
3387 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3390 return move_multiple_steps (iter, count,
3391 gtk_text_iter_backward_sentence_start,
3392 gtk_text_iter_forward_sentence_ends);
3396 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3401 gboolean already_moved_initially)
3403 if (!already_moved_initially)
3406 while (offset < (min_offset + len) &&
3407 !attrs[offset].is_cursor_position)
3410 *found_offset = offset;
3412 return offset < (min_offset + len);
3416 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3421 gboolean already_moved_initially)
3423 if (!already_moved_initially)
3426 while (offset > min_offset &&
3427 !attrs[offset].is_cursor_position)
3430 *found_offset = offset;
3432 return offset >= min_offset;
3436 is_cursor_pos_func (const PangoLogAttr *attrs,
3441 return attrs[offset].is_cursor_position;
3445 * gtk_text_iter_forward_cursor_position:
3446 * @iter: a #GtkTextIter
3448 * Moves @iter forward by a single cursor position. Cursor positions
3449 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3450 * surprisingly, there may not be a cursor position between all
3451 * characters. The most common example for European languages would be
3452 * a carriage return/newline sequence. For some Unicode characters,
3453 * the equivalent of say the letter "a" with an accent mark will be
3454 * represented as two characters, first the letter then a "combining
3455 * mark" that causes the accent to be rendered; so the cursor can't go
3456 * between those two characters. See also the #PangoLogAttr structure and
3457 * pango_break() function.
3459 * Return value: %TRUE if we moved and the new position is dereferenceable
3462 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3464 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3468 * gtk_text_iter_backward_cursor_position:
3469 * @iter: a #GtkTextIter
3471 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3473 * Return value: %TRUE if we moved
3476 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3478 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3482 * gtk_text_iter_forward_cursor_positions:
3483 * @iter: a #GtkTextIter
3484 * @count: number of positions to move
3486 * Moves up to @count cursor positions. See
3487 * gtk_text_iter_forward_cursor_position() for details.
3489 * Return value: %TRUE if we moved and the new position is dereferenceable
3492 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3495 return move_multiple_steps (iter, count,
3496 gtk_text_iter_forward_cursor_position,
3497 gtk_text_iter_backward_cursor_positions);
3501 * gtk_text_iter_backward_cursor_positions:
3502 * @iter: a #GtkTextIter
3503 * @count: number of positions to move
3505 * Moves up to @count cursor positions. See
3506 * gtk_text_iter_forward_cursor_position() for details.
3508 * Return value: %TRUE if we moved and the new position is dereferenceable
3511 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3514 return move_multiple_steps (iter, count,
3515 gtk_text_iter_backward_cursor_position,
3516 gtk_text_iter_forward_cursor_positions);
3520 * gtk_text_iter_forward_visible_cursor_position:
3521 * @iter: a #GtkTextIter
3523 * Moves @iter forward to the next visible cursor position. See
3524 * gtk_text_iter_forward_cursor_position() for details.
3526 * Return value: %TRUE if we moved and the new position is dereferenceable
3531 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3533 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3537 * gtk_text_iter_backward_visible_cursor_position:
3538 * @iter: a #GtkTextIter
3540 * Moves @iter forward to the previous visible cursor position. See
3541 * gtk_text_iter_backward_cursor_position() for details.
3543 * Return value: %TRUE if we moved and the new position is dereferenceable
3548 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3550 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3554 * gtk_text_iter_forward_visible_cursor_positions:
3555 * @iter: a #GtkTextIter
3556 * @count: number of positions to move
3558 * Moves up to @count visible cursor positions. See
3559 * gtk_text_iter_forward_cursor_position() for details.
3561 * Return value: %TRUE if we moved and the new position is dereferenceable
3566 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3569 return move_multiple_steps (iter, count,
3570 gtk_text_iter_forward_visible_cursor_position,
3571 gtk_text_iter_backward_visible_cursor_positions);
3575 * gtk_text_iter_backward_visible_cursor_positions:
3576 * @iter: a #GtkTextIter
3577 * @count: number of positions to move
3579 * Moves up to @count visible cursor positions. See
3580 * gtk_text_iter_forward_cursor_position() for details.
3582 * Return value: %TRUE if we moved and the new position is dereferenceable
3587 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3590 return move_multiple_steps (iter, count,
3591 gtk_text_iter_backward_visible_cursor_position,
3592 gtk_text_iter_forward_visible_cursor_positions);
3596 * gtk_text_iter_is_cursor_position:
3597 * @iter: a #GtkTextIter
3599 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3600 * pango_break() for details on what a cursor position is.
3602 * Return value: %TRUE if the cursor can be placed at @iter
3605 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3607 return test_log_attrs (iter, is_cursor_pos_func);
3611 * gtk_text_iter_set_line_offset:
3612 * @iter: a #GtkTextIter
3613 * @char_on_line: a character offset relative to the start of @iter's current line
3615 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3616 * (not byte) offset. The given character offset must be less than or
3617 * equal to the number of characters in the line; if equal, @iter
3618 * moves to the start of the next line. See
3619 * gtk_text_iter_set_line_index() if you have a byte index rather than
3620 * a character offset.
3624 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3627 GtkTextRealIter *real;
3630 g_return_if_fail (iter != NULL);
3632 real = gtk_text_iter_make_surreal (iter);
3637 check_invariants (iter);
3639 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3641 g_return_if_fail (char_on_line <= chars_in_line);
3643 if (char_on_line < chars_in_line)
3644 iter_set_from_char_offset (real, real->line, char_on_line);
3646 gtk_text_iter_forward_line (iter); /* set to start of next line */
3648 check_invariants (iter);
3652 * gtk_text_iter_set_line_index:
3653 * @iter: a #GtkTextIter
3654 * @byte_on_line: a byte index relative to the start of @iter's current line
3656 * Same as gtk_text_iter_set_line_offset(), but works with a
3657 * <emphasis>byte</emphasis> index. The given byte index must be at
3658 * the start of a character, it can't be in the middle of a UTF-8
3659 * encoded character.
3663 gtk_text_iter_set_line_index (GtkTextIter *iter,
3666 GtkTextRealIter *real;
3669 g_return_if_fail (iter != NULL);
3671 real = gtk_text_iter_make_surreal (iter);
3676 check_invariants (iter);
3678 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3680 g_return_if_fail (byte_on_line <= bytes_in_line);
3682 if (byte_on_line < bytes_in_line)
3683 iter_set_from_byte_offset (real, real->line, byte_on_line);
3685 gtk_text_iter_forward_line (iter);
3687 if (real->segment->type == >k_text_char_type &&
3688 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3689 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3690 "character; this will crash the text buffer. "
3691 "Byte indexes must refer to the start of a character.",
3692 G_STRLOC, byte_on_line);
3694 check_invariants (iter);
3699 * gtk_text_iter_set_visible_line_offset:
3700 * @iter: a #GtkTextIter
3701 * @char_on_line: a character offset
3703 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3704 * characters, i.e. text with a tag making it invisible is not
3705 * counted in the offset.
3708 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3711 gint chars_seen = 0;
3714 g_return_if_fail (iter != NULL);
3718 /* For now we use a ludicrously slow implementation */
3719 while (chars_seen < char_on_line)
3721 if (!_gtk_text_btree_char_is_invisible (&pos))
3724 if (!gtk_text_iter_forward_char (&pos))
3727 if (chars_seen == char_on_line)
3731 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3734 gtk_text_iter_forward_line (iter);
3738 bytes_in_char (GtkTextIter *iter)
3740 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3744 * gtk_text_iter_set_visible_line_index:
3745 * @iter: a #GtkTextIter
3746 * @byte_on_line: a byte index
3748 * Like gtk_text_iter_set_line_index(), but the index is in visible
3749 * bytes, i.e. text with a tag making it invisible is not counted
3753 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3756 gint bytes_seen = 0;
3760 g_return_if_fail (iter != NULL);
3764 /* For now we use a ludicrously slow implementation */
3765 while (bytes_seen < byte_on_line)
3767 if (!_gtk_text_btree_char_is_invisible (&pos))
3768 bytes_seen += bytes_in_char (&pos);
3771 if (!gtk_text_iter_forward_char (&pos))
3774 if (bytes_seen >= byte_on_line)
3778 if (bytes_seen > byte_on_line)
3779 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3780 "character; this will crash the text buffer. "
3781 "Byte indexes must refer to the start of a character.",
3782 G_STRLOC, byte_on_line);
3784 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3787 gtk_text_iter_forward_line (iter);
3791 * gtk_text_iter_set_line:
3792 * @iter: a #GtkTextIter
3793 * @line_number: line number (counted from 0)
3795 * Moves iterator @iter to the start of the line @line_number. If
3796 * @line_number is negative or larger than the number of lines in the
3797 * buffer, moves @iter to the start of the last line in the buffer.
3801 gtk_text_iter_set_line (GtkTextIter *iter,
3806 GtkTextRealIter *real;
3808 g_return_if_fail (iter != NULL);
3810 real = gtk_text_iter_make_surreal (iter);
3815 check_invariants (iter);
3817 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3819 iter_set_from_char_offset (real, line, 0);
3821 /* We might as well cache this, since we know it. */
3822 real->cached_line_number = real_line;
3824 check_invariants (iter);
3828 * gtk_text_iter_set_offset:
3829 * @iter: a #GtkTextIter
3830 * @char_offset: a character number
3832 * Sets @iter to point to @char_offset. @char_offset counts from the start
3833 * of the entire text buffer, starting with 0.
3836 gtk_text_iter_set_offset (GtkTextIter *iter,
3840 GtkTextRealIter *real;
3842 gint real_char_index;
3844 g_return_if_fail (iter != NULL);
3846 real = gtk_text_iter_make_surreal (iter);
3851 check_invariants (iter);
3853 if (real->cached_char_index >= 0 &&
3854 real->cached_char_index == char_offset)
3857 line = _gtk_text_btree_get_line_at_char (real->tree,
3862 iter_set_from_char_offset (real, line, real_char_index - line_start);
3864 /* Go ahead and cache this since we have it. */
3865 real->cached_char_index = real_char_index;
3867 check_invariants (iter);
3871 * gtk_text_iter_forward_to_end:
3872 * @iter: a #GtkTextIter
3874 * Moves @iter forward to the "end iterator," which points one past the last
3875 * valid character in the buffer. gtk_text_iter_get_char() called on the
3876 * end iterator returns 0, which is convenient for writing loops.
3879 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3881 GtkTextBuffer *buffer;
3882 GtkTextRealIter *real;
3884 g_return_if_fail (iter != NULL);
3886 real = gtk_text_iter_make_surreal (iter);
3891 buffer = _gtk_text_btree_get_buffer (real->tree);
3893 gtk_text_buffer_get_end_iter (buffer, iter);
3896 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3897 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3898 * If all else fails we could cache the para delimiter pos in the iter.
3899 * I think forward_to_line_end() actually gets called fairly often.
3902 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3907 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3908 _gtk_text_iter_get_btree (&end)))
3910 gtk_text_iter_forward_to_end (&end);
3914 /* if we aren't on the last line, go forward to start of next line, then scan
3915 * back for the delimiters on the previous line
3917 gtk_text_iter_forward_line (&end);
3918 gtk_text_iter_backward_char (&end);
3919 while (!gtk_text_iter_ends_line (&end))
3920 gtk_text_iter_backward_char (&end);
3923 return gtk_text_iter_get_line_offset (&end);
3927 * gtk_text_iter_forward_to_line_end:
3928 * @iter: a #GtkTextIter
3930 * Moves the iterator to point to the paragraph delimiter characters,
3931 * which will be either a newline, a carriage return, a carriage
3932 * return/newline in sequence, or the Unicode paragraph separator
3933 * character. If the iterator is already at the paragraph delimiter
3934 * characters, moves to the paragraph delimiter characters for the
3935 * next line. If @iter is on the last line in the buffer, which does
3936 * not end in paragraph delimiters, moves to the end iterator (end of
3937 * the last line), and returns %FALSE.
3939 * Return value: %TRUE if we moved and the new location is not the end iterator
3942 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3944 gint current_offset;
3948 g_return_val_if_fail (iter != NULL, FALSE);
3950 current_offset = gtk_text_iter_get_line_offset (iter);
3951 new_offset = find_paragraph_delimiter_for_line (iter);
3953 if (current_offset < new_offset)
3955 /* Move to end of this line. */
3956 gtk_text_iter_set_line_offset (iter, new_offset);
3957 return !gtk_text_iter_is_end (iter);
3961 /* Move to end of next line. */
3962 if (gtk_text_iter_forward_line (iter))
3964 /* We don't want to move past all
3967 if (!gtk_text_iter_ends_line (iter))
3968 gtk_text_iter_forward_to_line_end (iter);
3969 return !gtk_text_iter_is_end (iter);
3977 * gtk_text_iter_forward_to_tag_toggle:
3978 * @iter: a #GtkTextIter
3979 * @tag: a #GtkTextTag, or %NULL
3981 * Moves forward to the next toggle (on or off) of the
3982 * #GtkTextTag @tag, or to the next toggle of any tag if
3983 * @tag is %NULL. If no matching tag toggles are found,
3984 * returns %FALSE, otherwise %TRUE. Does not return toggles
3985 * located at @iter, only toggles after @iter. Sets @iter to
3986 * the location of the toggle, or to the end of the buffer
3987 * if no toggle is found.
3989 * Return value: whether we found a tag toggle after @iter
3992 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3995 GtkTextLine *next_line;
3996 GtkTextLine *current_line;
3997 GtkTextRealIter *real;
3999 g_return_val_if_fail (iter != NULL, FALSE);
4001 real = gtk_text_iter_make_real (iter);
4006 check_invariants (iter);
4008 current_line = real->line;
4009 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4012 while (_gtk_text_iter_forward_indexable_segment (iter))
4014 /* If we went forward to a line that couldn't contain a toggle
4015 for the tag, then skip forward to a line that could contain
4016 it. This potentially skips huge hunks of the tree, so we
4017 aren't a purely linear search. */
4018 if (real->line != current_line)
4020 if (next_line == NULL)
4022 /* End of search. Set to end of buffer. */
4023 _gtk_text_btree_get_end_iter (real->tree, iter);
4027 if (real->line != next_line)
4028 iter_set_from_byte_offset (real, next_line, 0);
4030 current_line = real->line;
4031 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4036 if (gtk_text_iter_toggles_tag (iter, tag))
4038 /* If there's a toggle here, it isn't indexable so
4039 any_segment can't be the indexable segment. */
4040 g_assert (real->any_segment != real->segment);
4045 /* Check end iterator for tags */
4046 if (gtk_text_iter_toggles_tag (iter, tag))
4048 /* If there's a toggle here, it isn't indexable so
4049 any_segment can't be the indexable segment. */
4050 g_assert (real->any_segment != real->segment);
4054 /* Reached end of buffer */
4059 * gtk_text_iter_backward_to_tag_toggle:
4060 * @iter: a #GtkTextIter
4061 * @tag: a #GtkTextTag, or %NULL
4063 * Moves backward to the next toggle (on or off) of the
4064 * #GtkTextTag @tag, or to the next toggle of any tag if
4065 * @tag is %NULL. If no matching tag toggles are found,
4066 * returns %FALSE, otherwise %TRUE. Does not return toggles
4067 * located at @iter, only toggles before @iter. Sets @iter
4068 * to the location of the toggle, or the start of the buffer
4069 * if no toggle is found.
4071 * Return value: whether we found a tag toggle before @iter
4074 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4077 GtkTextLine *prev_line;
4078 GtkTextLine *current_line;
4079 GtkTextRealIter *real;
4081 g_return_val_if_fail (iter != NULL, FALSE);
4083 real = gtk_text_iter_make_real (iter);
4088 check_invariants (iter);
4090 current_line = real->line;
4091 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4095 /* If we're at segment start, go to the previous segment;
4096 * if mid-segment, snap to start of current segment.
4098 if (is_segment_start (real))
4100 if (!_gtk_text_iter_backward_indexable_segment (iter))
4105 ensure_char_offsets (real);
4107 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4113 /* If we went backward to a line that couldn't contain a toggle
4114 * for the tag, then skip backward further to a line that
4115 * could contain it. This potentially skips huge hunks of the
4116 * tree, so we aren't a purely linear search.
4118 if (real->line != current_line)
4120 if (prev_line == NULL)
4122 /* End of search. Set to start of buffer. */
4123 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4127 if (real->line != prev_line)
4129 /* Set to last segment in prev_line (could do this
4132 iter_set_from_byte_offset (real, prev_line, 0);
4134 while (!at_last_indexable_segment (real))
4135 _gtk_text_iter_forward_indexable_segment (iter);
4138 current_line = real->line;
4139 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4144 if (gtk_text_iter_toggles_tag (iter, tag))
4146 /* If there's a toggle here, it isn't indexable so
4147 * any_segment can't be the indexable segment.
4149 g_assert (real->any_segment != real->segment);
4153 while (_gtk_text_iter_backward_indexable_segment (iter));
4155 /* Reached front of buffer */
4160 matches_pred (GtkTextIter *iter,
4161 GtkTextCharPredicate pred,
4166 ch = gtk_text_iter_get_char (iter);
4168 return (*pred) (ch, user_data);
4172 * gtk_text_iter_forward_find_char:
4173 * @iter: a #GtkTextIter
4174 * @pred: a function to be called on each character
4175 * @user_data: user data for @pred
4176 * @limit: search limit, or %NULL for none
4178 * Advances @iter, calling @pred on each character. If
4179 * @pred returns %TRUE, returns %TRUE and stops scanning.
4180 * If @pred never returns %TRUE, @iter is set to @limit if
4181 * @limit is non-%NULL, otherwise to the end iterator.
4183 * Return value: whether a match was found
4186 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4187 GtkTextCharPredicate pred,
4189 const GtkTextIter *limit)
4191 g_return_val_if_fail (iter != NULL, FALSE);
4192 g_return_val_if_fail (pred != NULL, FALSE);
4195 gtk_text_iter_compare (iter, limit) >= 0)
4198 while ((limit == NULL ||
4199 !gtk_text_iter_equal (limit, iter)) &&
4200 gtk_text_iter_forward_char (iter))
4202 if (matches_pred (iter, pred, user_data))
4210 * gtk_text_iter_backward_find_char:
4211 * @iter: a #GtkTextIter
4212 * @pred: function to be called on each character
4213 * @user_data: user data for @pred
4214 * @limit: search limit, or %NULL for none
4216 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4218 * Return value: whether a match was found
4221 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4222 GtkTextCharPredicate pred,
4224 const GtkTextIter *limit)
4226 g_return_val_if_fail (iter != NULL, FALSE);
4227 g_return_val_if_fail (pred != NULL, FALSE);
4230 gtk_text_iter_compare (iter, limit) <= 0)
4233 while ((limit == NULL ||
4234 !gtk_text_iter_equal (limit, iter)) &&
4235 gtk_text_iter_backward_char (iter))
4237 if (matches_pred (iter, pred, user_data))
4245 forward_chars_with_skipping (GtkTextIter *iter,
4247 gboolean skip_invisible,
4248 gboolean skip_nontext)
4253 g_return_if_fail (count >= 0);
4259 gboolean ignored = FALSE;
4262 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4267 _gtk_text_btree_char_is_invisible (iter))
4270 gtk_text_iter_forward_char (iter);
4278 lines_match (const GtkTextIter *start,
4279 const gchar **lines,
4280 gboolean visible_only,
4282 GtkTextIter *match_start,
4283 GtkTextIter *match_end)
4290 if (*lines == NULL || **lines == '\0')
4293 *match_start = *start;
4296 *match_end = *start;
4301 gtk_text_iter_forward_line (&next);
4303 /* No more text in buffer, but *lines is nonempty */
4304 if (gtk_text_iter_equal (start, &next))
4312 line_text = gtk_text_iter_get_visible_slice (start, &next);
4314 line_text = gtk_text_iter_get_slice (start, &next);
4319 line_text = gtk_text_iter_get_visible_text (start, &next);
4321 line_text = gtk_text_iter_get_text (start, &next);
4324 if (match_start) /* if this is the first line we're matching */
4325 found = strstr (line_text, *lines);
4328 /* If it's not the first line, we have to match from the
4329 * start of the line.
4331 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4343 /* Get offset to start of search string */
4344 offset = g_utf8_strlen (line_text, found - line_text);
4348 /* If match start needs to be returned, set it to the
4349 * start of the search string.
4353 *match_start = next;
4355 forward_chars_with_skipping (match_start, offset,
4356 visible_only, !slice);
4359 /* Go to end of search string */
4360 offset += g_utf8_strlen (*lines, -1);
4362 forward_chars_with_skipping (&next, offset,
4363 visible_only, !slice);
4372 /* pass NULL for match_start, since we don't need to find the
4375 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4378 /* strsplit () that retains the delimiter as part of the string. */
4380 strbreakup (const char *string,
4381 const char *delimiter,
4384 GSList *string_list = NULL, *slist;
4385 gchar **str_array, *s;
4388 g_return_val_if_fail (string != NULL, NULL);
4389 g_return_val_if_fail (delimiter != NULL, NULL);
4392 max_tokens = G_MAXINT;
4394 s = strstr (string, delimiter);
4397 guint delimiter_len = strlen (delimiter);
4404 len = s - string + delimiter_len;
4405 new_string = g_new (gchar, len + 1);
4406 strncpy (new_string, string, len);
4407 new_string[len] = 0;
4408 string_list = g_slist_prepend (string_list, new_string);
4410 string = s + delimiter_len;
4411 s = strstr (string, delimiter);
4413 while (--max_tokens && s);
4418 string_list = g_slist_prepend (string_list, g_strdup (string));
4421 str_array = g_new (gchar*, n);
4425 str_array[i--] = NULL;
4426 for (slist = string_list; slist; slist = slist->next)
4427 str_array[i--] = slist->data;
4429 g_slist_free (string_list);
4435 * gtk_text_iter_forward_search:
4436 * @iter: start of search
4437 * @str: a search string
4438 * @flags: flags affecting how the search is done
4439 * @match_start: return location for start of match, or %NULL
4440 * @match_end: return location for end of match, or %NULL
4441 * @limit: bound for the search, or %NULL for the end of the buffer
4443 * Searches forward for @str. Any match is returned by setting
4444 * @match_start to the first character of the match and @match_end to the
4445 * first character after the match. The search will not continue past
4446 * @limit. Note that a search is a linear or O(n) operation, so you
4447 * may wish to use @limit to avoid locking up your UI on large
4450 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4451 * have invisible text interspersed in @str. i.e. @str will be a
4452 * possibly-noncontiguous subsequence of the matched range. similarly,
4453 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4454 * pixbufs or child widgets mixed inside the matched range. If these
4455 * flags are not given, the match must be exact; the special 0xFFFC
4456 * character in @str will match embedded pixbufs or child widgets.
4458 * Return value: whether a match was found
4461 gtk_text_iter_forward_search (const GtkTextIter *iter,
4463 GtkTextSearchFlags flags,
4464 GtkTextIter *match_start,
4465 GtkTextIter *match_end,
4466 const GtkTextIter *limit)
4468 gchar **lines = NULL;
4470 gboolean retval = FALSE;
4472 gboolean visible_only;
4475 g_return_val_if_fail (iter != NULL, FALSE);
4476 g_return_val_if_fail (str != NULL, FALSE);
4479 gtk_text_iter_compare (iter, limit) >= 0)
4484 /* If we can move one char, return the empty string there */
4487 if (gtk_text_iter_forward_char (&match))
4490 gtk_text_iter_equal (&match, limit))
4494 *match_start = match;
4503 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4504 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4506 /* locate all lines */
4508 lines = strbreakup (str, "\n", -1);
4514 /* This loop has an inefficient worst-case, where
4515 * gtk_text_iter_get_text () is called repeatedly on
4521 gtk_text_iter_compare (&search, limit) >= 0)
4524 if (lines_match (&search, (const gchar**)lines,
4525 visible_only, slice, &match, &end))
4527 if (limit == NULL ||
4529 gtk_text_iter_compare (&end, limit) < 0))
4534 *match_start = match;
4543 while (gtk_text_iter_forward_line (&search));
4545 g_strfreev ((gchar**)lines);
4551 vectors_equal_ignoring_trailing (gchar **vec1,
4554 /* Ignores trailing chars in vec2's last line */
4563 if (strcmp (*i1, *i2) != 0)
4565 if (*(i2 + 1) == NULL) /* if this is the last line */
4567 gint len1 = strlen (*i1);
4568 gint len2 = strlen (*i2);
4571 strncmp (*i1, *i2, len1) == 0)
4573 /* We matched ignoring the trailing stuff in vec2 */
4598 typedef struct _LinesWindow LinesWindow;
4604 GtkTextIter first_line_start;
4605 GtkTextIter first_line_end;
4607 gboolean visible_only;
4611 lines_window_init (LinesWindow *win,
4612 const GtkTextIter *start)
4615 GtkTextIter line_start;
4616 GtkTextIter line_end;
4618 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4621 if (gtk_text_iter_is_start (start) ||
4622 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4624 /* Already at the end, or not enough lines to match */
4625 win->lines = g_new0 (gchar*, 1);
4630 line_start = *start;
4633 /* Move to start iter to start of line */
4634 gtk_text_iter_set_line_offset (&line_start, 0);
4636 if (gtk_text_iter_equal (&line_start, &line_end))
4638 /* we were already at the start; so go back one line */
4639 gtk_text_iter_backward_line (&line_start);
4642 win->first_line_start = line_start;
4643 win->first_line_end = line_end;
4645 win->lines = g_new0 (gchar*, win->n_lines + 1);
4647 i = win->n_lines - 1;
4654 if (win->visible_only)
4655 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4657 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4661 if (win->visible_only)
4662 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4664 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4667 win->lines[i] = line_text;
4669 line_end = line_start;
4670 gtk_text_iter_backward_line (&line_start);
4677 lines_window_back (LinesWindow *win)
4679 GtkTextIter new_start;
4682 new_start = win->first_line_start;
4684 if (!gtk_text_iter_backward_line (&new_start))
4688 win->first_line_start = new_start;
4689 win->first_line_end = new_start;
4691 gtk_text_iter_forward_line (&win->first_line_end);
4696 if (win->visible_only)
4697 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4698 &win->first_line_end);
4700 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4701 &win->first_line_end);
4705 if (win->visible_only)
4706 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4707 &win->first_line_end);
4709 line_text = gtk_text_iter_get_text (&win->first_line_start,
4710 &win->first_line_end);
4713 /* Move lines to make room for first line. */
4714 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4716 *win->lines = line_text;
4718 /* Free old last line and NULL-terminate */
4719 g_free (win->lines[win->n_lines]);
4720 win->lines[win->n_lines] = NULL;
4726 lines_window_free (LinesWindow *win)
4728 g_strfreev (win->lines);
4732 * gtk_text_iter_backward_search:
4733 * @iter: a #GtkTextIter where the search begins
4734 * @str: search string
4735 * @flags: bitmask of flags affecting the search
4736 * @match_start: return location for start of match, or %NULL
4737 * @match_end: return location for end of match, or %NULL
4738 * @limit: location of last possible @match_start, or %NULL for start of buffer
4740 * Same as gtk_text_iter_forward_search(), but moves backward.
4742 * Return value: whether a match was found
4745 gtk_text_iter_backward_search (const GtkTextIter *iter,
4747 GtkTextSearchFlags flags,
4748 GtkTextIter *match_start,
4749 GtkTextIter *match_end,
4750 const GtkTextIter *limit)
4752 gchar **lines = NULL;
4756 gboolean retval = FALSE;
4757 gboolean visible_only;
4760 g_return_val_if_fail (iter != NULL, FALSE);
4761 g_return_val_if_fail (str != NULL, FALSE);
4764 gtk_text_iter_compare (limit, iter) > 0)
4769 /* If we can move one char, return the empty string there */
4770 GtkTextIter match = *iter;
4772 if (limit && gtk_text_iter_equal (limit, &match))
4775 if (gtk_text_iter_backward_char (&match))
4778 *match_start = match;
4787 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4788 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4790 /* locate all lines */
4792 lines = strbreakup (str, "\n", -1);
4802 win.n_lines = n_lines;
4804 win.visible_only = visible_only;
4806 lines_window_init (&win, iter);
4808 if (*win.lines == NULL)
4813 gchar *first_line_match;
4816 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4818 /* We're now before the search limit, abort. */
4822 /* If there are multiple lines, the first line will
4823 * end in '\n', so this will only match at the
4824 * end of the first line, which is correct.
4826 first_line_match = g_strrstr (*win.lines, *lines);
4828 if (first_line_match &&
4829 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4834 GtkTextIter start_tmp;
4836 /* Offset to start of search string */
4837 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4839 next = win.first_line_start;
4841 forward_chars_with_skipping (&start_tmp, offset,
4842 visible_only, !slice);
4845 gtk_text_iter_compare (limit, &start_tmp) > 0)
4846 goto out; /* match was bogus */
4849 *match_start = start_tmp;
4851 /* Go to end of search string */
4855 offset += g_utf8_strlen (*l, -1);
4859 forward_chars_with_skipping (&next, offset,
4860 visible_only, !slice);
4869 while (lines_window_back (&win));
4872 lines_window_free (&win);
4883 * gtk_text_iter_equal:
4884 * @lhs: a #GtkTextIter
4885 * @rhs: another #GtkTextIter
4887 * Tests whether two iterators are equal, using the fastest possible
4888 * mechanism. This function is very fast; you can expect it to perform
4889 * better than e.g. getting the character offset for each iterator and
4890 * comparing the offsets yourself. Also, it's a bit faster than
4891 * gtk_text_iter_compare().
4893 * Return value: %TRUE if the iterators point to the same place in the buffer
4896 gtk_text_iter_equal (const GtkTextIter *lhs,
4897 const GtkTextIter *rhs)
4899 GtkTextRealIter *real_lhs;
4900 GtkTextRealIter *real_rhs;
4902 real_lhs = (GtkTextRealIter*)lhs;
4903 real_rhs = (GtkTextRealIter*)rhs;
4905 check_invariants (lhs);
4906 check_invariants (rhs);
4908 if (real_lhs->line != real_rhs->line)
4910 else if (real_lhs->line_byte_offset >= 0 &&
4911 real_rhs->line_byte_offset >= 0)
4912 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4915 /* the ensure_char_offsets () calls do nothing if the char offsets
4916 are already up-to-date. */
4917 ensure_char_offsets (real_lhs);
4918 ensure_char_offsets (real_rhs);
4919 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4924 * gtk_text_iter_compare:
4925 * @lhs: a #GtkTextIter
4926 * @rhs: another #GtkTextIter
4928 * A qsort()-style function that returns negative if @lhs is less than
4929 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4930 * Ordering is in character offset order, i.e. the first character in the buffer
4931 * is less than the second character in the buffer.
4933 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4936 gtk_text_iter_compare (const GtkTextIter *lhs,
4937 const GtkTextIter *rhs)
4939 GtkTextRealIter *real_lhs;
4940 GtkTextRealIter *real_rhs;
4942 real_lhs = gtk_text_iter_make_surreal (lhs);
4943 real_rhs = gtk_text_iter_make_surreal (rhs);
4945 if (real_lhs == NULL ||
4947 return -1; /* why not */
4949 check_invariants (lhs);
4950 check_invariants (rhs);
4952 if (real_lhs->line == real_rhs->line)
4954 gint left_index, right_index;
4956 if (real_lhs->line_byte_offset >= 0 &&
4957 real_rhs->line_byte_offset >= 0)
4959 left_index = real_lhs->line_byte_offset;
4960 right_index = real_rhs->line_byte_offset;
4964 /* the ensure_char_offsets () calls do nothing if
4965 the offsets are already up-to-date. */
4966 ensure_char_offsets (real_lhs);
4967 ensure_char_offsets (real_rhs);
4968 left_index = real_lhs->line_char_offset;
4969 right_index = real_rhs->line_char_offset;
4972 if (left_index < right_index)
4974 else if (left_index > right_index)
4983 line1 = gtk_text_iter_get_line (lhs);
4984 line2 = gtk_text_iter_get_line (rhs);
4987 else if (line1 > line2)
4995 * gtk_text_iter_in_range:
4996 * @iter: a #GtkTextIter
4997 * @start: start of range
4998 * @end: end of range
5000 * Checks whether @iter falls in the range [@start, @end).
5001 * @start and @end must be in ascending order.
5003 * Return value: %TRUE if @iter is in the range
5006 gtk_text_iter_in_range (const GtkTextIter *iter,
5007 const GtkTextIter *start,
5008 const GtkTextIter *end)
5010 g_return_val_if_fail (iter != NULL, FALSE);
5011 g_return_val_if_fail (start != NULL, FALSE);
5012 g_return_val_if_fail (end != NULL, FALSE);
5013 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5015 return gtk_text_iter_compare (iter, start) >= 0 &&
5016 gtk_text_iter_compare (iter, end) < 0;
5020 * gtk_text_iter_order:
5021 * @first: a #GtkTextIter
5022 * @second: another #GtkTextIter
5024 * Swaps the value of @first and @second if @second comes before
5025 * @first in the buffer. That is, ensures that @first and @second are
5026 * in sequence. Most text buffer functions that take a range call this
5027 * automatically on your behalf, so there's no real reason to call it yourself
5028 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5029 * that expect a pre-sorted range.
5033 gtk_text_iter_order (GtkTextIter *first,
5034 GtkTextIter *second)
5036 g_return_if_fail (first != NULL);
5037 g_return_if_fail (second != NULL);
5039 if (gtk_text_iter_compare (first, second) > 0)
5050 * Init iterators from the BTree
5054 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5058 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5059 gint real_char_index;
5063 g_return_if_fail (iter != NULL);
5064 g_return_if_fail (tree != NULL);
5066 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5067 &line_start, &real_char_index);
5069 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5071 real->cached_char_index = real_char_index;
5073 check_invariants (iter);
5077 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5082 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5086 g_return_if_fail (iter != NULL);
5087 g_return_if_fail (tree != NULL);
5089 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5091 iter_init_from_char_offset (iter, tree, line, char_on_line);
5093 /* We might as well cache this, since we know it. */
5094 real->cached_line_number = real_line;
5096 check_invariants (iter);
5100 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5105 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5109 g_return_if_fail (iter != NULL);
5110 g_return_if_fail (tree != NULL);
5112 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5114 iter_init_from_byte_offset (iter, tree, line, byte_index);
5116 /* We might as well cache this, since we know it. */
5117 real->cached_line_number = real_line;
5119 check_invariants (iter);
5123 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5128 g_return_if_fail (iter != NULL);
5129 g_return_if_fail (tree != NULL);
5130 g_return_if_fail (line != NULL);
5132 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5134 check_invariants (iter);
5138 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5144 g_return_val_if_fail (iter != NULL, FALSE);
5145 g_return_val_if_fail (tree != NULL, FALSE);
5147 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5151 /* Set iter to last in tree */
5152 _gtk_text_btree_get_end_iter (tree, iter);
5153 check_invariants (iter);
5158 iter_init_from_byte_offset (iter, tree, line, 0);
5160 if (!gtk_text_iter_toggles_tag (iter, tag))
5161 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5163 check_invariants (iter);
5169 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5173 g_return_val_if_fail (iter != NULL, FALSE);
5174 g_return_val_if_fail (tree != NULL, FALSE);
5176 _gtk_text_btree_get_end_iter (tree, iter);
5177 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5178 check_invariants (iter);
5184 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5186 const gchar *mark_name)
5190 g_return_val_if_fail (iter != NULL, FALSE);
5191 g_return_val_if_fail (tree != NULL, FALSE);
5193 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5199 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5200 check_invariants (iter);
5206 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5210 GtkTextLineSegment *seg;
5212 g_return_if_fail (iter != NULL);
5213 g_return_if_fail (tree != NULL);
5214 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5216 seg = mark->segment;
5218 iter_init_from_segment (iter, tree,
5219 seg->body.mark.line, seg);
5220 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5221 check_invariants (iter);
5225 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5227 GtkTextChildAnchor *anchor)
5229 GtkTextLineSegment *seg;
5231 g_return_if_fail (iter != NULL);
5232 g_return_if_fail (tree != NULL);
5233 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5235 seg = anchor->segment;
5237 g_assert (seg->body.child.line != NULL);
5239 iter_init_from_segment (iter, tree,
5240 seg->body.child.line, seg);
5241 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5242 check_invariants (iter);
5246 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5249 g_return_if_fail (iter != NULL);
5250 g_return_if_fail (tree != NULL);
5252 _gtk_text_btree_get_iter_at_char (tree,
5254 _gtk_text_btree_char_count (tree));
5255 check_invariants (iter);
5259 _gtk_text_iter_check (const GtkTextIter *iter)
5261 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5262 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5263 GtkTextLineSegment *byte_segment = NULL;
5264 GtkTextLineSegment *byte_any_segment = NULL;
5265 GtkTextLineSegment *char_segment = NULL;
5266 GtkTextLineSegment *char_any_segment = NULL;
5267 gboolean segments_updated;
5269 /* This function checks our class invariants for the Iter class. */
5271 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5273 if (real->chars_changed_stamp !=
5274 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5275 g_error ("iterator check failed: invalid iterator");
5277 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5278 g_error ("iterator check failed: both char and byte offsets are invalid");
5280 segments_updated = (real->segments_changed_stamp ==
5281 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5284 printf ("checking iter, segments %s updated, byte %d char %d\n",
5285 segments_updated ? "are" : "aren't",
5286 real->line_byte_offset,
5287 real->line_char_offset);
5290 if (segments_updated)
5292 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5293 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5295 if (real->segment->char_count == 0)
5296 g_error ("iterator check failed: segment is not indexable.");
5298 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5299 g_error ("segment char offset is not properly up-to-date");
5301 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5302 g_error ("segment byte offset is not properly up-to-date");
5304 if (real->segment_byte_offset >= 0 &&
5305 real->segment_byte_offset >= real->segment->byte_count)
5306 g_error ("segment byte offset is too large.");
5308 if (real->segment_char_offset >= 0 &&
5309 real->segment_char_offset >= real->segment->char_count)
5310 g_error ("segment char offset is too large.");
5313 if (real->line_byte_offset >= 0)
5315 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5316 &byte_segment, &byte_any_segment,
5317 &seg_byte_offset, &line_byte_offset);
5319 if (line_byte_offset != real->line_byte_offset)
5320 g_error ("wrong byte offset was stored in iterator");
5322 if (segments_updated)
5324 if (real->segment != byte_segment)
5325 g_error ("wrong segment was stored in iterator");
5327 if (real->any_segment != byte_any_segment)
5328 g_error ("wrong any_segment was stored in iterator");
5330 if (seg_byte_offset != real->segment_byte_offset)
5331 g_error ("wrong segment byte offset was stored in iterator");
5333 if (byte_segment->type == >k_text_char_type)
5336 p = byte_segment->body.chars + seg_byte_offset;
5338 if (!gtk_text_byte_begins_utf8_char (p))
5339 g_error ("broken iterator byte index pointed into the middle of a character");
5344 if (real->line_char_offset >= 0)
5346 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5347 &char_segment, &char_any_segment,
5348 &seg_char_offset, &line_char_offset);
5350 if (line_char_offset != real->line_char_offset)
5351 g_error ("wrong char offset was stored in iterator");
5353 if (segments_updated)
5355 if (real->segment != char_segment)
5356 g_error ("wrong segment was stored in iterator");
5358 if (real->any_segment != char_any_segment)
5359 g_error ("wrong any_segment was stored in iterator");
5361 if (seg_char_offset != real->segment_char_offset)
5362 g_error ("wrong segment char offset was stored in iterator");
5364 if (char_segment->type == >k_text_char_type)
5367 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5370 /* hmm, not likely to happen eh */
5371 if (!gtk_text_byte_begins_utf8_char (p))
5372 g_error ("broken iterator char offset pointed into the middle of a character");
5377 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5379 if (byte_segment != char_segment)
5380 g_error ("char and byte offsets did not point to the same segment");
5382 if (byte_any_segment != char_any_segment)
5383 g_error ("char and byte offsets did not point to the same any segment");
5385 /* Make sure the segment offsets are equivalent, if it's a char
5387 if (char_segment->type == >k_text_char_type)
5389 gint byte_offset = 0;
5390 gint char_offset = 0;
5391 while (char_offset < seg_char_offset)
5393 const char * start = char_segment->body.chars + byte_offset;
5394 byte_offset += g_utf8_next_char (start) - start;
5398 if (byte_offset != seg_byte_offset)
5399 g_error ("byte offset did not correspond to char offset");
5402 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5404 if (char_offset != seg_char_offset)
5405 g_error ("char offset did not correspond to byte offset");
5407 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5408 g_error ("byte index for iterator does not index the start of a character");
5412 if (real->cached_line_number >= 0)
5416 should_be = _gtk_text_line_get_number (real->line);
5417 if (real->cached_line_number != should_be)
5418 g_error ("wrong line number was cached");
5421 if (real->cached_char_index >= 0)
5423 if (real->line_char_offset >= 0) /* only way we can check it
5424 efficiently, not a real
5429 char_index = _gtk_text_line_char_index (real->line);
5430 char_index += real->line_char_offset;
5432 if (real->cached_char_index != char_index)
5433 g_error ("wrong char index was cached");
5437 if (_gtk_text_line_is_last (real->line, real->tree))
5438 g_error ("Iterator was on last line (past the end iterator)");